Documente Academic
Documente Profesional
Documente Cultură
ERNEST SCHEIBER
Bra sov
Prefat a
Scopul acestui curs este prezentarea tehnologiilor de programare Java care permit programarea aplicat iilor client - server: socluri Java; apelarea metodelor de la distant a (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 comunicat iilor si pe arhitectura programelor / aplicat iilor care le utilizeaz a. Trebuie semnalat faptul c a exemplele date nu incorporeaz a aspecte indispensabile unei aplicat ii informatice la standardele zilei: securitate, autenticare si autorizare; interfat a grac a pentru componenta client; utilizarea bazelor de date relat ionale / orientate obiect / NoSQL. Metodele si instrumentele de programare vor exemplicate pe problema foarte simpl a de calcul a celui mai mare divizor comun a dou a numere naturale. Codul acestei metode de calcul poate Varianta imperativ a ca metod a 3
1 2 3 4 5 6 7 8 9 10 11
public long cmmdc( long m, long n ) { long r , c ; do { c=n ; r= m %n ; m =n ; n=r ; } while ( r ! = 0 ) ; return c ; }
i n t e r f a c e CmmdcService { long cmmdc( long m, long n ) ; } s t a t i c CmmdcService cmmdcService=( long m, long n ) > { long r , c ; do { c=n ; r= m %n ; m =n ; n=r ; } while ( r ! = 0 ) ; return c ; };
public long cmmdc( long m, long n ) { i f (m ==n ) return m; else i f (m >n ) return cmmdc(m n , n ) ; else return cmmdc(m, n m) ; }
Guava: Google Core Libraries for Java posed a o metoda de calcul a celui mai mare divizor a dou a numere naturale com.google.common.math.LongMath. gcd(...). Pentru aplicat iile care utilizeaz a o baz a de date, sistemul de gestiune a bazei de date (SGBD) va una dintre sistemele Derby/Javadb sau mysql. Tiparul de nv a tare propus este 1. Se instaleaz a toate resursele necesare (Se exemplic a la laborator). 2. Se execut a aplicat ia / aplicat iile din curs (Se exemplic a la laborator).
5 3. Pentru ecare tehnologie, pe suportul oferit de curs, se programeaz ao alt a aplicat ie. Propunem urm atoarele teme: Conversia dintre grade Celsius si grade Fahrenheit (F = 1.8C + 32). Crearea, ntret inerea si utilizarea unei agende de adrese de e-mail. Agenda este o baz a de date. 4. In nal, se rezolv a tema pentru examen. Nu de put ine ori metodele / tehnologiile utilizate presupun utilizarea unui sablon de programare specic. Din acest punct de vedere, acest curs se dore ste a un suport metodic.
No. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
Versiunile produselor informatice utilizate n lucrare Produsul informatic Resursa/versiunea apache-ant apache.ant-1.8.1-bin.tar.gz apache-commons-leupload commons-leupload-1.3-bin.tar.gz apache-ftpserver ftpserver-1.0.6.tar.gz apache-maven apache-maven-3.1.0-bin.tar.gz apache-tomcat apache-tomcat-7.0.42.tar.gz apacheds apacheds-2.0.0-M15.tar.gz glasssh glasssh-4.0.zip google appengine appengine-java-sdk-1.8.0.zip db-derby db-derby-10.10.1.1-bin.tar.gz httpcomponents-client httpcomponents-client-4.3-bin.tar.gz httpcomponents-asyncclient httpcomponents-asyncclient-4.0-beta4-bin.tar.gz Java (jdk) jdk-7u40-windows-{i586;x64}.exe junit junit4.11.zip mysql mysql-5.6.10-win{32;x64}.zip mysql-connector mysql-connector-java-5.1.24.tar.gz OpenDS OpenDS-2.3.0-build003.zip openmq openmq5.0-binary-WINNT.zip
Cuprins
1 Introducere 15
21
23 23 24 25 30 33 38 43 44 58 61
2 Programare cu socluri Java 2.1 TCP vs. UDP . . . . . . . . . . . . . . . . . . 2.2 Soclu TCP . . . . . . . . . . . . . . . . . . . . 2.2.1 Aplicat ie client server cu socluri . . . 2.2.2 Streaming . . . . . . . . . . . . . . . . 2.3 Datagrame . . . . . . . . . . . . . . . . . . . . 2.3.1 Aplicat ii client server cu datagrame. 2.3.2 Multicast vs. Broadcast . . . . . . . . 2.4 Canale de comunicat ie . . . . . . . . . . . . . 2.5 Recept ie cu Selector . . . . . . . . . . . . . 2.6 Comunicat ii asincrone prin canale . . . . . . .
3 Reg asirea obiectelor prin servicii de nume 67 3.1 Java Naming and Directory Interface . . . . . . . . . . . . . . . 67 3.1.1 LDAP . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71 4 Invocarea procedurilor la distant a 4.1 Remote Method Invocation . . . . 4.1.1 Crearea unei aplicat ii RMI . 4.1.2 Tipare de programare . . . . 4.1.3 Obiect activabil la distant a 4.2 CORBA . . . . . . . . . . . . . . . 4.2.1 Conexiunea RMI - CORBA 4.2.2 Aplicat ie Java prin CORBA 9 77 77 81 87 93 97 98 103
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
10 5 Mesaje n Java 5.1 Java Message Service (JMS) . . . . . . . . . . . 5.2 Open Message Queue 5 . . . . . . . . . . . . . . 5.3 Elemente de programare - JMS-2 . . . . . . . . 5.3.1 Modul programat: Trimiterea unui mesaj 5.3.2 Recept ia sincron a a unui mesaj . . . . . 5.3.3 Recept ia asincron a a unui mesaj . . . . . 5.3.4 Publicarea mesajelor . . . . . . . . . . . 5.3.5 Abonare si recept ia mesajelor . . . . . . 5.3.6 Cazul abonatului partajat . . . . . . . . 5.3.7 Obiecte administrator prin JNDI . . . . 5.3.8 Comunicat ia prin coad a - queue . . . . . 5.3.9 Comunicat ia pe baz a de subiect - topic . 5.3.10 Aplicat ie JMS slab cuplat a. . . . . . . . 5.3.11 Programare JMS prin glasssh . . . . . .
CUPRINS
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
113 . 113 . 115 . 116 . 116 . 118 . 120 . 122 . 123 . 124 . 127 . 128 . 131 . 133 . 136
II
139
. . . . 141 141 147 148 150
6 HyperText Transfer Protocol 6.1 Transact ie http . . . . . . . . . . 6.2 Server Web - container de servlet 6.3 Serverul Web apache-tomcat . . . 6.4 Glasssh . . . . . . . . . . . . . .
7 Applet - Miniaplicat ie Java 153 7.1 Clasa Applet . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154 7.2 Desf a surarea unui applet . . . . . . . . . . . . . . . . . . . . . . 155 7.3 Comunicare Java - JavaScript ntr-un applet . . . . . . . . . . . 161 8 Conexiune simpl a prin clase din java.net 163 8.1 Clasa java.net.URL . . . . . . . . . . . . . . . . . . . . . . . . 163 9 Servlet 9.1 Marcajul <form> . . . . . . . . . . . . 9.2 Realizarea unui servlet . . . . . . . . . 9.2.1 Codul unui servlet . . . . . . . 9.3 Procesare asincron a n Java Servlet 3.0 9.4 Dezvolt ari n servlet-api 3.1 . . . . . . 9.4.1 Procesare asincron a neblocant a 165 166 167 170 177 180 180
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
CUPRINS
11 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182 188 188 194 196 198 200 201 204 206 207 211 212 219 220 223 224 227 227 232 234 234 236 239 240 245 246 246 250 252 254
9.4.2 Modicarea protocolului http: upgrade 9.5 Facilit a ti de programare cu servlet . . . . . . . 9.5.1 Program client al unui servlet . . . . . 9.5.2 Servlete nl ant uite . . . . . . . . . . . 9.5.3 Sesiune de lucru . . . . . . . . . . . . . 9.5.4 Cookie . . . . . . . . . . . . . . . . . . 9.5.5 Autenticare . . . . . . . . . . . . . . 9.5.6 Servlet cu conexiune la o baz a de date 9.5.7 Imagini furnizate de servlet . . . . . . 9.5.8 Servlet cu RMI . . . . . . . . . . . . . 9.5.9 Servlet cu JMS . . . . . . . . . . . . . 9.5.10 Servlet cu jurnalizare . . . . . . . . . . 9.6 FileUpload . . . . . . . . . . . . . . . . . . . . 9.7 Desc arcarea unui sier . . . . . . . . . . . . . 9.8 Filtru . . . . . . . . . . . . . . . . . . . . . . 9.9 Eveniment si auditor . . . . . . . . . . . . . . 9.10 Server apache-tomcat ncorporat . . . . . . . . 10 Java Server Page JSP 10.1 Tehnologia JSP . . . . . . . . . . . . . . . 10.1.1 Declarat ii JSP . . . . . . . . . . . . 10.1.2 Directive JSP . . . . . . . . . . . . 10.1.3 Marcaje JSP predenite . . . . . . 10.1.4 Pagini JSP cu componente Java . . 10.2 JSP Standard Tag Library JSTL . . . . . 10.2.1 Biblioteca de baz a . . . . . . . . . 10.2.2 Biblioteca de lucru cu baze de date 10.3 Marcaje JSP personale . . . . . . . . . . . 10.3.1 Marcaje f ar a atribute si f ar a corp. . 10.3.2 Marcaje cu atribute si f ar a corp. . . 10.3.3 Marcaje cu corp. . . . . . . . . . . 10.4 Servlet si JSP n Google App Engine . . . 11 Enterprise Java Beans 11.1 Session EJB . . . . . . . . . . . . . . . . . 11.1.1 Component a EJB sesiune stateless 11.1.2 Aplicat ie JEE cu module EJB, Web 11.1.3 Component a EJB sesiune singleton 11.1.4 Component a EJB sesiune stateful .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . si client RMI-IIOP . . . . . . . . . . . . . . . . . . . . . .
12
CUPRINS
11.1.5 Component a EJB MessageDriven . . . . . . . . . . . . . 271 11.1.6 Component a EJB Entity . . . . . . . . . . . . . . . . . . 274 12 Java Web Start 279 12.1 Java Web Start . . . . . . . . . . . . . . . . . . . . . . . . . . . 279 13 Java Management Extensions 13.1 Standard MBean . . . . . . . . . . . 13.1.1 Crearea unui Standard MBean 13.1.2 Crearea unui MBeanServer . . 13.1.3 Notic ari . . . . . . . . . . . 13.1.4 Agent MBean . . . . . . . . . 13.1.5 Invocarea la distant a . . . . . 285 . 286 . 286 . 288 . 292 . 295 . 296
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
III
ANEXE
311
313 . 313 . 316 . 318 333 337 341 343 . 343 . 344 . 345 349 . 349 . 350 . 352
A Unelte de dezvoltare A.1 XML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A.2 apache-ant . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A.3 apache-maven . . . . . . . . . . . . . . . . . . . . . . . . . . . B Testare cu junit C Jurnalizare D Component a Java E Adnot ari E.1 Denirea unei adnot ari . . . . . . . . . . . . . . . . . . . . . . E.2 Declararea unei adnot ari . . . . . . . . . . . . . . . . . . . . . E.3 Procesarea unei adnot ari . . . . . . . . . . . . . . . . . . . . . F Utilizarea SGBD n Java F.1 Derby / Javadb . . . . . . . . . . . . . . . . . . . . . . . . . . F.2 mysql . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . F.3 S ablonul de utilizare a unei baze de date . . . . . . . . . . . .
CUPRINS
13
IV
TEME DE LABORATOR
357
14
CUPRINS
Capitolul 1 Introducere
Ret elele locale, internetul, r asp andirea pe o arie geograc a a resurselor si a locat iilor n care se petrec act iuni ce tin de o activitate bine denit a sau sunt urm arite, gestionate din alte locuri au drept consecint a existent a aplicat iilor distribuite. Termenul distribuit se refer a tocmai la faptul c a componente ale aplicat iei se a a pe calculatoare diferite dar ntre care au loc schimburi de date. Dac a p art ile unei aplicat ii sau resursele utilizate se g asesc pe calculatoare distincte atunci aplicat ia se nume ste distribuit a. Intre p art ile sau resursele unei aplicat ii distribuite au loc schimburi de date, ceea ce se face utiliz and diferite mecanisme la realizarea c arora concur a sistemul de calcul, sistemul de operare si limbajul de programare. Astfel se vorbe ste de programare distribuit a ca mijloc de realizare a aplicat iilor distribuite. Pe l ang a algoritm, structuri de date, limbaj de programare, la realizarea unei aplicat ii distribuite intervin comunicat iile: schimbul de date dintre dou a componente aate pe calculatoare diferite. Punem n evident a dou a modele de aplicat ii distribuite: client-server: Programul server execut a cererile client ilor. O aplicat ie client server se compune din: componenta server - alc atuit a din programe / clase ce asigur a una sau mai multe funct iuni (servicii), care pot apelate de c atre client i. componenta client - alc atuit a din programe / clase care permit accesul la server si apelarea serviciilor acestuia. Serverul si clientul (client ii) ruleaz a, de obicei, pe calculatoare distincte. Un server trebuie s a satisfac a cererile mai multor client i. 15
16
CAPITOLUL 1. INTRODUCERE
Durata de viat a a unei aplicat ii client server este dat a de durata funct ion arii serverului. Aceast a durat a poate alc atuit a din intervale disjuncte de timp, ntre acele intervale, din diverse motive, serverul este inactiv. Intervalul de timp determinat de conectarea unui client la server si p an a la deconectare poart a numele de sesiune. In aceast a perioad a, clientul poate invoca mai multe servicii ale serverului. Un client poate init ia mai multe sesiuni. Un client trebuie s a- si reg aseasc a datele n cadrul unei sesiuni, ntre sesiuni, pe toat a durata de viat a a aplicat iei. Astfel se pune problema ret inerii / persistent ei datelor pentru ecare client n parte. Amintim urm atoarele tehnologii Java pentru realizarea aplicat iilor clientserver: Tehnologii destinate ret elelor locale, nebazate pe protocolul http. Socluri RMI (Remote Method Invocation) CORBA (Common Object Request Brocker Arhitecture) JMS (Java Message Service)
Comunicat iile utilizeaz a porturi care nu trebuie s a e nchise de eventuale aplicat ii de tip rewall. Tehnologii cu comunicat ii prin Internet, bazate pe protocolul http. Servlet si JSP (Java Server Pages) Java Web Start WebSocket dispecer-lucr ator: Programul dispecer distribuie sarcinile de executat lucr atorilor si le coordoneaz a activitatea. Exist a multe abord ari de programere a aplicat iilor dispecer-lucr ator. Exist a diferent e mari ntre o aplicat ie care ruleaz a pe un calculator si o aplicat ie distribuit a1 latent a (latency ) - exist a mai multe denit ii:
Waldo J., Wyant G., Wollrath A., Kendall S., 1994, A Note on Distributed Computing. Sun Microsystems Corporation, Technical report, SMLI TR-94-29.
1
17 diferent a n timp ntre o operat ie executat a pe un calculator la distant a de execut ia ei pe calculatorul local. diferent a n timp ntre momentul recept ion arii r aspunsului la o cerere si momentul lans arii ei. diferent a n timp ntre momentul recept ion arii unei cereri si momentul transmiterii r aspunsului. Recept ia rezultatului unei operat ii executate pe un calculator la distant a se poate programa sincron de obicei recept ia blocheaz a rul de execut ie al apelului p an a la sosirea rezultatului; asincron recept ia se obt ine ntr-un obiect dedicat care se execut a n afara rului de execut ie al apelului. O preocupare continu a este dezvoltarea de tehnologii hard si soft pentru mic sorarea latent ei. accesul la memorie (memory access ) Aplicat iile distribuite pot rula pe platforme diferite (de exemplu Java si .NET) iar componentele ei pot realizate n limbaje de programare diferite. Instrumente de programare cadre de lucru (framework ) care mijlocesc realizarea aplicat iilor asigur a accesul la resursele aate n memoria calculatoarelor. Exist a o preocupare pentru produse care asigur a interoperabilitatea dintre platformele de calcul. pr abu sirea part ial a (partial failure ) const a n ncetarea funct ion arii unei p art i a aplicat iei distribuite, dar care continu a s a e accesibil a. Tratarea acestei probleme pare a cea mai dicil a tem a a program arii distribuite. Teorema CAP (Eric Brewer, 2000) trateaz a leg atura dintre pr abu sirea part ial a, disponibilitatea aplicat iei si consistent a datelor. Preciz am sensul unor not iuni utilizate n lucrare: protocol - pachet de reguli, sablon utilizat n comunicat ii, n accesarea unor resurse. Exemple de protocoale utilizate sunt: http - HyperText Transfer Protocol este principalul protocol utilizat n comunicat iile prin Internet; https protocol http securizat;
18
CAPITOLUL 1. INTRODUCERE
le - protocol pentru specicarea sierelor aate pe calculatorul local; ftp - File Transfer Protocol - protocol pentru transferul sierelor ntre dou a calculatoare; smtp - Simple Message Transfer Protocol utilizat de po sta elecronic a. host - calculatorul gazd a, cel pe care se lucreaz a. Acest calculator se specic a printr-o adres a IP (Internet Protocol ) sau printr-un nume. port - o adres a de memorie cuprins a ntre 0 si 65535. Porturile cuprinse ntre 0 si 1023 sunt rezervate sistemului de operare. Dintre acestea amintim: Port Utilizat de 80 http 443 https 25 smtp Referint ele resurselor se indic a folosind Uniform Resource Identiers - (URI) si mai precis Uniform Resource Locator - (URL). URI identic a o resurs a n timp ce URL desemneaz a locat ia resursei. URL se consider a ca un caz particular de URI. Sintaxa folosit a pentru URI este protocol://host[:port][cale][?cerere] Un rol important n dezvoltarea tehnologiilor legate de limbajul Java revine organizat iilor de standardizare: Java Community Process JCP; Advancing open standards for the information society OASIS; The Internet Engineering Task Force IETF.
20
CAPITOLUL 1. INTRODUCERE
21
2.1
Calculatoarele ce ruleaz a n ret ea comunic a ntre ele folosind protocolul TCP (Transmission Control Protocol) sau UDP (User Datagram Protocol). Intr-un program Java se utilizeaz a clasele pachetului java.net prin intermediul c arora se acceseaz a nivelele deservite de protocoalele TCP sau UDP. In felul acesta se pot realiza comunicat ii independente de platforma de calcul. Pentru a alege clasa Java care s a e utilizat a trebuie cunoscut a diferent a dintre TCP si UDP. TCP C and dou a aplicat ii comunic a ntre ele se stabile ste o conexiune prin intermediul c areia se schimb a date. Folosind protocolul TCP, comunicat ia garanteaz a c a datele trimise dintr-un cap at ajung n cel alalt cap at cu p astrarea ordinii n care au fost trimise. Acest tip de comunicat ie seam an a cu o convorbire telefonic a. TCP furnizeaz a un canal sigur de comunicat ie ntre aplicat ii. UDP Utilizarea protocolului UDP presupune trimiterea unor pachete de date numite datagrame de la o aplicat ie la alta f ar a s a se asigure faptul c a datagramele ajung la destinat ie si nici ordinea lor de sosire. Acest tip de comunicat ie seam an a cu trimiterea scrisorilor prin po st a. 23
24
2.2
Soclu TCP
Pentru a comunica utiliz and TCP programul client si programul server stabilesc o conexiune sigur a. Fiecare program se leag a la conexiune printr-un soclu (socket). Un soclu este cap atul unei c ai de comunicat ie bidirect ional ntre dou a programe ce ruleaz a n ret ea. Un soclu este legat de un port prin care nivelul TCP poate identica aplicat ia c areia i sunt transmise datele. Pentru a comunica at at clientul c at si serverul citesc date de la si scriu date la soclul legat la conexiunea dintre ele. In pachetul java.net clasele Socket si ServerSocket implementeaz a un soclu din partea clientului si respectiv din partea serverului. Clientul cunoa ste numele calculatorului pe care ruleaz a serverul c at si portul la care acesta este conectat. Pentru stabilirea conexiunii, clientul ncearc a un rendez-vous cu serverul de pe ma sina serverului si la portul serverului. Dac a totul decurge bine, serverul accept a conexiunea. Dup a acceptare, serverul creaz a pentru client un nou soclu legat la un alt port n a sa fel nc at ascultarea cererilor la soclul init ial s a poat a continua n timp ce sunt satisf acute cererile clientului conectat. Din partea clientului, dup a acceptarea conexiunii soclul este creat si este utilizat pentru comunicat ia cu serverul.
Clasa java.net.Socket
Resursele clasei Socket sunt destinate clientului. Constructori public Socket(String host, int port ) throws UnknownHostException, IOException Creaz a un soclu conectat la calculatorul cu portul specicat. public Socket(InetAddress host, int port ) throws IOException Creaz a un soclu conectat la calculatorul cu portul specicat. Metode public InputStream getInputStream() throws IOException Returneaz a un ux de intrare ata sat soclului, pentru citirea (preluarea) informat iilor de la soclu.
25
public OutputStream getOutputStream() throws IOException Returneaz a un ux de ie sire ata sat soclului, pentru scrierea (transmiterea) informat iilor la soclu. public synchronized void close() throws IOException nchide soclul de referint a .
Clasa java.net.ServerSocket
Resursele clasei ServerSocket sunt destinate serverului. Constructori public ServerSocket(int port ) throws IOException Creaz a un soclu la portul specicat. Dac a port =0, atunci va utilizat orice port disponibil. Capacitatea sirului (tamponului) de a steptare pentru cererile de conectare se xeaz a la valoarea implicit a 50. Cererile n exces vor refuzate. public ServerSocket(int port, int lung ) throws IOException In plus xeaz a lungimea sirului (tamponului) de a steptare. Metode public Socket accept() throws IOException Metoda blocheaz a procesul (rul de execut ie) apelant p an a la sosirea unei cereri de conectare si creaz a un soclu client prin care se va desf a sura comunicarea cu solicitantul acceptat. public synchronized void close() throws IOException nchide soclul de referint a .
2.2.1
Serverul trebuie s a satisfac a simultan solicit arile mai multor client i. Fiecare client apeleaz a programul server la acela si port si n consecint a cererile de conectare sunt recept ionate de acela si ServerSocket. Serverul recept ioneaz a apelurile secvent ial. La un apel, se creaz a de partea severului un soclu prin care se va face schimbul de date cu clientul. Cererile client ilor pot satisface concurent/paralel, utiliz and re de execut ie ce implementeaz a serviciul oferit sau secvent ial - n cazul unor servicii de durat a scurt a.
26
Exemplul 2.2.1 Sistem client - server pentru calculul celui mai mare divizor comun a dou a numere naturale. Portul obiectului de tip ServerSocket este 7999. Programul client CmmdcClient se conecteaz a la server, transmite serverului cele dou a numere naturale si recept ioneaz a rezultatul pe care apoi l a seaz a. In esent a orice program client trebuie s a execute: 1. Deschide/creaz a un soclu. 2. Deschide/creaz a uxuri de date pentru comunicat ia cu serverul. 3. Transmite si recept ioneaz a date potrivit specicului aplicat iei (protocolului serverului). Acest pas variaz a de la un program client la altul. 4. Inchiderea uxurilor de date. 5. Inchiderea soclului.
1 2 3 4 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
public c l a s s CmmdcClient { public s t a t i c void main ( S t r i n g [ ] a r g s ) { S t r i n g h o s t= l o c a l h o s t ; i n t p o r t =7999; i f ( a r g s . l e n g t h > 0) h o s t=a r g s [ 0 ] ; i f ( a r g s . l e n g t h > 1) p o r t=I n t e g e r . p a r s e I n t ( a r g s [ 1 ] ) ; S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ; long m, n , r ; System . out . p r i n t l n ( m = ) ; m =s c a n n e r . nextLong ( ) ; System . out . p r i n t l n ( n= ) ; n=s c a n n e r . nextLong ( ) ; try ( S o c k e t cmmdcSocket = new S o c k e t ( hos t , p o r t ) ; DataInputStream i n=new DataInputStream ( cmmdcSocket . g e t I n p u t S t r e a m ( ) ) ; DataOutputStream out= new DataOutputStream ( cmmdcSocket . getOutputStream ( ) ) ) { out . w r i t e L o n g (m) ; out . w r i t e L o n g ( n ) ; r=i n . readLong ( ) ; System . out . p r i n t l n ( R e q u i r e d r e s u l t : +r ) ; } catch ( E x c e p t i o n e ) { System . e r r . p r i n t l n ( C l i e n t c o m u n i c a t i o n e r r o r : +e . g e t M e s s a g e ( ) ) ; } } }
27
Se presupune c a programul server ruleaz a pe calculatorul local si utilizeaz a portul 7999. Dac a ace sti parametri se modic a - de exemplu serverul ruleaz a n ret ea pe calculatorul atlantis la portul 8200 - atunci la apelare transmitem ace sti parametri prin java CmmdcClient atlantis 8200 Partea server este alc atuit a din mai multe clase: Clasa MyMServer, independent a de un serviciu anume, preia apelurile client ilor si lanseaz a satisfacerea cererii.
1 2 3 4 5 7 8 9 11 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
java . net . ServerSocket ; java . net . Socket ; j a v a . i o . IOException ; java . u t i l . concurrent . ExecutorService ; java . u t i l . concurrent . Executors ;
public c l a s s MyMServer { s t a t i c f i n a l i n t NTHREADS=100; s t a t i c E x e c u t o r S e r v i c e e x e c=E x e c u t o r s . newFixedThreadPool (NTHREADS) ; public s t a t i c void main ( S t r i n g [ ] a r g s ) throws IOException { i n t p o r t =7999; boolean l i s t e n i n g=true ; try ( S e r v e r S o c k e t s e r v e r S o c k e t=new S e r v e r S o c k e t ( p o r t ) ) { System . out . p r i n t l n ( The s e r v e r i s l i s t e n i n g on p o r t 7999 ) ; while ( l i s t e n i n g ) { AppThread o b j=new AppThread ( s e r v e r S o c k e t . a c c e p t ( ) ) ; exec . execute ( obj ) ; // v a r i a n t a // new AppThread ( s e r v e r S o c k e t . a c c e p t ( ) ) . s t a r t ( ) ; } } catch ( IOException e ) { System . e r r . p r i n t l n ( Could not l i s t e n on p o r t : +p o r t ) ; System . e r r . p r i n t l n ( e . g e t M e s s a g e ( ) ) ; System . e x i t ( 1 ) ; } } }
In ciclul while, la recept ia unei solicit ari de conexiune se creaz a si se lanseaz a un r de execut ie a c arei metod a run cont ine act iunile ce r aspund solicit arii. Clasa AppTread - r de execut ie responsabil de preluarea datelor si de transmitere a rezultatului.
1 2 3 4 6 7
28
9 10 11 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
public AppThread ( S o c k e t s o c k e t ) { t h i s . s o c k e t=s o c k e t ; } public void run ( ) { try ( DataOutputStream out = new DataOutputStream ( s o c k e t . getOutputStream ( ) ) ; DataInputStream i n = new DataInputStream ( s o c k e t . g e t I n p u t S t r e a m ( ) ) ) { long m=0 ,n=0 , r ; App app=new App ( ) ; m =i n . readLong ( ) ; n=i n . readLong ( ) ; r=app . cmmdc(m, n ) ; out . w r i t e L o n g ( r ) ; socket . close ( ) ; } catch ( IOException e ) { System . e r r . p r i n t l n ( S e r v e r c o m u n i c a t i o n e r r o r : +e . g e t M e s s a g e ( ) ) ; } } }
Clasa App corespunz atoare calcului celui mai mare divizor comul a dou a numere naturale.
1 2 3
Rularea programelor. Se porne ste la nceput programul server MyMServer iar apoi clientul CmmdcClient. Clientul se poate rula de pe orice calculator al ret elei. Dac a programul client se execut a pe alt calculator dec at cel pe care ruleaz a programul server, atunci la apelarea clientului trebuie precizat numele calculatorului server si eventual portul utilizat. O alt a arhitectur a a aplicat iei este dezvoltat a n continuare. Aceast a arhitectur a este mai bun a n sensul c a poate utilizat a n alte cadre de lucru / de dezvoltare (de exemplu OSGi, Junit ). Aplicat ia se va compune din: Aplicat ia server alc atuit a din: Interfat a
1 2 3 4 5 6
29
Implementarea interfet ei
1 2 3 4 5 6 7 8 10 12 13 14 15 16 17 18 19 20 21 22 23 24 26 27 28 29 30 31 32 33 34 35 36 37 38 39
package s e r v e r . impl ; import s e r v e r . AppThread ; import i s e r v e r . IMyMServer ; import j a v a . n e t . S e r v e r S o c k e t ; import j a v a . n e t . S o c k e t ; import j a v a . i o . IOException ; import j a v a . u t i l . c o n c u r r e n t . E x e c u t o r S e r v i c e ; import j a v a . u t i l . c o n c u r r e n t . E x e c u t o r s ; public c l a s s MyMServer implements IMyMServer { public S e r v e r S o c k e t g e t S e r v e r S o c k e t ( i n t p o r t ) { ServerSocket s e r v e r S o c k e t = null ; try { s e r v e r S o c k e t = new S e r v e r S o c k e t ( p o r t ) ; } catch ( IOException e ) { System . e r r . p r i n t l n ( Could not l i s t e n on p o r t : +p o r t ) ; System . e r r . p r i n t l n ( e . g e t M e s s a g e ( ) ) ; System . e x i t ( 1 ) ; } System . out . p r i n t l n ( S e r v e r S o c k e t i s r e a d y . . . ) ; return s e r v e r S o c k e t ; } public void myAction ( S e r v e r S o c k e t s e r v e r S o c k e t ) { i n t NTHREADS=100; E x e c u t o r S e r v i c e e x e c=E x e c u t o r s . newFixedThreadPool (NTHREADS) ; while ( true ) { try { AppThread o b j=new AppThread ( s e r v e r S o c k e t . a c c e p t ( ) ) ; exec . execute ( obj ) ; } catch ( IOException e ) { System . e r r . p r i n t l n ( MyActionException : +e . g e t M e s s a g e ( ) ) ; } } } }
Clasele AppThread, App sunt cele utilizate anterior. Clas a de lansare a serverului
1 2 3 4 6 7 8 9 10 11 12 13 14
package s e r v e r ; import j a v a . n e t . S e r v e r S o c k e t ; import s e r v e r . impl . MyMServer ; import i s e r v e r . IMyMServer ; public c l a s s AppServer { public s t a t i c void main ( S t r i n g [ ] a r g s ) { i n t p o r t =7999; i f ( a r g s . l e n g t h > 0) p o r t=I n t e g e r . p a r s e I n t ( a r g s [ 0 ] ) ; IMyMServer myMServer=new MyMServer ( ) ; S e r v e r S o c k e t s e r v e r S o c k e t=myMServer . g e t S e r v e r S o c k e t ( p o r t ) ; myMServer . myAction ( s e r v e r S o c k e t ) ; }
30
}
15
2.2.2
Streaming
Prin socluri se pot transmite uxuri de date (streaming ). Modul de programare depinde de natura datelor ce trebuie vehiculate (text, sunet, grac a). Exemplul 2.2.2 Clientul solicit a serverului transmisia unui sier text, cerere care va satisf acut a de server. Clientul cunoa ste lista sierelor pe care le poate trimite serverul. Structura aplicat iei este: Client StreamClient.java Server MyMServer.java AppThread.java Clasa StreamClient
1 2 3 4 5 6 7 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
j a v a . i o . DataInputStream ; j a v a . i o . DataOutputStream ; java . net . Socket ; j a v a . i o . IOException ; j a v a . i o . EOFException ; j a v a . i o . UTFDataFormatException ; java . u t i l . Scanner ;
public c l a s s S t r e a m C l i e n t { public s t a t i c void main ( S t r i n g [ ] a r g s ) { S t r i n g h o s t= l o c a l h o s t ; i n t p o r t =7999; System . out . p r i n t l n ( A l e g e t i f i s i e r u l : ) ; System . out . p r i n t l n ( 1 : c a p i t o l . t x t ) ; System . out . p r i n t l n ( 2 : j u n i t . t e x ) ; S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ; i n t n o F i l e=s c a n n e r . n e x t I n t ( ) ; try ( S o c k e t c l i e n t S o c k e t = new S o c k e t ( hos t , p o r t ) ; DataInputStream i n = new DataInputStream ( c l i e n t S o c k e t . g e t I n p u t S t r e a m ( ) ) ; DataOutputStream out = new DataOutputStream ( c l i e n t S o c k e t . getOutputStream ( ) ) ) { out . w r i t e I n t ( n o F i l e ) ; System . out . p r i n t l n ( R e c e i v e d : ) ; String s ; while ( ! ( s=i n . readUTF ( ) ) . e q u a l s ( e n d O F f i l e ) ) System . out . p r i n t l n ( s ) ; } catch ( IOException e ) { System . e r r . p r i n t l n ( C l i e n t c o m u n i c a t i o n e r r o r : +e . g e t M e s s a g e ( ) ) ; } } }
31
Clasa MyThread.java
1 2 3 4 5 6 7 9 10 12 13 14 16 17 18 19 20 21 22 23 24 25 26 27 28 29 31 32 33 34 35 36 37 38 39 40 41 42 43 44
java . net . Socket ; j a v a . i o . DataInputStream ; j a v a . i o . DataOutputStream ; java . io . F i l e ; java . io . FileReader ; java . i o . BufferedReader ; j a v a . i o . IOException ;
public c l a s s AppThread extends Thread { S o c k e t s o c k e t=n u l l ; public AppThread ( S o c k e t s o c k e t ) { t h i s . s o c k e t=s o c k e t ; } public void run ( ) { try ( DataInputStream i n = new DataInputStream ( s o c k e t . g e t I n p u t S t r e a m ( ) ) ; DataOutputStream out = new DataOutputStream ( s o c k e t . getOutputStream ( ) ) ) { i n t n o F i l e=i n . r e a d I n t ( ) ; System . out . p r i n t l n ( n o F i l e ) ; S t r i n g f i l e N a m e= ; i f ( n o F i l e ==1) f i l e N a m e= c a p i t o l . t x t ; else f i l e N a m e= j u n i t . t e x ; F i l e i n p u t F i l e=new F i l e ( f i l e N a m e ) ; F i l e R e a d e r f r=new F i l e R e a d e r ( i n p u t F i l e ) ; B u f f e r e d R e a d e r br= new B u f f e r e d R e a d e r ( f r ) ; String s ; while ( ( s=br . r e a d L i n e ( ) ) ! = n u l l ) out . writeUTF ( s ) ; out . writeUTF ( e n d O F f i l e ) ; out . f l u s h ( ) ; br . c l o s e ( ) ; fr . close (); System . out . p r i n t l n ( A c t i v i t y F i n i s h e d ! ) ; socket . close ( ) ; } catch ( IOException e ) { System . e r r . p r i n t l n ( S e r v e r c o m u n i c a t i o n e r r o r : +e . g e t M e s s a g e ( ) ) ; } } }
Exemplul 2.2.3 Clientul solicit a serverului transmisia unui sier grac, cerere care va satisf acut a de server. Clientul cunoa ste lista sierelor pe care le poate trimite serverul. Pe acea si structur a codurile claselor sunt Clasa StreamClient
1 2
32
3 4 5 6 7 8 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
j a v a . awt . image . B u f f e r e d I m a g e ; java . net . Socket ; j a v a . i o . IOException ; j a v a x . i m a g e i o . ImageIO ; j a v a . awt . Image ; java . u t i l . Scanner ;
public c l a s s S t r e a m C l i e n t { public s t a t i c void main ( S t r i n g [ ] a r g s ) { S t r i n g h o s t= l o c a l h o s t ; i n t p o r t =7999; System . out . p r i n t l n ( A l e g e t i f i s i e r u l : ) ; System . out . p r i n t l n ( 1 : xml p i c . j p g ) ; System . out . p r i n t l n ( 2 : b r a s o v . j p g ) ; S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ; i n t n o F i l e=s c a n n e r . n e x t I n t ( ) ; try ( S o c k e t c l i e n t S o c k e t = new S o c k e t ( hos t , p o r t ) ; InputStream i n=c l i e n t S o c k e t . g e t I n p u t S t r e a m ( ) ; DataOutputStream out = new DataOutputStream ( c l i e n t S o c k e t . getOutputStream ( ) ) ) { out . w r i t e I n t ( n o F i l e ) ; B u f f e r e d I m a g e b i=ImageIO . r e a d ( i n ) ; Image image=(Image ) b i ; ShowImage s=new ShowImage ( image ) ; s . show ( ) ; } catch ( E x c e p t i o n e ) { System . e r r . p r i n t l n ( C l i e n t c o m u n i c a t i o n e r r o r : +e . g e t M e s s a g e ( ) ) ; } } }
Clasa MyThread.java
1 2 3 4 5 6 7 8 9 10 12 13 15 16 17 19 20 21 22 23 25
import import import import import import import import import import
java . net . Socket ; j a v a . i o . InputStream ; j a v a . i o . OutputStream ; j a v a x . i m a g e i o . stream . FileImageOutputStream ; j a v a . i o . DataInputStream ; j a v a x . i m a g e i o . ImageIO ; j a v a . i o . IOException ; java . io . F i l e ; j a v a . awt . image . B u f f e r e d I m a g e ; j a v a . awt . Image ;
public c l a s s AppThread extends Thread { S o c k e t s o c k e t=n u l l ; public AppThread ( S o c k e t s o c k e t ) { t h i s . s o c k e t=s o c k e t ; } public void run ( ) { try ( OutputStream out=s o c k e t . getOutputStream ( ) ; DataInputStream i n=new DataInputStream ( s o c k e t . g e t I n p u t S t r e a m ( ) ) ) { i n t n o F i l e=i n . r e a d I n t ( ) ; System . out . p r i n t l n ( n o F i l e ) ; S t r i n g f i l e N a m e= ;
2.3. DATAGRAME
33
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
i f ( n o F i l e ==1) f i l e N a m e=xml p i c . j p g ; else f i l e N a m e= b r a s o v . j p g ; F i l e f i l e =new F i l e ( f i l e N a m e ) ; B u f f e r e d I m a g e b i=ImageIO . r e a d ( f i l e ) ; ImageIO . w r i t e ( bi , j p g , out ) ; out . f l u s h ( ) ; socket . close ( ) ; } catch ( E x c e p t i o n e ) { System . e r r . p r i n t l n ( S e r v e r c o m u n i c a t i o n e r r o r : +e . g e t M e s s a g e ( ) ) ; } } }
2.3
Datagrame
Pentru utilizarea datagramelor pachetul java.net pune la dispozit ie clasele DatagramSocket DatagramPacket MulticastSocket O aplicat ie trimite si recept ioneaz a pachete DatagramPacket prin intermediul unui DatagramSocket. Un pachet DatagramPacket poate trimis la mai mult i destinatari prin intermediul unui MulticastSocket. Reamintim c a o datagram a este un mesaj trimis prin ret ea a c arei sosire nu este garantat a iar momentul de sosire este neprecizat.
Clasa java.net.DatagramPacket.
Trimiterea unui pachet UDP necesit a crearea unui obiect DatagramPacket care cont ine corpul mesajului si adresa destinat iei. Apoi acest obiect DatagramPacket poate pus n ret ea n vederea trimiterii sale. Primirea unui pachet UDP necesit a crearea unui obiect DatagramPacket si apoi acceptarea unui pachet UDP din ret ea. Dup a primire, se poate extrage din obiectul DatagramPacket adresa surs a si cont inutul mesajului. Constructori Exist a doi constructori pentru datagrame UDP. Primul constructor este folosit pentru primirea de pachete si necesit a doar furnizarea unei memorii tampon, iar cel alalt este folosit pentru trimiterea de pachete si necesit a specicarea adresei destinatarului.
34
DatagramPacket(byte[ ] buer ,int lung ) Acest contructor este folosit pentru primirea pachetelor. Un pachet se memoreaz a n tamponul buer av and lung octet i. Dac a lungimea pachetului dep a se ste aceast a lungime, atunci pachetul este trunchiat iar octet ii n plus se pierd. DatagramPacket(byte[ ] buer ,int lung ,InetAddress adresa ,int port ) Acest constructor este folosit pentru crearea unui pachet n vederea expedierii. Corpul pachetului este cont inut n tamponul buer av and lung octet i. Pachetul va trimis c atre adresa si portul specicat. Trebuie s a existe un server UDP care ascult a la portul specicat pentru trimiterea pachetelor. Un server UDP poate coexista cu un server TCP care ascult a acela si port. Metode InetAddress getAddress() returneaz a adresa IP a expeditorului. int getPort() returneaz a portul expeditorului. byte[] getData() returneaz a cont inutul pachetului. int getLength() returneaz a lungimea pachetului. void setAddress(InetAddress adresa ) xeaz a adresa IP a pachetului. void setPort(int port ) xeaz a portul. void setData(byte[] buer ) xeaz a cont inutul pachetului. void setLength(int lung ) xeaz a lungimea pachetului.
2.3. DATAGRAME
35
Clasa java.net.DatagramSocket
Aceast a clas a se folose ste at at pentru trimiterea, c at si pentru primirea obiectelor DatagramPacket. Un obiect DatagramSocket ascult a la un port cuprins ntre 1 si 65535 (porturile cuprinse ntre 1 si 1023 sunt rezervate pentru aplicat iile sistem). Deoarece UDP nu este orientat pe conexiune, se va crea un singur obiect DatagramSocket pentru trimiterea pachetelor c atre diferite destinat ii si primirea pachetelor de la diferite surse. Constructori DatagramSocket() throws SocketException Creaz a un obiect DatagramSocket cu un num ar de port aleator; DatagramSocket(int port ) throws SocketException Creaz a un obiect DatagramSocket cu num arul de port specicat; Metode Clasa DatagramSocket cont ine metode pentru trimiterea si primirea de obiecte DatagramPacket, nchiderea soclului, determinarea informat iilor adresei locale si setarea timpului de primire. void send(DatagramPacket pachet ) throws IOException Trimite pachet ul prin ret ea. Dac a se trimit pachete la o destinat ie necunoscut a sau care nu ascult a, n cele din urm a se genereaz a o except ie IOException. void receive(DatagramPacket pachet ) throws IOException Metoda prime ste un singur pachet UDP n obiectul pachet specicat. Apoi, pachetul poate inspectat pentru determinarea adresei IP surs a, portul surs a si lungimea mesajului. Execut ia metodei este blocat a p an a c and se prime ste cu succes un pachet sau se scurge timpul de a steptare. InetAddress getLocalAddress() Returneaz a adresa local a c atre care este legat acest DatagramSocket; int getLocalPort() Returneaz a num arul de port unde ascult a DatagramSocket. void close() Inchide DatagramSocket.
36
void setSoTimeout(int timpDeA steptere ) throws SocketException Metoda xeaz a timpul de a steptare ( n milisecunde) a soclului. Metoda receive() se va bloca pentru timpul de a steptare specicat pentru primirea unui pachet UDP, dup a care va arunca o except ie Interrupted Exception. Dac a valoarea parametrului este 0, atunci soclul este blocat. int getSoTimeout() throws SocketException Returneaz a timpul de a steptare. void setSendBufferSize(int lungime ) throws SocketException Fixeaz a lungimea tamponului de trimitere a soclului la valoarea specicat a. Nu poate trimis mesaj UDP de lungime mai mare de aceast a valoare. int getSendBufferSize() throws SocketException Returneaz a lungimea tamponului de trimitere a soclului. void setReceiveBufferSize(int lungime ) throws SocketException Fixeaz a lungimea tamponului de primire a soclului la valoarea specicat a. Nu poate primit un mesaj UDP de lungime mai mare de aceast a valoare. int getReceiveBufferSize() throws SocketException Returneaz a lungimea tamponului de primire a soclului. void connect(InetAddress adresa, int port ) throws SocketException Conecteaz a soclul la adresa si portul specicat. Aceast a metod a nu este cerut a pentru operat iile uzuale UDP. void disconnect() Deconecteaz a soclul conectat. InetAddress getInetAddress() Returneaz a obiectul InetAddress c atre care este conectat soclul sau null dac a acesta nu este conectat. int getPort() Returneaz a portul la care este conectat soclul sau -1 dac a acesta nu este conectat.
2.3. DATAGRAME
37
Clasa java.net.InetAddress
Datele pot trimise prin ret ea indic and adresa IP corespunz atoare ma sinii destinat ie. Clasa InetAddress furnizeaz a acces la adresele IP. Nu exist a constructori pentru aceast a clas a. Instant ele trebuie create folosind metodele statice: InetAddress getLocalHost() throws UnknownHostException Returneaz a un obiect InetAddress corespunz ator ma sinii locale. InetAddress getByName(String host ) throws UnknownHostException Returneaz a un obiect InetAddress corespunz ator ma sinii host, parametru care poate specicat prin nume (de exemplu atlantis) sau prin adresa IP (168.192.0.1). InetAddress [ ]getAllByName(String host ) throws UnknownHostException Returneaz a un sir de obiecte InetAddress corespunz ator ec arei adrese IP a ma sinii host. Metodele clasei InetAddress byte [ ] getAddress() Returneaz a sirul de octet i corespunz ator obiectului InetAddress de referint a. String getHostName() Returneaz a numele ma sinii gazd a. String getHostAddress() Returneaz a adresa IP a ma sinii gazd a. boolean isMulticastAddress() Returneaz a true dac a obiectul InetAddress reprezint a o adres a IP multicast (cuprins ntre 224.0.0.0 si 239.255.255.255). Exemplul urm ator a seaz a numele si adresa calculatorului gazd a c at si acela al calculatoarelor ale c aror nume este transmis programului ca parametru. Exemplul 2.3.1
38
1 2 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
import j a v a . n e t . I n e t A d d r e s s ; import j a v a . n e t . UnknownHostException ; public c l a s s AdreseIP { public s t a t i c void main ( S t r i n g a r g [ ] ) { I n e t A d d r e s s a d r e s a=n u l l ; try { a d r e s a=I n e t A d d r e s s . g e t L o c a l H o s t ( ) ; System . out . p r i n t l n ( C a l c u l a t o r u l gazda a r e : ) ; System . out . p r i n t l n ( numele : +a d r e s a . getHostName ( ) ) ; System . out . p r i n t l n ( a d r e s a IP : +a d r e s a . g e t H o s t A d d r e s s ( ) ) ; } catch ( UnknownHostException e ) { System . out . p r i n t l n ( UnknownHostException : +e . g e t M e s s a g e ( ) ) ; } i f ( a r g . l e n g t h > 0) { f o r ( i n t i =0; i <a r g . l e n g t h ; i ++){ try { a d r e s a=I n e t A d d r e s s . getByName ( a r g [ i ] ) ; System . out . p r i n t l n ( C a l c u l a t o r u l +a r g [ i ]+ a r e : ) ; System . out . p r i n t l n ( a d r e s a IP \ getByName \ : +a d r e s a ) ; byte [ ] b=a d r e s a . g e t A d d r e s s ( ) ; f o r ( i n t j =0; j <b . l e n g t h ; j ++) i f ( b [ j ] < 0) System . out . p r i n t (256+b [ j ]+ . ) ; else System . out . p r i n t ( b [ j ]+ . ) ; System . out . p r i n t l n ( ) ; } catch ( UnknownHostException e ) { System . out . p r i n t l n ( UnknownHostException : + e . getMessage ( ) ) ; } } } } }
2.3.1
Un pachet de tip DatagramPacket este alc atuit dintr-un sir de octet i. Este datoria programatorului s a transforme datele (mesajul) n siruri de octet i la expediere si la recept ie. Transformarea unui obiect serializabil ntr-un sir de octet i si invers se poate realiza cu schema
2.3. DATAGRAME
39
Fie socket un obiect de tip DatagramSocket prin intermediul c aruia se execut a expedierea / recept ionarea pachetelor de tip DatagramPacket. In principiu expedierea si transformarea obiectului obj ntr-un sir de octet i se poate realiza cu secvent a de cod ByteArrayOutputStream baos=new ByteArrayOutputStream(256); ObjectOutputStream out=new ObjectOutputStream(baos); out.writeObject(obj); byte[] bout=baos.toByteArray(); DatagramPacket packet=new DatagramPacket(bout,bout.length, address,port); socket.send(packet); unde address si port sunt adresa si portul destinatarului. Dac a packet este un obiect DatagramPacket recept ionat atunci metodele getAddress() si getPort() furnizeaz a adresa si portul expeditorului Recept ionarea si transformarea invers a 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(); Dac a mesajul este un obiect String atunci el se transform a ntr-un sir de octet i cu metoda byte[] String.getByte() si invers, el se obt ine prin new String(bin) sau new String(packet.getData()). Exemplul 2.3.2 Program am aplicat ia de calculul a celui mai mare divizor comun a dou a numere naturale.
40
Clientul va trimite un obiect Protocol, care va cont ine datele problemei si va recept iona un obiect de acela si tip cu rezultatul (cel mai mare divizor comun) n primul c amp al obiectului. Aceasta clasa este disponibil a at at serverului c at si clientului. Se va utiliza arhitectura de aplicat ie dezvoltat a n nalul sect iunii anterioare. Aplicat ia se va compune din: Aplicat ia server alc atuit a din: Interfat a
1 2 3 4 5 6
package i s e r v e r ; import j a v a . n e t . DatagramSocket ; public i n t e r f a c e IMyMServer { public DatagramSocket getDatagramSocket ( i n t p o r t ) ; public void myAction ( DatagramSocket datagramSocket ) ; }
Implementarea interfet ei
1 2 3 4 5 6 7 8 9 10 11 12 14 16 17 18 19 20 21 22
package s e r v e r . impl ; import s e r v e r . App ; import s e r v e r . P r o t o c o l ; import i s e r v e r . IMyMServer ; import j a v a . n e t . DatagramSocket ; import j a v a . n e t . DatagramPacket ; import j a v a . n e t . I n e t A d d r e s s ; import j a v a . i o . IOException ; import j a v a . i o . ByteArrayInputStream ; import j a v a . i o . ByteArrayOutputStream ; import j a v a . i o . O b j e c t I n p u t S t r e a m ; import j a v a . i o . ObjectOutputStream ; public c l a s s MyMServer implements IMyMServer { public DatagramSocket getDatagramSocket ( i n t p o r t ) { DatagramSocket datagramSocket = n u l l ; try { datagramSocket = new DatagramSocket ( p o r t ) ; } catch ( IOException e ) { System . e r r . p r i n t l n ( Could not l i s t e n on p o r t : +p o r t ) ;
2.3. DATAGRAME
41
23 24 25 26 27 28 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 59
System . e r r . p r i n t l n ( e . g e t M e s s a g e ( ) ) ; System . e x i t ( 1 ) ; } System . out . p r i n t l n ( DatagramSocket i s r e a d y . . . ) ; return datagramSocket ; } public void myAction ( DatagramSocket datagramSocket ) { DatagramPacket p a c k e t=n u l l ; App app=new App ( ) ; P r o t o c o l p=n u l l ; while ( true ) { try { byte [ ] b i n=new byte [ 4 0 4 8 ] ; p a c k e t=new DatagramPacket ( bin , b i n . l e n g t h ) ; datagramSocket . r e c e i v e ( p a c k e t ) ; ByteArrayInputStream b a i s=new ByteArrayInputStream ( b i n ) ; O b j e c t I n p u t S t r e a m i n=new O b j e c t I n p u t S t r e a m ( b a i s ) ; p=( P r o t o c o l ) i n . r e a d O b j e c t ( ) ; p . x=app . cmmdc( p . x , p . y ) ; p . y =0; ByteArrayOutputStream baos=new ByteArrayOutputStream ( 2 5 6 ) ; ObjectOutputStream out=new ObjectOutputStream ( baos ) ; out . w r i t e O b j e c t ( p ) ; byte [ ] bout=baos . toByteArray ( ) ; I n e t A d d r e s s a d d r e s s=p a c k e t . g e t A d d r e s s ( ) ; i n t p o r t=p a c k e t . g e t P o r t ( ) ; p a c k e t=new DatagramPacket ( bout , bout . l e n g t h , a d d r e s s , p o r t ) ; datagramSocket . send ( p a c k e t ) ; } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ; } } } }
package s e r v e r ; import j a v a . n e t . DatagramSocket ; import s e r v e r . impl . MyMServer ; import i s e r v e r . IMyMServer ; public c l a s s AppServer { public s t a t i c void main ( S t r i n g [ ] a r g s ) { i n t p o r t =7999; i f ( a r g s . l e n g t h > 0) p o r t=I n t e g e r . p a r s e I n t ( a r g s [ 0 ] ) ; IMyMServer myMServer=new MyMServer ( ) ; DatagramSocket datagramSocket=myMServer . getDatagramSocket ( p o r t ) ; myMServer . myAction ( datagramSocket ) ; } }
Aplicat ia client
42
1 2 3 4 5 6 7 8 9 10 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
package c l i e n t ; import j a v a . n e t . DatagramSocket ; import j a v a . n e t . DatagramPacket ; import j a v a . n e t . I n e t A d d r e s s ; import j a v a . i o . ByteArrayInputStream ; import j a v a . i o . ByteArrayOutputStream ; import j a v a . i o . O b j e c t I n p u t S t r e a m ; import j a v a . i o . ObjectOutputStream ; import s e r v e r . P r o t o c o l ; import j a v a . u t i l . S c a n n e r ; public c l a s s CmmdcClient { public s t a t i c void main ( S t r i n g [ ] a r g s ) { S t r i n g h o s t S e r v e r= l o c a l h o s t ; i n t p o r t S e r v e r =7999; i f ( a r g s . l e n g t h > 0) h o s t S e r v e r=a r g s [ 0 ] ; i f ( a r g s . l e n g t h > 1) p o r t S e r v e r=I n t e g e r . p a r s e I n t ( a r g s [ 1 ] ) ; try { DatagramSocket s o c k e t=new DatagramSocket ( ) ; P r o t o c o l p=new P r o t o c o l ( 0 , 0 ) ; S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ; System . out . p r i n t l n ( I n t r o d u c e t i p r i m u l numar : ) ; p . x=s c a n n e r . nextLong ( ) ; System . out . p r i n t l n ( I n t r o d u c e t i a l d o i l e a numar : ) ; p . y=s c a n n e r . nextLong ( ) ; ByteArrayOutputStream baos=new ByteArrayOutputStream ( 2 5 6 ) ; ObjectOutputStream out=new ObjectOutputStream ( baos ) ; out . w r i t e O b j e c t ( p ) ; byte [ ] bout=baos . toByteArray ( ) ; I n e t A d d r e s s a d d r e s s=I n e t A d d r e s s . getByName ( h o s t S e r v e r ) ; DatagramPacket p a c k e t = new DatagramPacket ( bout , bout . l e n g t h , a d d r e s s , p o r t S e r v e r ) ; s o c k e t . send ( p a c k e t ) ; byte [ ] b i n=new byte [ 4 0 4 8 ] ; p a c k e t=new DatagramPacket ( bin , b i n . l e n g t h ) ; socket . r e c e i v e ( packet ) ; ByteArrayInputStream b a i s=new ByteArrayInputStream ( b i n ) ; O b j e c t I n p u t S t r e a m i n=new O b j e c t I n p u t S t r e a m ( b a i s ) ; p=( P r o t o c o l ) i n . r e a d O b j e c t ( ) ; System . out . p r i n t l n ( Cmmdc = +p . x ) ; socket . close ( ) ; } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ; } } }
2.3. DATAGRAME
43
2.3.2
Clasa java.net.MulticastSocket
Prin intermediul unui soclu de tip MulticastSocket se pot recept iona datagrame expediate de un server c atre tot i client ii cu un asemenea soclu. Constructori MulticastSocket(int port ) throws SocketException Metode void joinGroup(InetAddress adres a ) throws SocketException Soclul se conecteaz a la grupul denit de adresa IP (de tip D, adic a cuprins ntre 224.0.0.0 si 239.255.255.255). void leaveGroup(InetAddress adres a ) throws SocketException Soclul se deconecteaz a la grupul denit de adresa IP. void close() Preg atirea clientului n vederea recept ion arii datagramelor printr-un soclu de tip MulticastSocket const a din MulticastSocket socket= new MulticastSocket(port); InetAddress adresa=InetAddress.getByName("230.0.0.1"); socket.joinGroup(adresa); In nal, clientul se deconecteaz a si nchide soclul. socket.leaveGroup(adresa); socket.close(); Pachetele trimise de programul server trebuie s a se adreseze grupului, identicat prin adresa IP de tip D. Astfel prin multicast serverul trimite pachete la o adres a de grup si la un port xat. Pachetele emise de server sunt recept ionate de orice client ce creaz a un soclu de tip MulticastSocket pentru portul la care emite serverul si care se al atur a grupului. Prin broadcast serverul emite datagrame c atre orice calculator al ret elei locale la un anumit port. Faptul c a emiterea datagramelor este de tip broadcast se indic a prin
44
DatagramSocket.setBroadcast(true) Orice client care si creaz a un soclu la portul la care emite serverul recept ioneaz a datagramele trimise de server. Adresa utilizat a de server la crearea datagramelor trebuie s a identice ret eaua. Observat ie. In cazul unui calculator izolat este nevoie de instalarea driverului Microsoft Loopback Adapter, care simuleaz a existent a unei pl aci de ret ea active. Exemplul 2.3.3 Multicast si Broadcast: programele server emit din cinci n cinci secunde ora exact a. Un client va recept iona c ate cinci datagrame. Codurile sunt date n Fig. 2.1 si Fig. 2.2, respectiv pentru partea de server si cea de client.
2.4
Canale de comunicat ie
Odat a cu versiunea j2sdk1.4 apar clase noi pentru operat ii de intrare - ie sire n pachetele java.nio si java.nio.channels. Pachetul java.nio.channels cont ine clase pentru comunicat ia n ret ea, si anume canalele de comunicat ie. Utiliz am clasele java.nio.channels.SocketChannel, java.nio.channel. DatagramChannel. Informat ia transportat a n aceste canale de comunicat ie trebuie nglobat a 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 cont ine date de tipul specicat de denumirea clasei. Un obiect de tip Buffer este caracterizat de
45
MulticastServer import java.io.*; import java.net.*; import java.util.*; import java.text.DateFormat; public class MulticastServer{ public static void main(String[] args){ long FIVE_SECONDS = 5000; boolean sfarsit=false; int serverPort=7000; int clientPort=7001; byte[] buf = new byte[256]; Date data=null; DatagramPacket packet = null; try(DatagramSocket socket= =new DatagramSocket(serverPort)){ while (! sfarsit){ data=new Date(); String df=DateFormat. getTimeInstance().format(data); buf = df.getBytes(); // send it InetAddress group = InetAddress.getByName("230.0.0.1"); packet=new DatagramPacket(buf, buf.length,group,clientPort); socket.send(packet); // sleep for a while Thread.sleep(FIVE_SECONDS); } } catch (Exception e) { System.out.println(e.getMessage()); } } }
BroadcastServer import java.io.*; import java.net.*; import java.util.*; import java.text.DateFormat; public class BroadcastServer{ public static void main(String[] args){ long FIVE_SECONDS = 5000; boolean sfarsit=false; int serverPort=7000; int clientPort=7001; byte[] buf = new byte[256]; Date data = null; DatagramPacket packet = null; try(DatagramSocket socket= new DatagramSocket(serverPort)){ while (! sfarsit) { data=new Date(); String df=DateFormat. getTimeInstance().format(data); buf = df.getBytes(); InetAddress group = InetAddress.getByName("192.168.0.255"); packet=new DatagramPacket(buf, buf.length,group,clientPort); socket.setBroadcast(true); socket.send(packet); Thread.sleep(FIVE_SECONDS); } } catch (Exception e) { System.out.println(e.getMessage()); } } }
46
MulticastClient import java.io.*; import java.net.*; public class MulticastClient { public static void main(String[] args) throws IOException { DatagramPacket packet; byte[] buf = new byte[256]; int clientPort=7001; MulticastSocket socket= new MulticastSocket(clientPort); InetAddress address= InetAddress.getByName("230.0.0.1"); socket.joinGroup(address); int i=-1; do{ i++; packet=new DatagramPacket(buf, buf.length); socket.receive(packet); String received=new String(packet.getData()); System.out.println("Am primit: "+received); } while(i<5); socket.leaveGroup(address); socket.close(); } }
BroadcastClient import java.io.*; import java.net.*; public class BroadcastClient { public static void main(String[] args) throws IOException { DatagramPacket packet; byte[] buf = new byte[256]; int clientPort=7001; DatagramSocket socket= new DatagramSocket(clientPort);
int i=-1; do{ i++; packet=new DatagramPacket(buf, buf.length); socket.receive(packet); String received=new String(packet.getData()); System.out.println("Am primit: "+received); } while(i<5); socket.close(); } }
47
capacitate (capacity) num arul elementelor care pot nmagazitate n tampon; limit a (limit) marginea superior a a indicelui; indice (position) valoarea curent a a indicelui, ce corespunde unui cursor ce indic a nceputul zonei unde se introduc sau de unde se extrag date din tampon. Metode generale clear() permite unui obiect de tip Buffer s a e re nc arcat. Fixeaz a limita = capacitate si indice = 0. ip() preg ate ste obiectul de tip Buffer pentru consultare (citire). Fixeaz a limita =num arul elementelor din tampon si indice = 0. rewind() preg ate ste obiectul de tip Buffer pentru re-citire. remaining() returneaz a num aul octet ilor cuprin si ntre valoarea indicelui si limit a.
Clasa java.nio.ByteBuffer
Instant ierea unui obiect se obt ine prin metoda static a static ByteBuffer allocate(capacitate ) Introducerea si extragerea datelor din tampon se poate face n mod relativ - implic a modicarea indicelui tamponului; absolut - far a modicarea indicelui. Metode Introducerea datelor n mod relativ: ByteBuffer put(byte b ) ByteBuffer putTip (tip x ) Extragerea datelor n mod relativ: byte get()
48 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 char, short, int, long, float, double. Alte metode public final boolean hasRemaining() Dac a indicele nu este egal cu limita atunci returneaz a true, semnal and existent a n tampon a unor octet i. static ByteBuffer wrap(byte[] array ) public static ByteBuffer wrap(byte[] array ,int oset ,int length ) Converte ste sirul de octet i ntr-un obiect ByteBuffer. public final byte[] array() Transformarea invers a, obiectul ByteBuffer este convertit ntr-un sir de octet i. Un obiect de tip ByteBuffer se poate percepe ca un obiect de tip LongBuffer, DoubleBuffer, etc prin ByteBuffer bb=ByteBuffer.allocate(10); LongBuffer lb=bb.asLongBuffer(); DoubleBuffer db=bb.asDoubleBuffer();
49
Clasa java.net.InetSocketAddress
Clasa InetSocketAddress extinde clasa SocketAddress si ncapsuleaz a adresa unui calculator din Internet mpreun a cu un port n vederea leg arii la un ServerSocket. Constructori: InetSocketAddress(InetAddress addr ,int port ) InetSocketAddress(String numeCalculator ,int port ) InetSocketAddress(int port )
Clasa java.nio.channels.ServerSocketChannel
Crearea unui obiect de tip ServerSocketChannel se realizeaz a prin static ServerSocketChannel open() throws IOException Unui asemenea obiect i se asociaz a un ServerSocket prin metoda ServerSocket socket() throws IOException. Obiectul de tip ServerSocket trebuie leagat la un port de comunicat ie prin metoda void bind(InetSocketAddress endpoint ) throws IOException. S ablonul de utilizare este try{ ServerSocketChannel ssc=ServerSocketChannel.open(); ServerSocket ss=ssc.socket(); InetSocketAddress isa=new InetSocketAddress(addr,port); ss.bind(isa); } catch(Exception e){. . .} La apelul unui client, serverul trebuie s a genereze un obiect de tip Socket Channel prin care se vor derula comunicat iile cu clientul. Acest canal de comunicat ie se obt ine cu metoda accept().
50
Clasa java.nio.channels.SocketChannel
Crearea unui obiect de tip SocketChannel se realizeaz a prin static SocketChannel open() throws IOException Acest obiect trebuie conectat la obiectul ServerSocketChannel al serverului cu metoda connect(InetSocketAddress addr ). Datele vehiculate printr-un SocketChannel sunt de tip ByteBuffer. Datele se transmit prin metoda int write(ByteBuffer surs a) si se recept ioneaz a prin metoda int read(ByteBuffer destinat ie ) Valoarea returnat a de cele dou a metode reprezint a num arul octet ilor trimi si / recept ionat i. Doar octet ii unui obiect de tip ByteBuffer cuprin si ntre indice si limit a sunt transmi si prin canal. Astfel, dup a nc arcarea unui obiectului ByteBuffer cu metode relative trebuie apelat a metoda flip(). Canalul se nchide cu metoda close(). Exemplul 2.4.1 Calculul celui mai mare divizor comun a dou a numere naturale. Aplicat ie client-server bazat pe canale de comunicat ie prin socluri se compune din: Aplicat ia server alc atuit a din: Interfat a
1 2 3 4 5 6
Implementarea interfet ei
51
1 2 3 4 5 6 7 8 9 11 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 30 31 32 33 34 35 36 37 38 39 40 41 42 43
package s e r v e r . impl ; import s e r v e r . AppThread ; import i s e r v e r . IMyMServer ; import j a v a . n e t . I n e t S o c k e t A d d r e s s ; import j a v a . n e t . S e r v e r S o c k e t ; import j a v a . n i o . c h a n n e l s . S e r v e r S o c k e t C h a n n e l ; import j a v a . u t i l . c o n c u r r e n t . E x e c u t o r S e r v i c e ; import j a v a . u t i l . c o n c u r r e n t . E x e c u t o r s ; import j a v a . i o . IOException ; public c l a s s MyMServer implements IMyMServer { public S e r v e r S o c k e t C h a n n e l g e t S e r v e r S o c k e t C h a n n e l ( i n t p o r t ) { S e r v e r S o c k e t C h a n n e l s e r v e r S o c k e t C h a n n e l=n u l l ; try { s e r v e r S o c k e t C h a n n e l = S e r v e r S o c k e t C h a n n e l . open ( ) ; I n e t S o c k e t A d d r e s s i s a=new I n e t S o c k e t A d d r e s s ( p o r t ) ; S e r v e r S o c k e t s s=s e r v e r S o c k e t C h a n n e l . s o c k e t ( ) ; s s . bind ( i s a ) ; } catch ( IOException e ) { System . out . p r i n t l n ( S e r v e r S o c k e t C h a n n e l E r r o r : + e . getMessage ( ) ) ; System . e x i t ( 0 ) ; } System . out . p r i n t l n ( S e r v e r r e a d y . . . ) ; return s e r v e r S o c k e t C h a n n e l ; } public void myAction ( S e r v e r S o c k e t C h a n n e l s e r v e r S o c k e t C h a n n e l ) { i n t NTHREADS=100; E x e c u t o r S e r v i c e e x e c=E x e c u t o r s . newFixedThreadPool (NTHREADS) ; while ( true ) { try { AppThread o b j=new AppThread ( s e r v e r S o c k e t C h a n n e l . a c c e p t ( ) ) ; exec . execute ( obj ) ; } catch ( IOException e ) { System . e r r . p r i n t l n ( MyActionException : +e . g e t M e s s a g e ( ) ) ; } } } }
Clasa AppThread
1 2 3 4 6 7 9 10 11
package s e r v e r ; import j a v a . i o . IOException ; import j a v a . n i o . c h a n n e l s . S o c k e t C h a n n e l ; import j a v a . n i o . B y t e B u f f e r ; public c l a s s AppThread extends Thread { S o c k e t C h a n n e l s o c k e t C h a n n e l=n u l l ; public AppThread ( S o c k e t C h a n n e l s o c k e t C h a n n e l ) { t h i s . s o c k e t C h a n n e l=s o c k e t C h a n n e l ; }
52
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
public void run ( ) { try { B y t e B u f f e r bb = B y t e B u f f e r . a l l o c a t e ( 1 6 ) ; // L o n g B u f f e r l b = bb . a s L o n g B u f f e r ( ) ; s o c k e t C h a n n e l . r e a d ( bb ) ; // V a r i a n t a 1 long m =bb . getLong ( 0 ) ; long n=bb . getLong ( 8 ) ; // V a r i a n t a 2 // l o n g m =l b . g e t ( 0 ) ; // l o n g n=l b . g e t ( 1 ) ; App app=new App ( ) ; long r=app . cmmdc(m, n ) ; bb . c l e a r ( ) ; // V a r i a n t a 1 bb . putLong ( 0 , r ) ; // V a r i a n t a 2 // l b . p u t ( r ) ; s o c k e t C h a n n e l . w r i t e ( bb ) ; socketChannel . c l o s e ( ) ; } catch ( IOException e ) { System . e r r . p r i n t l n ( S e r v e r c o m u n i c a t i o n e r r o r : + e . getMessage ( ) ) ; } } }
package s e r v e r ; import j a v a . n i o . c h a n n e l s . S e r v e r S o c k e t C h a n n e l ; import s e r v e r . impl . MyMServer ; import i s e r v e r . IMyMServer ; public c l a s s AppServer { public s t a t i c void main ( S t r i n g [ ] a r g s ) { i n t p o r t =7999; i f ( a r g s . l e n g t h > 0) p o r t=I n t e g e r . p a r s e I n t ( a r g s [ 0 ] ) ; IMyMServer myMServer=new MyMServer ( ) ; ServerSocketChannel serverSocketChannel = myMServer . g e t S e r v e r S o c k e t C h a n n e l ( p o r t ) ; myMServer . myAction ( s e r v e r S o c k e t C h a n n e l ) ; } }
Aplicat ia client
1 2 3 4 5 6 7 9
package c l i e n t ; import j a v a . n e t . UnknownHostException ; import j a v a . n e t . I n e t S o c k e t A d d r e s s ; import j a v a . n i o . c h a n n e l s . S o c k e t C h a n n e l ; import j a v a . n i o . B y t e B u f f e r ; import j a v a . u t i l . S c a n n e r ; import j a v a . i o . IOException ; public c l a s s CmmdcClient {
53
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
public s t a t i c void main ( S t r i n g [ ] a r g s ) { S t r i n g h o s t= l o c a l h o s t ; i n t p o r t =7999; i f ( a r g s . l e n g t h > 0) h o s t=a r g s [ 0 ] ; i f ( a r g s . l e n g t h > 1) p o r t=I n t e g e r . p a r s e I n t ( a r g s [ 1 ] ) ; S o c k e t C h a n n e l s c=n u l l ; try { I n e t S o c k e t A d d r e s s i s a=new I n e t S o c k e t A d d r e s s ( hos t , p o r t ) ; s c=S o c k e t C h a n n e l . open ( ) ; sc . connect ( i s a ) ; } catch ( UnknownHostException e ) { System . e r r . p r i n t l n ( S e r v e r n e c u n o s c u t : +h o s t+ +e . g e t M e s s a g e ( ) ) ; System . e x i t ( 1 ) ; } catch ( IOException e ) { System . e r r . p r i n t l n ( C o n e c t a r e i m p o s i b i l a l a : + h o s t+ pe p o r t u l +p o r t+ +e . g e t M e s s a g e ( ) ) ; System . e x i t ( 1 ) ; } S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ; long m, n , r ; System . out . p r i n t l n ( m = ) ; m =s c a n n e r . nextLong ( ) ; System . out . p r i n t l n ( n= ) ; n=s c a n n e r . nextLong ( ) ; B y t e B u f f e r bb=B y t e B u f f e r . a l l o c a t e ( 1 6 ) ; // V a r i a n t a 1 bb . putLong ( 0 ,m) . putLong ( 8 , n ) ; // V a r i a n t a 2 // L o n g B u f f e r l b=bb . a s L o n g B u f f e r ( ) ; // l b . p u t ( 0 ,m) . p u t ( 1 , n ) ; try { s c . w r i t e ( bb ) ; bb . c l e a r ( ) ; s c . r e a d ( bb ) ; // V a r i a n t a 1 r=bb . getLong ( 0 ) ; // V a r i a n t a 2 // r=l b . g e t ( 0 ) ; System . out . p r i n t l n ( Cmmdc : +r ) ; sc . clos e ( ) ; } catch ( E x c e p t i o n e ) { System . e r r . p r i n t l n ( E r o a r e de c o m u n i c a t i e +e . g e t M e s s a g e ( ) ) ; } } }
Varianta comentat a corespunde cazului n care se utilizear a clasa acoperitoare LongBuffer. Alternativ, se poate lucra cu obiecte. Pentru exemplul dat, utiliz and clasa Protocol, introdus a n sect iunea dedicat a datagramelor, codul privind trimiterea ti recept ia datelor din clasele AppThread si CmmdcClient va
54
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
. . . B y t e B u f f e r bb = B y t e B u f f e r . a l l o c a t e ( 1 0 2 4 ) ; s o c k e t C h a n n e l . r e a d ( bb ) ; byte [ ] b i n=bb . a r r a y ( ) ; ByteArrayInputStream b a i s=new ByteArrayInputStream ( b i n ) ; O b j e c t I n p u t S t r e a m i n=new O b j e c t I n p u t S t r e a m ( b a i s ) ; P r o t o c o l p=( P r o t o c o l ) i n . r e a d O b j e c t ( ) ; App app=new App ( ) ; p . x=app . cmmdc( p . x , p . y ) ; p . y =0; ByteArrayOutputStream baos=new ByteArrayOutputStream ( 2 5 6 ) ; ObjectOutputStream out=new ObjectOutputStream ( baos ) ; out . w r i t e O b j e c t ( p ) ; byte [ ] bout=baos . toByteArray ( ) ; bb=B y t e B u f f e r . wrap ( bout ) ; s o c k e t C h a n n e l . w r i t e ( bb ) ; socketChannel . c l o s e ( ) ; . . .
si, respectiv,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
. . . B y t e B u f f e r bb=B y t e B u f f e r . a l l o c a t e ( 2 0 4 8 ) ; P r o t o c o l p=new P r o t o c o l (m, n ) ; try { ByteArrayOutputStream baos=new ByteArrayOutputStream ( 2 5 6 ) ; ObjectOutputStream out=new ObjectOutputStream ( baos ) ; out . w r i t e O b j e c t ( p ) ; byte [ ] bout=baos . toByteArray ( ) ; bb=B y t e B u f f e r . wrap ( bout ) ; s c . w r i t e ( bb ) ; bb . c l e a r ( ) ; s c . r e a d ( bb ) ; byte [ ] b i n=bb . a r r a y ( ) ; ByteArrayInputStream b a i s=new ByteArrayInputStream ( b i n ) ; O b j e c t I n p u t S t r e a m i n=new O b j e c t I n p u t S t r e a m ( b a i s ) ; p=( P r o t o c o l ) i n . r e a d O b j e c t ( ) ; System . out . p r i n t l n ( Cmmdc : +p . x ) ; sc . clos e ( ) ; . . .
Clasa java.nio.channels.DatagramChannel
S ablonul de programare pentru instant ierea unui obiect de tip DatagramChannel este DatagramChannel dc=null; InetSocketAddress isa=new InetSocketAddress(port); try{ dc=DatagramChannel.open(); DatagramSocket datagramSocket=dc.socket(); datagramSocket.bind(isa);
55
} catch(Exception e){. . .} unde port este portul folosit de DatagramChannel. Dac a port=0 atunci se alege aleator un port disponibil. Transmiterea unui obiect ByteBuffer se face cu metoda public int send(ByteBuffer src , SocketAddress target ) throws IOException Metoda returneaz a num arul de octet i expediat i. Recept ia unui ByteBuffer se obt ine cu metoda public SocketAddress receive(ByteBuffer dst ) throws IOException Obiectul returnat reprezint a adresa expeditorului. Exemplul 2.4.2 Calculul celui mai mare divizor comun a dou a numere naturale. Aplicat ia server este alc atuit a din: Interfat a
1 2 3 4 5 6
package i s e r v e r ; import j a v a . n i o . c h a n n e l s . DatagramChannel ; public i n t e r f a c e IMyMServer { public DatagramChannel getDatagramChannel ( i n t p o r t ) ; public void myAction ( DatagramChannel datagramChannel ) ; }
Implementarea interfet ei
1 2 3 4 5 6 7 8 9 11 13 14 15 16 17 18 19
package s e r v e r . impl ; import s e r v e r . App ; import i s e r v e r . IMyMServer ; import j a v a . n e t . DatagramSocket ; import j a v a . n e t . I n e t S o c k e t A d d r e s s ; import j a v a . n e t . S o c k e t A d d r e s s ; import j a v a . n i o . c h a n n e l s . DatagramChannel ; import j a v a . n i o . B y t e B u f f e r ; import j a v a . i o . IOException ; public c l a s s MyMServer implements IMyMServer { public DatagramChannel getDatagramChannel ( i n t p o r t ) { DatagramChannel datagramChannel=n u l l ; I n e t S o c k e t A d d r e s s i s a=new I n e t S o c k e t A d d r e s s ( p o r t ) ; try { datagramChannel = DatagramChannel . open ( ) ; DatagramSocket datagramSocket=datagramChannel . s o c k e t ( ) ; datagramSocket . bind ( i s a ) ;
56
20 21 22 23 24 25 26 27 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
} catch ( IOException e ) { System . out . p r i n t l n ( DatagramChannelError : +e . g e t M e s s a g e ( ) ) ; System . e x i t ( 0 ) ; } System . out . p r i n t l n ( S e r v e r r e a d y . . . ) ; return datagramChannel ; } public void myAction ( DatagramChannel datagramChannel ) { i n t NTHREADS=100; while ( true ) { App app=new App ( ) ; try { B y t e B u f f e r bb = B y t e B u f f e r . a l l o c a t e ( 1 6 ) ; // L o n g B u f f e r l b = bb . a s L o n g B u f f e r ( ) ; S o c k e t A d d r e s s s a=datagramChannel . r e c e i v e ( bb ) ; // V a r i a n t a 1 long m =bb . getLong ( 0 ) ; long n=bb . getLong ( 8 ) ; // V a r i a n t a 2 // l o n g m =l b . g e t ( 0 ) ; // l o n g n=l b . g e t ( 1 ) ; long r=app . cmmdc(m, n ) ; bb . c l e a r ( ) ; // V a r i a n t a 1 bb . putLong ( 0 , r ) ; // V a r i a n t a 2 // l b . p u t ( r ) ; datagramChannel . send ( bb , s a ) ; } catch ( IOException e ) { System . e r r . p r i n t l n ( S e r v e r c o m u n i c a t i o n e r r o r : + e . getMessage ( ) ) ; } } } }
package s e r v e r ; import j a v a . n i o . c h a n n e l s . DatagramChannel ; import s e r v e r . impl . MyMServer ; import i s e r v e r . IMyMServer ; public c l a s s AppServer { public s t a t i c void main ( S t r i n g [ ] a r g s ) { i n t p o r t =7999; i f ( a r g s . l e n g t h > 0) p o r t=I n t e g e r . p a r s e I n t ( a r g s [ 0 ] ) ; IMyMServer myMServer=new MyMServer ( ) ; DatagramChannel datagramChannel = myMServer . getDatagramChannel ( p o r t ) ; myMServer . myAction ( datagramChannel ) ; } }
57
Aplicat ia client
1 2 3 4 5 6 7 8 9 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
package c l i e n t ; import j a v a . n e t . UnknownHostException ; import j a v a . n e t . I n e t S o c k e t A d d r e s s ; import j a v a . n e t . I n e t A d d r e s s ; import j a v a . n e t . DatagramSocket ; import j a v a . n i o . c h a n n e l s . DatagramChannel ; import j a v a . n i o . B y t e B u f f e r ; import j a v a . u t i l . S c a n n e r ; import j a v a . i o . IOException ; public c l a s s CmmdcClient { public s t a t i c void main ( S t r i n g [ ] a r g s ) throws IOException { S t r i n g s e r v e r H o s t= l o c a l h o s t ; i n t p o r t =7999; i f ( a r g s . l e n g t h > 0) s e r v e r H o s t=a r g s [ 0 ] ; i f ( a r g s . l e n g t h > 1) p o r t=I n t e g e r . p a r s e I n t ( a r g s [ 1 ] ) ; I n e t S o c k e t A d d r e s s s e r v e r=null , i s a=n u l l ; try { s e r v e r= new I n e t S o c k e t A d d r e s s ( I n e t A d d r e s s . getByName ( s e r v e r H o s t ) , p o r t ) ; } catch ( UnknownHostException e ) { System . out . p r i n t l n ( Unknown h o s t : +e . g e t M e s s a g e ( ) ) ; System . e x i t ( 1 ) ; } i s a=new I n e t S o c k e t A d d r e s s ( 0 ) ; DatagramChannel dc=n u l l ; try { dc=DatagramChannel . open ( ) ; DatagramSocket s o c k e t = dc . s o c k e t ( ) ; s o c k e t . bind ( i s a ) ; } catch ( IOException e ) { System . e r r . p r i n t l n ( Couldn t open t h e DatagramChannel + e . getMessage ( ) ) ; System . e x i t ( 1 ) ; } long m, n , r ; S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ; System . out . p r i n t l n ( m = ) ; m =s c a n n e r . nextLong ( ) ; System . out . p r i n t l n ( n= ) ; n=s c a n n e r . nextLong ( ) ; B y t e B u f f e r bb=B y t e B u f f e r . a l l o c a t e ( 1 6 ) ; // V a r i a n t a 1 bb . putLong ( 0 ,m) . putLong ( 8 , n ) ; // V a r i a n t a 2 // L o n g B u f f e r l b=bb . a s L o n g B u f f e r ( ) ; // l b . p u t ( 0 ,m) . p u t ( 1 , n ) ; try { dc . send ( bb , s e r v e r ) ; bb . c l e a r ( ) ; dc . r e c e i v e ( bb ) ; // V a r i a n t a 1 r=bb . getLong ( 0 ) ; // V a r i a n t a 2
58
59 60 61 62 63 64 65 66 67 68 69
2.5
Recept ie cu Selector
Programarea recept iei cererilor client ilor f ar a utilizarea relor de execut ie se poate face utiliz and clasele java.nio.channel.Selector Gestioneaz a obiectele SocketChannel nregistrate si transmite cererile care trebuie satisf acute. java.nio.channel.SelectionKey Obiect utilizat de selector pentru sortarea cererilor. O cheie identic a un client si tipul cererii. Figura 2.1 prezint a structura unei aplicat ii.
1
Clasa java.nio.channel.Selector Metode public static Selector open() throws IOException Instat iaz a un obiect de tip Selector. public Set<SelectionKey> selectedKeys() Returneaz a cheile inregistrate de selector. public int select() throws IOException Metod a blocant a p an a la selectarea unui canal.
Imaginea este preluat a din Naccarato G., http://www.onjava.com, 2002.
1
59
Figure 2.1: Structura unei aplicat ii. Inregistrarea selectorului se face de c atre obiectiul SocketChannel sau ServerSocketChannel prin metoda public final SelectionKey register(Selector selector, int ops ) throws ClosedChannelException Operat iile pot SelectionKey.OP CONNECT SelectionKey.OP ACCEPT SelectionKey.OP READ SelectionKey.OP WRITE Canalul se congureaz a pe modul ne-blocant prin configureBlocking(false) throws IOException Clasa java.nio.channel.SelectionKey Metode public final boolean isConnectable() public final boolean isReadable() public final boolean isWritable() public final boolean isAcceptable() public void cancel()
60
Exemplul 2.5.1 Aplicat ia server pentru aplicat ia de calcul a celui mai mare divizor comun. Aplicat ia server va format a de clasele AppServer si App, cea utilizat a n acest capitol.
1 2 3 4 5 6 7 8 9 10 11 13 14 15 16 17 19 20 21 22 23 24 25 26 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
package s e r v e r ; import j a v a . n i o . c h a n n e l s . S e r v e r S o c k e t C h a n n e l ; import j a v a . n i o . c h a n n e l s . S o c k e t C h a n n e l ; import j a v a . n i o . c h a n n e l s . S e l e c t i o n K e y ; import j a v a . n i o . c h a n n e l s . S e l e c t o r ; import j a v a . n e t . I n e t S o c k e t A d d r e s s ; import j a v a . n e t . S e r v e r S o c k e t ; import j a v a . n i o . B y t e B u f f e r ; import j a v a . u t i l . I t e r a t o r ; import j a v a . u t i l . S e t ; import j a v a . i o . IOException ; public c l a s s AppServer { public s t a t i c void main ( S t r i n g [ ] a r g s ) { i n t p o r t =7999; i f ( a r g s . l e n g t h > 0) p o r t=I n t e g e r . p a r s e I n t ( a r g s [ 0 ] ) ; S e r v e r S o c k e t C h a n n e l s e r v e r S o c k e t C h a n n e l=n u l l ; try { s e r v e r S o c k e t C h a n n e l = S e r v e r S o c k e t C h a n n e l . open ( ) ; I n e t S o c k e t A d d r e s s i s a=new I n e t S o c k e t A d d r e s s ( p o r t ) ; S e r v e r S o c k e t s s=s e r v e r S o c k e t C h a n n e l . s o c k e t ( ) ; s s . bind ( i s a ) ; serverSocketChannel . configureBlocking ( false ) ; System . out . p r i n t l n ( S e r v e r r e a d y . . . ) ; S e l e c t o r s e l e c t o r = S e l e c t o r . open ( ) ; SelectionKey serverkey = s e r v e r S o c k e t C h a n n e l . r e g i s t e r ( s e l e c t o r , S e l e c t i o n K e y .OP ACCEPT ) ; ByteBuffer b u f f e r = ByteBuffer . a l l o c a t e ( 1 6 ) ; while ( true ) { selector . select (); Set < S e l e c t i o n K e y > k e y s = s e l e c t o r . s e l e c t e d K e y s ( ) ; f o r ( I t e r a t o r i = k e y s . i t e r a t o r ( ) ; i . hasNext ( ) ; ) { S e l e c t i o n K e y key = ( S e l e c t i o n K e y ) i . n e x t ( ) ; i . remove ( ) ; i f ( key == s e r v e r k e y ) { i f ( key . i s A c c e p t a b l e ( ) ) { SocketChannel c l i e n t = serverSocketChannel . accept ( ) ; c l i e n t . configureBlocking ( false ) ; SelectionKey clientkey = c l i e n t . r e g i s t e r ( selector , S e l e c t i o n K e y .OP READ ) ; } } else { i f ( key . i s R e a d a b l e ( ) ) { S o c k e t C h a n n e l c l i e n t = ( S o c k e t C h a n n e l ) key . c h a n n e l ( ) ; int bytesread = c l i e n t . read ( b u f f e r ) ; long m =b u f f e r . getLong ( 0 ) ; long n=b u f f e r . getLong ( 8 ) ; App app=new App ( ) ;
61
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
long r=app . cmmdc(m, n ) ; buffer . clear (); b u f f e r . putLong ( 0 , r ) ; c l i e n t . write ( buffer ) ; buffer . clear (); client . close (); key . c a n c e l ( ) ; } } } } } catch ( E x c e p t i o n e ) { System . e r r . p r i n t l n ( B u f f e r O p E x c e p t i o n : +e . g e t M e s s a g e ( ) ) ; } } }
2.6
Utilizarea canalelor asincrone, introduse n Java 7, face apel la metode neblocante. Astfel sunt introduse clasele: java.nio.channels.AsynchronousServerSocketChannel si java.nio.channels.AsynchronousSocketChannel. Tehnicile de programare utilizate se bazeaz a pe utilizarea claselor: java.util.concurrent.Future
Interfat a Future<V>
Metode V get() boolean isDone() Valoarea true rezult a dac a s-a obt inut / generat obiectul de tip V. Un obiect de tip V care rezult a n urma apel arii metodei cu semn atura Future<V> metoda(. . . ) se va utiliza doar dup a vericarea gener arii ei, de exemplu cu metoda isDone().
62
Clasa AsynchronousServerSocketChannel
Un obiect de tip AsynchronousServerSocketChannel se obt ine cu metoda static a open(). Metode static AsynchronousServerSocketChannel open() throws IOException AsynchronousServerSocketChannel bind(SocketAddress addr ) Se precizeaz a portul la care se leag a canalul asincron. Clasa InetSocketAddress este extinde clasa SocketAddress. public Future<AsynchronousSocketChannel> accept() Metoda neblocant a genereaz a un soclu prin care se realizeaz a conexiunea din partea serverului cu un client.
Clasa AsynchronousSocketChannel
Metodei public static AsynchronousSocketChannel open() throws IOException public abstract Future<Void> connect(SocketAddress remote ) public Future<Integer> read(ByteBuffer dst ) Metoda returneaz a num arul octet ilor nc arcat i n dst. public Future<Integer> write(ByteBuffer src ) Metoda returneaz a num arul octet ilor expediat i din src. Exemplul 2.6.1 Utiliz am modelul aplicat iei dezvoltat a pe baza clasei ServerSocketChannel: 1. IMyMServer.java
1 2 3 4 5 6 7 8
package i s e r v e r ; import j a v a . n i o . c h a n n e l s . A s y n c h r o n o u s S e r v e r S o c k e t C h a n n e l ; public i n t e r f a c e IMyMServer { public A s y n c h r o n o u s S e r v e r S o c k e t C h a n n e l getAsynchronousServerSocketChannel ( int port ) ; public void myAction ( A s y n c h r o n o u s S e r v e r S o c k e t C h a n n e l asynchronousServerSocketChannel ) ; }
63
2. MyMServer.java
1 2 3 4 5 6 7 8 9 10 12 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
package s e r v e r . impl ; import s e r v e r . AppThread ; import i s e r v e r . IMyMServer ; import j a v a . n e t . I n e t S o c k e t A d d r e s s ; import j a v a . n i o . c h a n n e l s . A s y n c h r o n o u s S e r v e r S o c k e t C h a n n e l ; import j a v a . n i o . c h a n n e l s . AsynchronousSocketChannel ; import j a v a . u t i l . c o n c u r r e n t . E x e c u t o r S e r v i c e ; import j a v a . u t i l . c o n c u r r e n t . E x e c u t o r s ; import j a v a . i o . IOException ; import j a v a . u t i l . c o n c u r r e n t . Future ; public c l a s s MyMServer implements IMyMServer { public A s y n c h r o n o u s S e r v e r S o c k e t C h a n n e l getAsynchronousServerSocketChannel ( int port ){ A s y n c h r o n o u s S e r v e r S o c k e t C h a n n e l a s y n c h r o n o u s S e r v e r S o c k e t C h a n n e l=n u l l ; try { asynchronousServerSocketChannel = A s y n c h r o n o u s S e r v e r S o c k e t C h a n n e l . open ( ) ; I n e t S o c k e t A d d r e s s i s a=new I n e t S o c k e t A d d r e s s ( p o r t ) ; a s y n c h r o n o u s S e r v e r S o c k e t C h a n n e l . bind ( i s a ) ; } catch ( IOException e ) { System . out . p r i n t l n ( A s y n c h r o n o u s S e r v e r S o c k e t C h a n n e l E r r o r : + e . getMessage ( ) ) ; System . e x i t ( 0 ) ; } System . out . p r i n t l n ( S e r v e r r e a d y . . . ) ; return a s y n c h r o n o u s S e r v e r S o c k e t C h a n n e l ; } public void myAction ( A s y n c h r o n o u s S e r v e r S o c k e t C h a n n e l asynchronousServerSocketChannel ){ i n t NTHREADS=100; E x e c u t o r S e r v i c e e x e c=E x e c u t o r s . newFixedThreadPool (NTHREADS) ; while ( true ) { try { Future <AsynchronousSocketChannel > f u t u r e = asynchronousServerSocketChannel . accept ( ) ; while ( ! f u t u r e . i s D o n e ( ) ) ; AppThread o b j=new AppThread ( f u t u r e . g e t ( ) ) ; exec . execute ( obj ) ; } catch ( E x c e p t i o n e ) { System . e r r . p r i n t l n ( MyActionException : +e . g e t M e s s a g e ( ) ) ; } } } }
3. AppThread.java
1 2 3 4
64
6 7 9 10 11 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
public c l a s s AppThread extends Thread { private AsynchronousSocketChannel a s c=n u l l ; public AppThread ( AsynchronousSocketChannel a s c ) { t h i s . a s c=a s c ; } public void run ( ) { try { B y t e B u f f e r bb = B y t e B u f f e r . a l l o c a t e ( 1 6 ) ; Future < I n t e g e r > f r=a s c . r e a d ( bb ) ; while ( ! f r . i s D o n e ( ) ) ; long m =bb . getLong ( 0 ) ; long n=bb . getLong ( 8 ) ; App app=new App ( ) ; System . out . p r i n t l n (m + <> +n ) ; long r=app . cmmdc(m, n ) ; bb . c l e a r ( ) ; bb . putLong ( 0 , r ) ; Future < I n t e g e r > fw=a s c . w r i t e ( bb ) ; while ( ! fw . i s D o n e ( ) ) ; asc . c l o s e ( ) ; } catch ( E x c e p t i o n e ) { System . e r r . p r i n t l n ( S e r v e r c o m u n i c a t i o n e r r o r : +e . g e t M e s s a g e ( ) ) ; } } }
4. AppServer.java
1 2 3 4 6 7 8 9 10 11 12 13 14 15 16
package s e r v e r ; import j a v a . n i o . c h a n n e l s . A s y n c h r o n o u s S e r v e r S o c k e t C h a n n e l ; import s e r v e r . impl . MyMServer ; import i s e r v e r . IMyMServer ; public c l a s s AppServer { public s t a t i c void main ( S t r i n g [ ] a r g s ) { i n t p o r t =7999; i f ( a r g s . l e n g t h > 0) p o r t=I n t e g e r . p a r s e I n t ( a r g s [ 0 ] ) ; IMyMServer myMServer=new MyMServer ( ) ; AsynchronousServerSocketChannel asynchronousServerSocketChannel = myMServer . g e t A s y n c h r o n o u s S e r v e r S o c k e t C h a n n e l ( p o r t ) ; myMServer . myAction ( a s y n c h r o n o u s S e r v e r S o c k e t C h a n n e l ) ; } }
5. CmmdcClient.java
1 2 3 4 5 6 7
package c l i e n t ; import j a v a . n e t . UnknownHostException ; import j a v a . n e t . I n e t S o c k e t A d d r e s s ; import j a v a . n i o . c h a n n e l s . AsynchronousSocketChannel ; import j a v a . n i o . B y t e B u f f e r ; import j a v a . u t i l . S c a n n e r ; import j a v a . i o . IOException ;
65
8 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 34 35 36 37 38 39 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
import j a v a . u t i l . c o n c u r r e n t . Future ; public c l a s s CmmdcClient { public s t a t i c void main ( S t r i n g [ ] a r g s ) { S t r i n g h o s t= l o c a l h o s t ; i n t p o r t =7999; i f ( a r g s . l e n g t h > 0) h o s t=a r g s [ 0 ] ; i f ( a r g s . l e n g t h > 1) p o r t=I n t e g e r . p a r s e I n t ( a r g s [ 1 ] ) ; AsynchronousSocketChannel a s c=n u l l ; try { I n e t S o c k e t A d d r e s s i s a=new I n e t S o c k e t A d d r e s s ( hos t , p o r t ) ; a s c=AsynchronousSocketChannel . open ( ) ; asc . connect ( i s a ) ; } catch ( UnknownHostException e ) { System . e r r . p r i n t l n ( S e r v e r n e c u n o s c u t : +h o s t+ +e . g e t M e s s a g e ( ) ) ; System . e x i t ( 1 ) ; } catch ( IOException e ) { System . e r r . p r i n t l n ( C o n e c t a r e i m p o s i b i l a l a : + h o s t+ pe p o r t u l +p o r t+ +e . g e t M e s s a g e ( ) ) ; System . e x i t ( 1 ) ; } S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ; long m, n , r ; System . out . p r i n t l n ( m = ) ; m =s c a n n e r . nextLong ( ) ; System . out . p r i n t l n ( n= ) ; n=s c a n n e r . nextLong ( ) ; B y t e B u f f e r bb=B y t e B u f f e r . a l l o c a t e ( 1 6 ) ; bb . putLong ( 0 ,m) . putLong ( 8 , n ) ; try { Future < I n t e g e r > fw=a s c . w r i t e ( bb ) ; while ( ! fw . i s D o n e ( ) ) ; bb . c l e a r ( ) ; Future < I n t e g e r > f r=a s c . r e a d ( bb ) ; while ( ! f r . i s D o n e ( ) ) ; r=bb . getLong ( 0 ) ; System . out . p r i n t l n ( Cmmdc : +r ) ; asc . c l o s e ( ) ; } catch ( E x c e p t i o n e ) { System . e r r . p r i n t l n ( E r o a r e de c o m u n i c a t i e +e . g e t M e s s a g e ( ) ) ; } } }
66
2. Precizat i clasele Java necesare unei aplicat ii client-server cu socluri (socket). 3. Precizat i diferent a de simetrie privind instant ierea dintre un obiect de tip Socket si unul de tip ServerSocket. 4. Care este rolul unui obiect de tip ServerSocket si cum se utilizeaz a? 5. Precizat i metodele unui obiect Socket, necesare n transmiterea si recept ia datelor. 6. Precizat i termenul multicast. 7. In ce const a participarea serverului la transmisie multicast ? 8. In ce const a participarea unui client la recept ia multicast ? 9. Precizat i termenul broadcast. 10. In ce const a participarea serverului la transmisie broadcast ? 11. In ce const a participarea unui client la recept ia broadcast ? 12. Care este rolul unui obiect de tip DatagramPacket ? 13. Precizati metodele clasei DatagramSocket utilizate la expedierea si la recept ia unui datagram. 14. Ce parametri caracterizeaz a un obiect de tip Buffer ? 15. Ce asem anare exist a ntre comunicat ia bazat a de datagrame si cea prin intermediul canalelor ?
3.1
Java Naming and Directory Interface - JNDI este o interfat a de programare (Application Programming Interface - API ) care descrie funct ionalitatea unui serviciu de nume. Cuv antul servici este utilizat n sens comun, entitate care pune la dispozit ie facilit a ti de folosire. Al aturi de interfat a JNDI, arhitectura JNDI mai cont ine interfat a Service Provider Interface - SPI. Implementarea interfet ei SPI de un furnizor de servicii JNDI are ca efect independent a programului Java de furnizorul de servicii JNDI. 67
68
JNDI este implementat de serviciile de nume: Filesystem are ca obiect asocierea dintre numele de sier sau catalog cu obiectul corespunz ator. DNS - Domain Name System are ca obiect asocierea dintre adresa Internet cu adresa IP. RMI registry utilizat n aplicat ii RMI, din Java. Are ca obiect asocierea ntre un nume de serviciu de invocare ale obiectelor la distant a cu un delegat al serviciului (stub). COS - Common Object Service Naming utilizat n aplicat ii CORBA. Are ca obiect asocierea ntre numele unui serviciu de invocare ale obiectelor la distant a cu referint a la serviciu. LDAP - Lightweight Directory Access Protocol dene ste un protocol pentru accesarea datelor ret inute ntr-un catalog LDAP (LDAP directory, information directory ). Un catalog LDAP permite ret inerea si reg asirea referint elor obiectelor denite pe un calculator.
Interfat a javax.naming.Context
Printr-un context se va nt elege o mult ime de asocieri nume - obiect. Corespunz ator unui context, JNDI dene ste interfat a Context, cu metodele void bind(String nume ,Object object ) void rebind(String nume ,Object object ) void unbind(String nume ) Object lookup(String nume ) NamingEnumeration list(String nume ) Returneaz a lista cu nume obiectelor mpreuna cu tipul lor. NamingEnumeration listBindings(String nume ) Returneaz a lista cu nume obiectelor mpreuna cu tipul si locat ia acestora. Specicat iile JNDI prev ad denirea unui context init ial, implementat prin clasa javax.naming.InitialContext, clas a ce implementeaz a interfat a Context. Constructori.
69
public InitialContext() throws NamingException public void InitialContext(Hashtable<?,?> environment )throws NamingException Pentru crearea contextului init ial trebuie specicat a clasa care creaz a contextul init ial prin parametrul java.naming.factory.initial sau constanta Context.INITIAL CONTEXT FACTORY. Acest parametru se poate da n mai multe moduri: Includerea n obiectul Hashtable care apare n constructorul clasei 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 sierul de propriet a ti jndi.properties. In aceste ultime dou a cazuri, contextul initial se creaz a prin Context ctx=new InitialContext();
70
Funct ie de serviciul de nume, clasa care creaz a contextul init ial este dat n tabelul Serviciul de nume Filesystem COS RMI DNS LDAP Clasa com.sun.jndi.fscontext.RefFSContextFactory com.sun.jndi.cosnaming.CNCtxFactory com.sun.jndi.rmi.registry.RegistryContextFactory com.sun.jndi.dns.DnsContextFactory com.sun.jndi.ldap.LdapCtxFactory
Exemplul 3.1.1 Utiliz and serviciul JNDI Filesystem se creaz a un context prin intermediul c areia se a seaz a cont inutul unui catalog indicat de client.
1 2 3 4 5 6 7 8 9 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 38 39 40
j a v a x . naming . Context ; j a v a x . naming . I n i t i a l C o n t e x t ; j a v a x . naming . B i n d i n g ; j a v a x . naming . NamingEnumeration ; j a v a x . naming . NamingException ; j a v a x . naming . NameClassPair ; java . io . F i l e ; java . u t i l . Hashtable ; java . u t i l . Scanner ;
c l a s s Lookup { public s t a t i c void main ( S t r i n g [ ] a r g s ) { Context c t x=n u l l ; / // V a r i a n t a 1 H a s h t a b l e env = new H a s h t a b l e ( 1 1 ) ; env . p u t ( C o n t e x t . INITIAL CONTEXT FACTORY, com . sun . j n d i . f s c o n t e x t . RefFSContextFactory ) ; try { c t x = new I n i t i a l C o n t e x t ( env ) ; } c a t c h ( NamingException e ) { System . o u t . p r i n t l n ( I n i t i a l C o n t e x t E r r o r : +e . g e t M e s s a g e ( ) ) ; } / / // V a r i a n t a 2 System . s e t P r o p e r t y ( j a v a . naming . f a c t o r y . i n i t i a l , com . sun . j n d i . f s c o n t e x t . RefFSContextFactory ) ; try { c t x = new I n i t i a l C o n t e x t ( ) ; } c a t c h ( NamingException e ) { System . o u t . p r i n t l n ( I n i t i a l C o n t e x t E r r o r : +e . g e t M e s s a g e ( ) ) ; } / // V a r i a n t a 3 try { c t x = new I n i t i a l C o n t e x t ( ) ;
71
41 42 43 44 46 47 48 49 50 51 53 54 55 56 57 58 60 61 62 63 64 65 66 67 68 69 70 71 72
} catch ( NamingException e ) { System . out . p r i n t l n ( I n i t i a l C o n t e x t E r r o r : +e . g e t M e s s a g e ( ) ) ; } S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ; System . out . p r i n t l n ( I n t r o d u c e t i r e f e r i n t a a b s o l u t a a unui c a t a l o g : ) ; S t r i n g myName=s c a n n e r . n e x t ( ) ; try { System . out . p r i n t l n ( \ n c t x . l o o k u p ( +myName+ ) p r o d u c e ) ; System . out . p r i n t l n ( c t x . l o o k u p (myName ) ) ; System . out . p r i n t l n ( \ n C o n t i n u t u l c a t a l o g u l u i +myName+ e s t e : \ n ) ; NamingEnumeration l s t =c t x . l i s t (myName ) ; while ( l s t . hasMore ( ) ) { NameClassPair nc = ( NameClassPair ) l s t . n e x t ( ) ; System . out . p r i n t l n ( nc ) ; } System . out . p r i n t l n ( \ n C o n t i n u t u l c a t a l o g u l u i +myName+ e s t e : \ n ) ; NamingEnumeration l s t 1 = c t x . l i s t B i n d i n g s (myName ) ; while ( l s t 1 . hasMore ( ) ) { B i n d i n g bd = ( B i n d i n g ) l s t 1 . n e x t ( ) ; System . out . p r i n t l n ( bd ) ; } ctx . c l o s e ( ) ; } catch ( NamingException e ) { System . out . p r i n t l n ( Lookup f a i l e d : + e . g e t M e s s a g e ( ) ) ; } } }
sau
java Lookup
caz, n care, n catalogul curent se g ase ste sierul jndi.properties cu cont inutul
java.naming.factory.initial=com.sun.jndi.fscontext.RefFSContextFactory
3.1.1
LDAP
LDAP poate privit ca un sistem de gestiune a unei baze de date (ne relat ional). Baza de date este alc atuit a din atribute ale c aror nume este precizat de protocolul LDAP. Punctele de intrare (r ad acinile) sunt date de DN (Distinguished Name ). Uzual DN se dene ste printr-una din variantele
72
1. o=organization ,c=country 2. o=organization 3. dc=domain content 1 ,dc=domain content 2 De exemplu, dc=example,dc=com 4. uid=user id ,ou=organization unit De exemplu, uid=admin,ou=system Un utilizator este caracterizat prin atributul cn - common name si are acces la LDAP prin precizarea simultan a a atributelor DN si cn. Implement ari gratuite LDAP sunt: OpenDS (Open Directory Service ); ApacheDS (Apache Directory Service ). Apache Directory Studio incorporeaz a si ofer a interfat a grac a de administrare pentru ApacheDS. Vom utiliza produsul OpenDS. Instalarea const a din: 1. dezarhivarea distribut iei; 2. se completeaz a sursa sierului OpenDS-*\setup.bat cu set OPENDS JAVA HOME=... ca prima linie; 3. se execut a OpenDS-*\setup.bat. Prin intermediul unei interfet e grace se xeaz a o parola pentru cn=Directory Manager. Fie 1q2w3e aceast a parol a. un punct de intrare, e acesta DN: dc=example,dc=com. Implicit, serverul OpenDS utilizeaz a portul 389. Operat iile de congurare se fac utiliz and interfat a grac a a componentei OpenDS Directory Server Control Panel, lansat prin
set OPENDS_JAVA_HOME=. . . set OpenDS_HOME=. . .\OpenDS-* %OpenDS_HOME%\bat\control-panel.bat
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 urmat de clic-dreapta pe DN si Reset User Password. Prin aceast a component a se poate porni si opri serverul OpenDS, ambele operat ii put and executate si apel and start-ds, stop-ds din catalogul OpenDS HOME\bat. Act iunile care pot ntreprinse de un client care interact ioneaz a cu serverul constau n autenticare: datele necesare sunt DN si parola; conectare (bind) / deconectare (unbind) la un punct de intrare. Conectarea implic a crearea unui punct de intrare precizat prin cn; c autarea / localizarea (lookup) unui punct de intrare precizat prin cn. Exemplul 3.1.2 Program pentru nregistrarea si stergerea referint ei unui obiect de tip Cmmdc.
1 2 3 4 5 6 8 9 10 11 12 13 14 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
java . u t i l . Hashtable ; java . u t i l . Scanner ; j a v a x . naming . Context ; j a v a x . naming . NamingException ; j a v a x . naming . d i r e c t o r y . D i r C o n t e x t ; j a v a x . naming . d i r e c t o r y . I n i t i a l D i r C o n t e x t ;
public c l a s s LDAPServerCmmdc { public s t a t i c void main ( S t r i n g [ ] a r g s ) { S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ; System . out . p r i n t l n ( A l e g e t i f u r n i z o r u l LDAP: ) ; System . out . p r i n t l n ( 1 : OpenDS ) ; System . out . p r i n t l n ( 2 : Apache D i r e c t o r y S e r v i c e ) ; i n t p r o v i d e r=s c a n n e r . n e x t I n t ( ) ; H a s h t a b l e env = new H a s h t a b l e ( ) ; env . put ( Context . INITIAL CONTEXT FACTORY, com . sun . j n d i . l d a p . LdapCtxFactory ) ; i f ( p r o v i d e r ==1){ env . put ( Context . PROVIDER URL, l d a p : / / l o c a l h o s t : 3 8 9 / dc=example , dc=com ) ; env . put ( Context . SECURITY PRINCIPAL , cn=D i r e c t o r y Manager ) ; env . put ( Context . SECURITY CREDENTIALS, 1 q2w3e ) ; } else { env . put ( Context . PROVIDER URL, l d a p : / / l o c a l h o s t : 1 0 3 8 9 / u i d=admin , ou=system ) ; env . put ( Context . SECURITY PRINCIPAL , u i d=admin , ou=system ) ; env . put ( Context . SECURITY CREDENTIALS, s e c r e t ) ; } DirContext ctx = null ;
74
32 33 34 35 36 37 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
System . out . p r i n t l n ( A l e g e t i o p e r a t i a : 1 bind ; 2 unbind ) ; i n t o p e r=s c a n n e r . n e x t I n t ( ) ; System . out . p r i n t l n ( I n t r o d u c e t i v a l o a r e a a t r i b u t u l u i \ cn \ + + a o b i e c t u l u i Cmmdc ) ; System . out . p r i n t l n ( cn= ) ; S t r i n g cmmdcObj=s c a n n e r . n e x t ( ) . t r i m ( ) ; try { c t x = new I n i t i a l D i r C o n t e x t ( env ) ; i f ( o p e r ==1){ Cmmdc o b j=new Cmmdc ( ) ; S t r i n g s t r= cn=+cmmdcObj ; c t x . bind ( s t r , o b j ) ; } else { c t x . unbind ( cn=+cmmdcObj ) ; } ctx . c l o s e ( ) ; } catch ( NamingException e ) { System . out . p r i n t l n ( LDAPserverCmmdc : } } }
+e . g e t M e s s a g e ( ) ) ;
public c l a s s Cmmdc implements j a v a . i o . S e r i a l i z a b l e { public long cmmdc( long a , long b ) { while ( b != 0 ) { long r = a % b ; a = b; b = r; } return a ; } }
Exemplul 3.1.3 Utilizarea unui obiect de tip Cmmdc reg asit pe baza referintei din serverul LDAP.
1 2 3 4 5 6 8 9 10 11 12 13 14 15
java . u t i l . Hashtable ; j a v a x . naming . Context ; j a v a x . naming . NamingException ; j a v a x . naming . d i r e c t o r y . D i r C o n t e x t ; j a v a x . naming . d i r e c t o r y . I n i t i a l D i r C o n t e x t ; java . u t i l . Scanner ;
public c l a s s LDAPClientCmmdc { public s t a t i c void main ( S t r i n g [ ] a r g s ) { S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ; System . out . p r i n t l n ( A l e g e t i f u r n i z o r u l LDAP: ) ; System . out . p r i n t l n ( 1 : OpenDS ) ; System . out . p r i n t l n ( 2 : Apache D i r e c t o r y S e r v i c e ) ; i n t p r o v i d e r=s c a n n e r . n e x t I n t ( ) ; H a s h t a b l e env = new H a s h t a b l e ( ) ;
75
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
env . put ( Context . INITIAL CONTEXT FACTORY, com . sun . j n d i . l d a p . LdapCtxFactory ) ; i f ( p r o v i d e r ==1){ env . put ( Context . PROVIDER URL, l d a p : / / l o c a l h o s t : 3 8 9 / dc=example , dc=com ) ; env . put ( Context . SECURITY PRINCIPAL , cn=D i r e c t o r y Manager ) ; env . put ( Context . SECURITY CREDENTIALS, 1 q2w3e ) ; } else { env . put ( Context . PROVIDER URL, l d a p : / / l o c a l h o s t : 1 0 3 8 9 / u i d=admin , ou=system ) ; env . put ( Context . SECURITY PRINCIPAL , u i d=admin , ou=system ) ; env . put ( Context . SECURITY CREDENTIALS, s e c r e t ) ; } DirContext ctx = null ; try { c t x=new I n i t i a l D i r C o n t e x t ( env ) ; i f ( c t x != n u l l ) { System . out . p r i n t l n ( I n t r o d u c e t i v a l o a r e a a t r i b u t u l u i \ cn \ + a o b i e c t u l u i Cmmdc ) ; System . out . p r i n t l n ( cn= ) ; S t r i n g cmmdcObj=s c a n n e r . n e x t ( ) . t r i m ( ) ; O b j e c t o b j e c t = c t x . l o o k u p ( cn=+cmmdcObj ) ; System . out . p r i n t l n ( Primul numar ) ; long a=s c a n n e r . n e x t I n t ( ) ; System . out . p r i n t l n ( Al d o i l e a numar ) ; long b=s c a n n e r . n e x t I n t ( ) ; Cmmdc o b j =(Cmmdc) o b j e c t ; System . out . p r i n t l n ( R e z u l t a t u l cmmdc e s t e : +o b j . cmmdc( a , b ) ) ; ctx . c l o s e ( ) ; } } catch ( NamingException e ) { System . out . p r i n t l n ( LDAPClientCmmdc : +e . g e t M e s s a g e ( ) ) ; } } }
76
4.1
Reg asirea obiectelor la distant a. Ideea g asirii unui obiect la distant a este c a serverul nscrie un reprezentant al s au numit stub (ciot) ntr-un obiect registry - registru. Acest obiect se creaz a cu programul rmiregistry.exe din distribut ia java si se lanseaz a n execut ie prin start rmiregistry [port ] unde valoarea implicit a a portului este 1099. Comanda start apart ine sistemului de operare. rmiregistry este un serviciu de nume JNDI. 77
78
Un client obt ine din registry stub-ul serverului, prin intermediul c aruia realizeaz a comunicat ia cu programul server. C and un obiect al clientului apeleaz a o metod a a unui obiect aat la distant a , se va face, de fapt, un apel de metod a a unui obiect care reprezint a serverul. Acesta este stub -ul, aat pe acea si ma sin a cu clientul. Rolul acestui obiect este s a mpacheteze (marshalling) parametrii de apel ai metodei ntr-un mesaj ce va transferat prin ret ea. Impachetarea se face ntr-o manier a independent a de calculator, mai precis sirurile de caractere si obiecte sunt transmise ntr-un format care nu se bazeaz a pe referint e. Pentru obiecte se utilizeaz a serializarea obiectelor Java. Serializarea datelor reprezint a transformarea acestora din tipuri de date diferite ntr-un sir de octet i care va transportat prin ret ea f ar a interpretare, dar care p astreaz a informat iile despre structura init ial a a datelor. Deserializarea este procesul invers de refacere a structurilor trimise prin ret ea. Mesajul asamblat este transmis c atre server, care stie s a desfac a mesajul recept ionat invoc and n mod corespunz ator metoda referit a de client. Atunci c and clientul face apel la o metod a aat a pe o alt a ma sin a, este invocat stub-ul client, care ncepe conversat ia cu serverul. Acest lucru este complet transparent utilizatorului, care are impresia c a invoc a o metod a local a. Metodele apelate la distant a trebuie declarate ca apart in and unei interfet e ce extinde interfat a java.rmi.Remote. Fiecare asemenea metod a trebuie s a arunce o except ie java.rmi.RemoteException. Obiectele care circul a prin ret ea trebuie s a implementeze interfat a java.io.Serializable. Structura unei aplicat ii RMI. O aplicat ie RMI este alc atuit a din trei componente: 1. O interfat a la distant a (remote ) n care se declar a serviciile puse la dispozit ie de server; 2. Aplicat ia server care poate implementa serviciile interfet ei la distant a si nscrie n registry stub-ul corespunz ator; 3. Aplicat ia client ce apeleaz a unul sau mai multe servicii ale serverului. Aplicat ia server trebuie s a aib a acces la clasele interfet ei si a celor care o implementeaz a. Locat ia acestor clase se xeaz a prin atributul de nume java.rmi.server.codebase. Valoarea atributului trebuie indicat printr-unul din protocoalele http, ftp, file. Utiliz and protocoalele http sau ftp arhiva interfet ei si a claselor care o implementeaz a se depun ntr-un server Web (Microsoft Internet Interchange
79
Server (IIS), apache-tomcat, respectiv ntr-un server ftp (apache-ftp ). In momentul lans arii aplicat iei server, serverul http / ftp trebuie s a e activ. Dac a se indic a prin protocolul file calea c atre cataloagele care cont in clasele interfet ei si ale implement arii lor atunci ultimul caracter al c aii este /. Din punctul de vedere al execut iei sunt implicate componentele: Serviciul de nume rmiregistry; Aplicat ia server; Aplicat ia client. Aplicat ia server si rmiregistry trebuie s a ruleze pe acela si calculator. Registrul rmiregistry implementeaz a interfat a java.rmi.registry.Registry1 . Metodele oferite sunt: void bind(String numeServiciu , Remote obj )throws RemoteException, AlreadyBoundException, AccessException Inregistreaz a n registry obiectul obj ce implementeaz a interfat a Remote sub numele numeServiciu. void rebind(String numeServiciu , Remote obj )throws RemoteException, AccessException Re nregistreaz a n registry obiectul obj ce implementeaz a interfat a Remote sub numele numeServiciu. Aceast a metod a poate apelat a doar dac a programul care face nregistrarea se a a pe acea si ma sin a ca registrul registry. String[] list()throws RemoteException, AccessException Returneaz a o list a a tuturor serviciilor nregistrate n registry. Remote lookup(String numeServiciu )throws RemoteException, NotBoundException, AccessException Returneaz a stub-ul serviciului nregistrat sub numele numeServiciu. void unbind(String numeServiciu )throws RemoteException, NotBoundException, AccessException S terge din registru serviciul.
1
80
Localizarea registrului se obt ine utiliz and metoda static a getRegistry a clasei java.rmi.registry.LocateRegistry. public static Registry getRegistry() throws RemoteException public static Registry getRegistry(String host ) throws RemoteException public static Registry getRegistry(int port ) throws RemoteException public static Registry getRegistry(String host ,int port ) throws RemoteException Metoda public static Registry createRegistry(int port ) throws RemoteException creaz a un registru la portul specicat pe calculatorul local. Ansamblul (rmiregistry, port ) determin a n mod univoc o aplicat ie / serviciu. Interfat a Remote serve ste la marcarea interfet elor ale c aror metode urmeaz a a apelate de pe alt a ma sin a virtual a Java. Un obiect de tip java.rmi.server.UnicastRemoteObject mijloce ste transmiterea obiectelor si serve ste la generarea unui stub unui serviciu. Generarea stub-ului unui serviciu se obt ine prin intermediul metodei statice static Remote UnicastRemoteObject.exportObject(Remote obj ,int port ) Inregistrarea stub-ului unui serviciu descris de interfat a IService si implementat de clasa ServiceImpl n registry se face prin ServiceImpl obj=new ServiceImpl(); IService stub=(IService)UnicastRemoteObject.exportObject(obj,0); // Varianta cu apel rmiregistry direct /* Registry registry=LocateRegistry.getRegistry(host,port); registry.bind("MyServiceName",stub); */ // Varianta JNDI String sPort=(new Integer(port)).toString(); System.setProperty(Context.INITIAL_CONTEXT_FACTORY,
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 dore ste s a foloseasc a trebuie s a cunoasc a: calculatorul pe care se g ase ste obiectul registry si portul la care ascult a serviciul; numele sub care serviciul s-a nregistrat n registry; metodele puse la dispozit ie de serviciu.
4.1.1
Exemplic am construirea unei aplicat ii RMI n care serviciul asigurat de server este calculul celui mai mare divizor comun a dou a numere naturale. 2 Pentru exemplele care urmeaz a, presupunem c a textele surs a se ret in n subcataloage ale unui catalog src, la care are acces doar programatorul, iar clasele obt inute prin compilare se depun n subcataloagele unui catalog public\classes, accesibil prin ret ea. Dezvoltarea unei aplicat ii se va face pe un calculator. In acest sens, celor 3 componente li se asociaz a cataloagele \i - pentru interfat a la distant a , \s pentru componenta server si \c - pentru componenta client. Pa si necesari compil arii si desf a sur arii componentelor aplicat iei se vor realiza prin intermediul lui ant. Pentru ecare component a se vor executa succesiv obiectivele: 1. Install - creaz a o structur a de cataloage src si public\classes. 2. Init - creaz a structura de cataloage specic a aplicat iei. 3. Compile - compileaz a programele surs a. Dezvoltarea unei aplicat ii RMI const a din parcurgerea urm atorilor pa si: 1. Denitea interfet ei la distant a .
82
1 2 3 4
package cmmdc ; public i n t e r f a c e ICmmdc extends j a v a . rmi . Remote { long cmmdc( long a , long b ) throws j a v a . rmi . RemoteException ; }
Presupunem ca programatorul interfet ei ret ine textul surs a ICmmdc.java n catalogul \i\src\cmmdc. 2. Compilarea si arhivarea interfet ei se poate realiza sierul ant-build
1 2 3 5 7 8 9 10 11 12 13 14 15 17 18 19 20 21 22 24 25 26 27 28 29 30 31 32
<project name= I n t e r f a c e d e f a u l t= I n s t a l l b a s e d i r= . > <description> I n t e r f a c e a c t i o n s </ description> < ! s e t g l o b a l p r o p e r t i e s f o r t h i s b u i l d > <property name= package v a l u e=cmmdc /> <target name= I n s t a l l > < ! C r e a t e t h e b u i l d d i r e c t o r y s t r u c t u r e used by c o m p i l e > <delete d i r= s r c /> <mkdir d i r= s r c /> <delete d i r= p u b l i c /> <mkdir d i r= p u b l i c /> <delete d i r= p u b l i c / c l a s s e s /> <mkdir d i r= p u b l i c / c l a s s e s /> </ target> <target name= I n i t > < ! C r e a t e t h e time stamp > <tstamp /> <mkdir d i r= s r c /$ { package } /> <mkdir d i r= p u b l i c / c l a s s e s /$ { package } /> </ target> <target name= Compile depends= I n i t description= c o m p i l e t h e s o u r c e > <javac s r c d i r= s r c i n c l u d e s= $ { package } / d e s t d i r= p u b l i c / c l a s s e s i n c l u d e a n t r u n t i m e= f a l s e /> < j a r b a s e d i r= p u b l i c / c l a s s e s d e s t f i l e = p u b l i c / c l a s s e s /$ { package } /$ { package } . j a r i n c l u d e s= $ { package } / . c l a s s /> </ target> </ project>
1 2 3 4 5 6 7 8
package s e r v e r ; import cmmdc . ICmmdc ; import j a v a . rmi . s e r v e r . UnicastRemoteObject ; // V a r i a n t a cu a p e l r m i r e g i s t r y d i r e c t import j a v a . rmi . r e g i s t r y . R e g i s t r y ; import j a v a . rmi . r e g i s t r y . L o c a t e R e g i s t r y ; // V a r i a n t a JNDI import j a v a x . naming . Context ;
83
9 11 13 15 16 17 18 19 20 21 22 24 25 26 27 28 30 31 32 33 34 35 36 38 39 40 41 42 43 44
public long cmmdc( long a , long b ) { . . . } public s t a t i c void main ( S t r i n g a r g s [ ] ) { S t r i n g h o s t= l o c a l h o s t ; i n t p o r t =1099; i f ( a r g s . l e n g t h > 0) p o r t=I n t e g e r . p a r s e I n t ( a r g s [ 0 ] ) ; try { CmmdcImpl o b j=new CmmdcImpl ( ) ; ICmmdc s t u b =(ICmmdc) UnicastRemoteObject . e x p o r t O b j e c t ( obj , 0 ) ; // V a r i a n t a d i r e c t a / R e g i s t r y r e g i s t r y=L o c a t e R e g i s t r y . g e t R e g i s t r y ( h o s t , p o r t ) ; r e g i s t r y . b i n d ( CmmdcServer , s t u b ) ; / // V a r i a n t a JNDI S t r i n g s P o r t =(new I n t e g e r ( p o r t ) ) . t o S t r i n g ( ) ; System . s e t P r o p e r t y ( Context . INITIAL CONTEXT FACTORY, com . sun . j n d i . rmi . r e g i s t r y . R e g i s t r y C o n t e x t F a c t o r y ) ; System . s e t P r o p e r t y ( Context . PROVIDER URL, rmi : / / +h o s t+ : +s P o r t ) ; Context c t x=new I n i t i a l C o n t e x t ( ) ; c t x . bind ( CmmdcServer , s t u b ) ; System . out . p r i n t l n ( CmmdcServer r e a d y ) ; } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( CmmdcImpl e r r : + e . g e t M e s s a g e ( ) ) ; } } }
Textul surs a al programului server CmmdcImpl.java se ret ine n catalogul \s\src\server 4. (a) Compilarea programului server; (b) Crearea obiectului registry ; (c) Lansarea serverului n lucru se obt in cu ant cu
1 2 4 6 7 8 9 10
<project name= S e r v e r d e f a u l t= I n s t a l l b a s e d i r= . > <description> S e r v e r a c t i o n s </ description> <property name= path l oc a t io n= . . . /> <property name= package v a l u e= s e r v e r /> <property name= i n t e r f a c e j a r l oc a t io n= $ { path } / i / p u b l i c / c l a s s e s /cmmdc /> <property name= j a r f i l e v a l u e=cmmdc . j a r /> <property name= s e r v i c e c l a s s v a l u e=CmmdcImpl
/>
84
11 12 14 15 16 17 18 19 20 21 22 23 24 26 27 28 29 30 32 33 34 35 36 37 38 39 41 42 43 44 45 47 48 49 50 51 52 54 55 56 58 59 61 62 63 64 65 66 67 68 69
<property name= p o r t v a l u e= 1099 /> <property name= h o s t v a l u e= l o c a l h o s t /> <target name= I n s t a l l > < ! C r e a t e t h e time stamp > <tstamp /> < ! C r e a t e t h e b u i l d d i r e c t o r y s t r u c t u r e used by c o m p i l e > <delete d i r= s r c /> <mkdir d i r= s r c /> <delete d i r= p u b l i c /> <mkdir d i r= p u b l i c /> <delete d i r= p u b l i c / c l a s s e s /> <mkdir d i r= p u b l i c / c l a s s e s /> </ target> <target name= I n i t > <mkdir d i r= s r c /$ { package } /> <mkdir d i r= p u b l i c / c l a s s e s /$ { package } /> <copy f i l e = $ { i n t e r f a c e j a r } /$ { j a r f i l e } t o d i r= p u b l i c / c l a s s e s /> </ target> <target name= Compile depends= I n i t description= c o m p i l e t h e s o u r c e > <javac s r c d i r= s r c i n c l u d e s= $ { package } / d e s t d i r= p u b l i c / c l a s s e s classpath= p u b l i c / c l a s s e s /$ { j a r f i l e } i n c l u d e a n t r u n t i m e= f a l s e /> <unjar src= p u b l i c / c l a s s e s /$ { j a r f i l e } d e s t= p u b l i c / c l a s s e s /> </ target> <target name=Rmi> <exec e x e c u t a b l e= r m i r e g i s t r y > <arg v a l u e= $ { p o r t } /> </ exec> </ target> <target name= A r c h i v e > < j a r d e s t f i l e =cmmdc . j a r b a s e d i r= p u b l i c / c l a s s e s > <include name= $ { package } / /> <include name=cmmdc/ /> </ j a r> </ target> <target name= S e r v e r > <java c l a s s n a m e= $ { package } . $ { s e r v i c e c l a s s } classpath= $ { path } / s / p u b l i c / c l a s s e s f o r k= t r u e > <jvmarg v a l u e= Djava . rmi . s e r v e r . c o d e b a s e= f i l e : $ { path } / s / p u b l i c / c l a s s e s / /> < ! <jvmarg v a l u e= Djava . rmi . s e r v e r . c o d e b a s e=h t t p : //$ { h o s t } : 8 0 8 0 / rmi /cmmdc . j a r /> > < ! <jvmarg v a l u e= Djava . rmi . s e r v e r . c o d e b a s e=f t p : //$ { h o s t } : 2 1 2 1 / rmi /cmmdc . j a r /> > <arg l i n e= $ { p o r t } />
85
70 71 72
Obiectivele Rmi si Server se lanseaz a n ferestre dos distincte care r am an active pe durata de viat a a aplicat iei server. Obiectivul Archive creaz a arhiva jar necesar a desf a sur arii interfet ei si a claselor care o implementeaz a ntr-un server http / ftp. A sa cum s-a amintit mai sus, acest a arhiv a este preluat a de aplicat ia server, la lansare, prin atributul java.rmi.server.codebase. Server ftp Utiliz am serverul ftp apache-ftpserver. Instalarea const a din dezarhivarea arhivei desc arcate. Lansarea serverului se obt ine prin
set FTP_SERVER_HOME=. . . set JAVA_HOME=. . . %FTP_SERVER_HOME%\bin\ftpd.bat res/conf/ftpd-typical.xml
Resursele / sierele puse la dispozit ie de serverul ftp sunt puse n catalogul FTP SERVER HOME\res\home. Serverul RMI cu server ftp. Se creaz a arhiva cmmdc.jar cu cont inutul
cmmdc | ICmmdc.class server | CmmdcImpl.class
1 2 3 4 5 6 7 8 9 11
package c l i e n t ; import cmmdc . ICmmdc ; import j a v a . u t i l . S c a n n e r ; // V a r i a n t a cu a p e l r m i r e g i s t r y d i r e c t import j a v a . rmi . r e g i s t r y . R e g i s t r y ; import j a v a . rmi . r e g i s t r y . L o c a t e R e g i s t r y ; ; // V a r i a n t a JNDI import j a v a x . naming . Context ; import j a v a x . naming . I n i t i a l C o n t e x t ; public c l a s s CmmdcClient {
86
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 39 40 41 42 43 44 45 46
public s t a t i c void main ( S t r i n g a r g s [ ] ) { S t r i n g h o s t= l o c a l h o s t ; i n t p o r t =1099; i f ( a r g s . l e n g t h > 0) h o s t=a r g s [ 0 ] ; i f ( a r g s . l e n g t h > 1) p o r t=I n t e g e r . p a r s e I n t ( a r g s [ 1 ] ) ; S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ; System . out . p r i n t l n ( Primul numar : ) ; long m =Long . par se Lo ng ( s c a n n e r . n e x t ( ) ) ; System . out . p r i n t l n ( Al d o i l e a numar : ) ; long n=Long . p ars eL ong ( s c a n n e r . n e x t ( ) ) ; long x =0; try { // V a r i a n t a d i r e c t a / R e g i s t r y r e g i s t r y=L o c a t e R e g i s t r y . g e t R e g i s t r y ( h o s t , p o r t ) ; ICmmdc o b j =(ICmmdc) r e g i s t r y . l o o k u p ( CmmdcServer ) ; / // V a r i a n t a JNDI S t r i n g s P o r t =(new I n t e g e r ( p o r t ) ) . t o S t r i n g ( ) ; System . s e t P r o p e r t y ( Context . INITIAL CONTEXT FACTORY, com . sun . j n d i . rmi . r e g i s t r y . R e g i s t r y C o n t e x t F a c t o r y ) ; System . s e t P r o p e r t y ( Context . PROVIDER URL, rmi : / / +h o s t+ : +s P o r t ) ; Context c t x=new I n i t i a l C o n t e x t ( ) ; ICmmdc o b j =(ICmmdc) c t x . l o o k u p ( CmmdcServer ) ; x=o b j . cmmdc(m, n ) ; System . out . p r i n t l n ( Cmmdc=+x ) ; } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( CmmdcClient e x c e p t i o n : +e . g e t M e s s a g e ( ) ) ; } } }
Sursa programului client CmmdcClient.java apart ine catalogului \c\src\client 6. Compilarea programului client si lansarea acestuia n execut ie.
1 2 4 6 7 8 9 10 11 12 14 15 16 17
<project name= C l i e n t d e f a u l t= I n s t a l l b a s e d i r= . > <description> C l i e n t a c t i o n s </ description> <property name= path l oc a t io n= . . . /> <property name= package v a l u e= c l i e n t /> <property name= i n t e r f a c e j a r l oc a t io n= $ { path } / i / p u b l i c / c l a s s e s /cmmdc /> <property name= j a r f i l e v a l u e=cmmdc . j a r /> <property name= h o s t v a l u e= l o c a l h o s t /> <property name= p o r t v a l u e= 1099 /> <property name= c l i e n t c l a s s v a l u e= CmmdcClient /> <target name= I n s t a l l > < ! C r e a t e t h e b u i l d d i r e c t o r y s t r u c t u r e used by c o m p i l e > <delete d i r= s r c /> <mkdir d i r= s r c />
87
18 19 20 22 23 24 25 26 27 28 30 31 32 33 34 35 37 38 39 40 41 42 43 44 45 46 47
<delete d i r= c l a s s e s /> <mkdir d i r= c l a s s e s /> </ target> <target name= I n i t > < ! C r e a t e t h e time stamp > <tstamp /> <mkdir d i r= s r c /$ { package } /> <mkdir d i r= c l a s s e s /$ { package } /> <copy f i l e = $ { i n t e r f a c e j a r }\ $ { j a r f i l e } t o d i r= c l a s s e s /> </ target> <target name= Compile depends= I n i t description= c o m p i l e t h e s o u r c e > <javac s r c d i r= s r c i n c l u d e s= $ { package } / . j a v a d e s t d i r= c l a s s e s classpath= c l a s s e s \ $ { j a r f i l e } i n c l u d e a n t r u n t i m e= f a l s e /> </ target> <target name=Run depends= Compile description= S t a r t t h r c l i e n t > <java c l a s s n a m e= $ { package } . $ { c l i e n t c l a s s } f o r k= t r u e > <classpath> <pathelement l oc a t io n= c l a s s e s /$ { j a r f i l e } /> <pathelement path= c l a s s e s /> </ classpath> <arg l i n e= $ { h o s t } $ { p o r t } /> </ java> </ target> </ project>
4.1.2
Tipare de programare
Fabrica de obiecte
Tiparul fabrica de obiecte va permite crearea dinamic a a unui server. Prin aceea schem a, se va crea o clas a - fabrica de obiecte - care implementeaz a c ate o metod a get, ce returneaz a o instant a de server. Aceste metode sunt declarate ntr-o interfat a la distant a . Un client, apel and o asemenea metod a, va instant ia serverul dorit si va obt ine stub-ul corespunz ator. In felul acesta se vor putea utiliza o mult ime de aplicat ii distincte prin intermediul unui singur rmiregistry. Fiec arei aplicat ii i corespunde un server, instant iat la apelul clientului de metoda get corespunz atoare. Programarea unui server care poate lansat dinamic trebuie s a satisfac a restrict iile: Clasa serverului extinde clasa UnicastRemoteObject.
88
Exist a un constructor f ar a argumente ce arunc a except ia java.rmi.Remote Exception. Pentru exemplicarea tehnicii de lucru relu am aplicat ia pentru calculul celui mai mare divizor comun a dou a numere naturale, consider and interfat a
1 2 3 4
Aceas a interfat a va implementat a de clasa ServerCmmdc. Metoda compute este o metod a de calcul a celui mai mare divizor comun a dou a numere. Obiecte de tip ServerCmmdc se creaz a, de la distant a prin fabrica de obiecte FabObiecte, o clas a ce implementeaz a interfat a
1 2 3 4
package cmmdc0 ; im po rt j a v a . rmi . RemoteException ; im po rt j a v a . rmi . s e r v e r . UnicastRemoteObject ; p u b l i c c l a s s ServerCmmdc e x t e n d s UnicastRemoteObject implements ICmmdc0 { p u b l i c ServerCmmdc ( ) throws RemoteException {} p u b l i c l o n g compute ( l o n g m, l o n g n ) throws RemoteException { . . . } }
respectiv
1 2 3 4 5 7 9 10 11 12 14 15 16 17 18
package cmmdc0 ; im po rt j a v a . rmi . RemoteException ; im po rt j a v a . rmi . s e r v e r . UnicastRemoteObject ; im po rt j a v a . rmi . r e g i s t r y . R e g i s t r y ; im po rt j a v a . rmi . r e g i s t r y . L o c a t e R e g i s t r y ; p u b l i c c l a s s FabObiecte implements I F a b O b i e c t e { p u b l i c ICmmdc0 getCmmdc ( ) throws RemoteException { ServerCmmdc cmmdc=new ServerCmmdc ( ) ; r e t u r n cmmdc ; } p u b l i c s t a t i c v o i d main ( S t r i n g a r g s [ ] ) { S t r i n g h o s t= l o c a l h o s t ; i n t p o r t =1099; i f ( a r g s . l e n g t h > 0) h o s t=a r g s [ 0 ] ;
89
19 20 21 22 23 24 25 26 27 28 29 30
try { FabObiecte o b j=new FabObiecte ( ) ; I F a b O b i e c t e s t u b =( I F a b O b i e c t e ) UnicastRemoteObject . e x p o r t O b j e c t ( obj , 0 ) ; R e g i s t r y r e g i s t r y=L o c a t e R e g i s t r y . g e t R e g i s t r y ( h os t , p o r t ) ; r e g i s t r y . bind ( O b j e c t F a c t o r y , s t u b ) ; System . out . p r i n t l n ( O b j e c t F a c t o r y r e a d y ) ; } catch ( Exception e ){ System . out . p r i n t l n ( F a c t o r y e r r +e . g e t M e s s a g e ( ) ) ; } } }
Aplicat ia client se compune din dou a clase 1. RemoteClient Clientul obt ine stub-ul serviciului, prin intermediul c aruia apeleaz a metada getCmmdc() a fabricii de obiecte, obt in and un obiect remote de tip ServerCmmdc, ce implementeaz a interfat a la distant a ICmmdc0.
1 2 3 4 5 7 9 11 13 14 15 16 17 18 19 20 21 22 23 24
package cmmdc0 ; im po rt j a v a . rmi . RemoteException ; im po rt j a v a . rmi . s e r v e r . UnicastRemoteObject ; im po rt j a v a . rmi . r e g i s t r y . R e g i s t r y ; im po rt j a v a . rmi . r e g i s t r y . L o c a t e R e g i s t r y ; p u b l i c c l a s s RemoteClient e x t e n d s UnicastRemoteObject { ICmmdc0 remote=n u l l ; p u b l i c RemoteClient ( ) throws RemoteException {} p u b l i c RemoteClient ( S t r i n g hos t , i n t p o r t ) throws RemoteException { I F a b O b i e c t e f a b r i c a=n u l l ; try { R e g i s t r y r e g i s t r y=L o c a t e R e g i s t r y . g e t R e g i s t r y ( h ost , p o r t ) ; I F a b O b i e c t e o b j =( I F a b O b i e c t e ) r e g i s t r y . l o o k u p ( O b j e c t F a c t o r y ) ; remote=o b j . getCmmdc ( ) ; } catch ( Exception e ){ System . out . p r i n t l n ( C l i e n t E x c e p t i o n : +e . g e t M e s s a g e ( ) ) ; } } }
90
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
i n t p o r t =1099; i f ( a r g s . l e n g t h > 0) h o s t=a r g s [ 0 ] ; i f ( a r g s . l e n g t h > 1) p o r t=I n t e g e r . p a r s e I n t ( a r g s [ 1 ] ) ; S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ; try { RemoteClient c t=new RemoteClient ( ho st , p o r t ) ; System . out . p r i n t l n ( m = ) ; long m =s c a n n e r . nextLong ( ) ; System . out . p r i n t l n ( n= ) ; l o n g n=s c a n n e r . nextLong ( ) ; l o n g x=c t . remote . compute (m, n ) ; System . out . p r i n t l n ( Cmmdc=+x ) ; } catch ( Exception e ){ System . out . p r i n t l n ( C l i e n t E x c e p t i o n : +e . g e t M e s s a g e ( ) ) ; } System . e x i t ( 0 ) ; } }
package cmmdc0 ; p u b l i c i n t e r f a c e ICmmdc0 e x t e n d s j a v a . rmi . Remote { p u b l i c l o n g compute ( l o n g m, l o n g n ) throws j a v a . rmi . RemoteException ; p u b l i c v o i d setMethod ( ICallbackCmmdc o b j ) throws j a v a . rmi . RemoteException ; }
91
1 2 3 4
package cmmdc0 ; im po rt j a v a . rmi . RemoteException ; im po rt j a v a . rmi . s e r v e r . UnicastRemoteObject ; p u b l i c c l a s s ServerCmmdc e x t e n d s UnicastRemoteObject implements ICmmdc0 { p r i v a t e S t r i n g method=n u l l ; p u b l i c ServerCmmdc ( ) throws RemoteException {} p u b l i c l o n g compute ( l o n g m, l o n g n ) { l o n g x =0; i f ( method . e q u a l s ( NERECURSIV ) ) x=n e r e c u r s i v (m, n ) ; i f ( method . e q u a l s ( RECURSIV ) ) x=r e c u r s i v (m, n ) ; return x ; } p u b l i c v o i d setMethod ( ICallbackCmmdc o b j ) throws RemoteException { method=o b j . getMethod ( ) ; } p r i v a t e long r e c u r s i v ( long a , long b){ i f ( a==b ) return a ; else i f ( a<b ) r e t u r n r e c u r s i v ( a , ba ) ; else r e t u r n r e c u r s i v ( ab , b ) ; } p r i v a t e l o n g n e r e c u r s i v ( l o n g m, l o n g n ) { long r , c ; do { c=n ; r= m %n ; m =n ; n=r ; } while ( r !=0); return c ; } }
Dup a obt inerea stub-ului, clientul apeleaz a metoda setMethod a serverului remote, care, prin apel invers, apeleaz a metoda getMethod din RemoteClient. Clientul stabile ste metoda de calcul si apeleaz a metoda compute a lui remote.
package cmmdc0 ; im po rt j a v a . rmi . RemoteException ; im po rt j a v a . rmi . s e r v e r . UnicastRemoteObject ; im po rt j a v a . rmi . r e g i s t r y . R e g i s t r y ; im po rt j a v a . rmi . r e g i s t r y . L o c a t e R e g i s t r y ; im po rt j a v a . u t i l . S c a n n e r ; p u b l i c c l a s s RemoteClient e x t e n d s UnicastRemoteObject implements ICallbackCmmdc { ICmmdc0 remote=n u l l ; p u b l i c RemoteClient ( ) throws RemoteException {} p u b l i c S t r i n g getMethod ( ) { S c a n n e r s c a n n e r=new S ca n n e r ( System . i n ) ; System . out . p r i n t l n ( A l e g e t i v a r i a n t a a l g o r i t m u l u i l u i E u c l i d ) ; System . out . p r i n t l n ( 1 a l g o r i t m u l ne r e c u r s i v ) ; System . out . p r i n t l n ( 2 a l g o r i t m u l r e c u r s i v ) ; i n t x=s c a n n e r . n e x t I n t ( ) ; S t r i n g method=n u l l ; i f ( x==1) method=NERECURSIV ; else method=RECURSIV ; r e t u r n method ; } p u b l i c RemoteClient ( S t r i n g hos t , i n t p o r t ) throws RemoteException { I F a b O b i e c t e f a b r i c a=n u l l ; try { R e g i s t r y r e g i s t r y=L o c a t e R e g i s t r y . g e t R e g i s t r y ( h os t , p o r t ) ; I F a b O b i e c t e o b j =( I F a b O b i e c t e ) r e g i s t r y . l o o k u p ( O b j e c t F a c t o r y ) ; remote=o b j . getCmmdc ( ) ; } catch ( Exception e ){ System . out . p r i n t l n ( C l i e n t E x c e p t i o n : +e . g e t M e s s a g e ( ) ) ; } } }
si
1 2 4 5 6 7 8 9 10 11 12 13 14 15 16
package cmmdc0 ; im po rt j a v a . u t i l . S c a n n e r ; p u b l i c c l a s s ClientCmmdc0 { p u b l i c s t a t i c v o i d main ( S t r i n g a r g s [ ] ) { S t r i n g h o s t= l o c a l h o s t ; i n t p o r t =1099; i f ( a r g s . l e n g t h > 0) h o s t=a r g s [ 0 ] ; i f ( a r g s . l e n g t h > 1) p o r t=I n t e g e r . p a r s e I n t ( a r g s [ 1 ] ) ; S c a n n e r s c a n n e r=new S ca n n e r ( System . i n ) ; try { RemoteClient c t=new RemoteClient ( ho st , p o r t ) ; c t . remote . setMethod ( c t ) ; System . out . p r i n t l n ( m = ) ;
93
17 18 19 20 21 22 23 24 25 26 27 28
long m =s c a n n e r . nextLong ( ) ; System . out . p r i n t l n ( n= ) ; l o n g n=s c a n n e r . nextLong ( ) ; l o n g x=c t . remote . compute (m, n ) ; System . out . p r i n t l n ( Cmmdc=+x ) ; } catch ( Exception e ){ System . out . p r i n t l n ( C l i e n t E x c e p t i o n : +e . g e t M e s s a g e ( ) ) ; } System . e x i t ( 0 ) ; } }
4.1.3
O instant a a clasei UnicastRemoteObject reprezint a un obiect la distant a care ruleaz a n permanent a, folosind resursele ma sinii server. Incep and cu versiunea JDK 1.2, prin ntroducerea clasei java.rmi.activation.Activatable si a programului rmid (...\jdk...\bin\rmid.exe) se pot crea programe care nregistreaz a informat ii despre obiecte la distant a ce vor create si executate la cerere. Invocarea de la distant a a unei metode apart in and unui asemenea obiect are ca efect activarea obiectului. Pe ecare ma sin a virtual a Java exist a un grup de activare (activation group), care realizeaz a activarea. Activarea este f acut a de un activator. Un activator cont ine o tabel a care face leg atura dintre clasa obiectului cu URL-ul acestuia si eventual, cu date necesare init ializ arii obiectului. Atunci c and activatorul constat a c a nu exist a un obiect referit, face apel la grupul de activare care va produce activarea obiectului. Din punctul de vedere al clientului utilizarea mecanismului de activare la distant a nu implic a modic ari. Modic arile intervin numai din punctul de vedere al serverului si al nregistr arii sale. Relu am aplicat ia dezvoltat a la nceputul capitolului, privind calculul celui mai mare divizor comun a dou a numere naturale. Aplicat ia server este compus a din dou a clase 1. o clasa ce implementeaz a interfat a ICmmdc : CmmdcActivabil; 2. clasa Setup, cu metoda main, care face posibil a mecanismul de activare si nscrie serviciul n registry. Aceast a clas a este preluat a din tutorialul dedicat activ arii a documentat iei ce nsot e ste distribut ia Java. Clasa ce implementeaz a interfat a la distant a trebuie
94
1. s a extind a clasa Activatable; 2. s a aib a un constructor ce are doi parametrii (a) un identicator al grupului de activare, de tip ActivationID, utilizat de demonul de activare rmid; (b) un obiect de tip MarshalledObject cu date de init ializare a obiec tului activabil. In cazul nostru, acest parametru nu va folosit. Codul surs a al clasei CmmdcActivabil este
1 2 3 4 5 6 8 9 11 12 13 14 16 17
package acmmdc ; im po rt j a v a . rmi . RemoteException ; im po rt j a v a . rmi . M a r s h a l l e d O b j e c t ; im po rt j a v a . rmi . a c t i v a t i o n . A c t i v a t a b l e ; im po rt j a v a . rmi . a c t i v a t i o n . A c t i v a t i o n I D ; im po rt cmmdc . ICmmdc ; p u b l i c c l a s s CmmdcActivabil e x t e n d s A c t i v a t a b l e implements ICmmdc { p u b l i c CmmdcActivabil ( A c t i v a t i o n I D id , M a r s h a l l e d O b j e c t data ) throws RemoteException { s u p e r ( id , 0 ) ; } p u b l i c l o n g cmmdc( l o n g m, l o n g n ) { . . . } }
Clasa Setup necesit a o serie de date furnizare ca propriet a ti: 1. drepturile de securitate ale grupului de activare myactivation.policy=group.policy; cu cont inutul
grant codeBase "${myactivation.impl.codebase}" { // permission to read and write objects file permission java.io.FilePermission "${myactivation.file}","read,write"; // permission to listen on an anonymous port permission java.net.SocketPermission "*:1024-","accept"; };
2. java.class.path=no.classpath ceea ce previne grupul de activare s a ncarce o clas a din classpath -ul local; 3. localizarea (URL) clasei ce implementeaz a interfat a myactivation.impl.codebase;
95
4. localizarea unui sier cu date de init ializare a obiectului activabil myactivation.file; 5. numele sub care nregistreaz a serviciul n registry myactivation.name. Programul Setup realizeaz a: 1. Construirea unui descriptor al grupului de activare. Grupul de activare este un container ce gestioneaz a obiectele activabile cont inute. 2. Inregistrarea descriptorului grupului de activare si obt inerea unui identicator al grupului de activare. 3. Construirea descriptorului de activare. Trebuie cunoscute idendicatorul grupului de activare; numele clasei ce implementeaz a interfat a la distant a ; localizarea (URL) clasei ce implementeaz a interfat a la distant a ; obiectul de tip MarshalledObject, cu datele de init ializare a obiectului activabil. 4. Inregistrarea descriptorului de activare, n urma c areia se obt ine stub-ul obiectului activabil. 5. Inregistrarea stub-ului mpreun a cu numele serviciului n registry. Codul clasei setup este
1 3 4 5 6 8 10 12 14 15 16 17 18
p u b l i c c l a s s Setup { p r i v a t e Setup ( ) {} p u b l i c s t a t i c v o i d main ( S t r i n g [ ] a r g s ) throws E x c e p t i o n { // Argumentul l i n i e i de comanda S t r i n g implClass = ; i f ( args . length < 1) { System . out . p r i n t l n ( u s a g e : ) ; System . out . p r i n t l n ( j a v a [ o p t i o n s ] examples . a c t i v a t i o n . Setup < i m p l C l a s s > ) ;
96
19 20 21 22 23 25 26 27 28 29 30 31 32 33 34 35 36 38 39 40 41 42 44 45 46 47 48 50 51 53 54 55 57 58 59 60 61 62
System . e x i t ( 1 ) ; } else { implClass = args [ 0 ] ; } // C o n s t r u i r e a d e s c r i p t o r u l u i g r u p u l u i de a c t i v a r e S t r i n g p o l i c y=System . g e t P r o p e r t y ( m y a c t i v a t i o n . p o l i c y , group . p o l i c y ) ; S t r i n g implCodbase=System . g e t P r o p e r t y ( m y a c t i v a t i o n . impl . c o d e b a s e ) ; S t r i n g filename=System . g e t P r o p e r t y ( m y a c t i v a t i o n . f i l e , ) ; P r o p e r t i e s p r o p s = new P r o p e r t i e s ( ) ; p r o p s . put ( j a v a . s e c u r i t y . p o l i c y , p o l i c y ) ; p r o p s . put ( j a v a . c l a s s . path , n o c l a s s p a t h ) ; p r o p s . put ( m y a c t i v a t i o n . impl . c o d e b a s e , implCodebase ) ; i f ( filename != n u l l && ! filename . equals ( ) ) { p r o p s . put ( m y a c t i v a t i o n . f i l e , filename ) ; } A c t i v a t i o n G r o u p D e s c groupDesc = new A c t i v a t i o n G r o u p D e s c ( props , n u l l ) ; // I n r e g i s t r a r e a g r u p u l u i de a c t i v a r e p e n t r o b t i n e r e a // i d e n t i f i c a t o r u l u i de a c t i v a r e Ac tivat ionG roupI D groupID= A c t i v a t i o n G r o u p . getSystem ( ) . r e g i s t e r G r o u p ( groupDesc ) ; System . e r r . p r i n t l n ( A c t i v a t i o n group d e s c r i p t o r r e g i s t e r e d . ) ; // C o n s t r u i r e a d e s c r i p t o r u l u i de a c t i v a r e M a r s h a l l e d O b j e c t data = n u l l ; i f ( filename != n u l l && ! filename . equals ( ) ) { data = new M a r s h a l l e d O b j e c t ( filename ) ; } A c t i v a t i o n D e s c d e s c= new A c t i v a t i o n D e s c ( groupID , i m p l C l a s s , implCodebase , data ) ; // I n r e g i s t r a r e a d e s c r i p t o r u l u i de a c t i v a r e Remote s t u b = A c t i v a t a b l e . r e g i s t e r ( d e s c ) ; System . e r r . p r i n t l n ( A c t i v a t i o n d e s c r i p t o r r e g i s t e r e d . ) ; // I n r e g i s t r a r e a s e r v i c i u l u i i n r e g i s t r y S t r i n g name = System . g e t P r o p e r t y ( m y a c t i v a t i o n . name ) ; L o c a t e R e g i s t r y . g e t R e g i s t r y ( ) . r e b i n d ( name , s t u b ) ; System . e r r . p r i n t l n ( Stub bound i n r e g i s t r y . ) ; } }
Sursele celor dou a programe CmmdcActivabil.java si respectiv Setup.java sunt n catalogul \c\src\acmmdc. Lansarea serverului n execut ie const a din 1. Pornirea demon -ului rmid start rmid -J-Djava.security.policy=rmid.policy -J-Dmyactivation.policy=group.policy unde rmid.policy este
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=*";};
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) interfet ei la distant a se precizeaz a prin java.rmi.server.codebase; Drept client se utilizeaz a programul realizat n sect iunea 4.1.
4.2
CORBA
Ret elele de calculatoare sunt eterogene n timp ce majoritatea interfet elor de programare a aplicat iilor sunt orientate spre platforme omogene. Pentru a facilita integrarea unor sisteme dezvoltate separat, ntr-un singur mediu distribuit eterogen, OMG (Object Management Group consort iu
98
cuprinz and peste 800 de rme) a elaborat standardul CORBA (Common Object Request Broker Arhitecture): un cadru de dezvoltare a aplicat iilor distribuite n medii eterogene. La CORBA au aderat toate marile rme de software - cu exceptia Microsoft, rm a care a dezvoltat propriul s au model DCOM (Distributed Component Object Model), incompatibil CORBA. Aplicat ia server se nregistreaz a ntr-un Object Request Broker (ORB) sub un nume simbolic - nume servici. Pe baza acestui nume de servici, un client acces and ORB va avea acces la funct iile oferite de aplicat ia server. ORB este un pachet de servicii, independent de aplicat ii, dar care permit aplicat iilor s a interact ioneze prin ret ea. ORB face parte din middleware un intermediar ntre softul de ret ea si cel de aplicat ie. Un ORB se poate executa local pe un singur calculator sau poate conectat cu oricare alt ORB din Internet, folosind protocolul IIOP -- Internet Inter ORB Protocol, denit de CORBA 2. Distribut ia jdk ofer a un ORB utilizabil n Java sub forma unui servici JNDI. CORBA face o separare ntre interfat a unui obiect si implementarea sa si folose ste un limbaj neutru pentru denirea interfet elor: IDL -- Interface Definition Language. IDL permite realizarea descrierii de interfet e independent de limbajul de programare si de sistemul de operare folosit. O interfat a IDL dene ste leg atura dintre client si server.
4.2.1
Firma Oracle - Sun Microsystems a dezvoltat o solut ie prin care interfet ele RMI pot implementate pentru a putea accesate ca obiecte CORBA. Aceasta este cunoscut a sub numele de solut ia RMI-IIOP, concretizat a printr-o serie de pachete din distribut ia jdk. In acest fel nu mai este necesar utilizarea limbajului IDL pentru descrierea interfet elor la distant a . Instrumente necesare utiliz arii solut iei RMI-IIOP: compilatorul rmic Opt iunea -iiop genereaza stub-ul si leg atura (tie) din partea serverului. Cu opt iunea -d se specic a catalogul n care aceste siere sunt scrise. serviciul ORB care asigur a reg asirea resurselor CORBA. Acest server se lanseaz a n execut ie prin
4.2. CORBA
99
start orbd -ORBInitialPort [port ] Programele orbd, rmic sunt n distribut ia jdk.
package cmmdciiop ; im po rt j a v a x . rmi . P o r t a b l e R e m o t e O b j e c t ; im po rt cmmdc . ICmmdc ; im po rt j a v a . rmi . RemoteException ; // Se e x t i n d e c l a s a P o r t a b l e R e m o t e O b j e c t // s i nu UnicastRemoteObject p u b l i c c l a s s CmmdcImpl e x t e n d s P o r t a b l e R e m o t e O b j e c t implements ICmmdc { // C o n s t r u c t o r u l c l a s e i p u b l i c CmmdcImpl ( ) throws RemoteException {} p u b l i c l o n g cmmdc( l o n g a , l o n g b ) { . . . } }
package cmmdciiop ; im po rt j a v a x . naming . I n i t i a l C o n t e x t ; im po rt j a v a x . naming . Context ; p u b l i c c l a s s CmmdcServer { p u b l i c s t a t i c v o i d main ( S t r i n g [ ] a r g s ) { S t r i n g h o s t= l o c a l h o s t ; S t r i n g p o r t= 1050 ; i f ( a r g s . l e n g t h > 0) h o s t=a r g s [ 0 ] ; i f ( a r g s . l e n g t h > 1) p o r t=a r g s [ 1 ] ; try { // 1 : C r e a r e a u n e i i n s t a n t e CmmdcImpl CmmdcImpl cmmdcRef = new CmmdcImpl ( ) ; // 2 : I n r e g i s t r a r e a u n e i r e f e r i n t e a s e r v i c i u l u i // u t i l i z a n d JNDI API System . s e t P r o p e r t y ( j a v a . naming . f a c t o r y . i n i t i a l , com . sun . j n d i . cosnaming . CNCtxFactory ) ;
100
21 22 23 24 25 26 27 28 29 30 31
System . s e t P r o p e r t y ( j a v a . naming . p r o v i d e r . u r l , i i o p : // +h o s t+ : +p o r t ) ; Context c t x = new I n i t i a l C o n t e x t ( ) ; c t x . r e b i n d ( CmmdcService , cmmdcRef ) ; System . out . p r i n t l n ( Cmmdc S e r v e r : Ready . . . ) ; } catch ( Exception e ) { System . out . p r i n t l n ( CmmdcServer: + e . g e t M e s s a g e ( ) ) ; } } }
4. Compilarea programelor CmmdcImpl.java si CmmdcServer.java. 5. Generarea stub-ului cmmdc. ICmmdc Stub.class corespunz ator interfet ei ator ICmmdc si a sierului Tie cmmdciiop. CmmdcImpl Tie.class corespunz clasei CmmdcImpl. Acestea se obt in rul and utilitarul rmic - din distrubut ia Java cu opt iunea -iiop rmic -iiop cmmdciiop.CmmdcImpl 6. Pornirea serverului CORBA de reg asire a serviciilor start orbd -ORBInitialPort 1050 7. Lansarea serverului n execut ie. Activit a tile legate de server se obt in prin ant cu sierul build
1 2 4 6 7 8 9 10 11 12 13 14 16 17 18 19 20 21 22
<project name= S e r v e r d e f a u l t= I n s t a l l b a s e d i r= . > <description> S e r v e r a c t i o n s</ description> <property name= path l oc a t io n= . . . /> <property name= package v a l u e= cmmdciiop /> <property name= i n t e r f a c e package v a l u e=cmmdc /> <property name= i n t e r f a c e j a r l oc a t io n= $ { path } / i / p u b l i c / c l a s s e s /cmmdc /> <property name= j a r f i l e v a l u e=cmmdc . j a r /> <property name= s e r v i c e c l a s s v a l u e=CmmdcServer /> <property name= i m p l e m e n t a t i o n c l a s s v a l u e=CmmdcImpl <property name= h o s t v a l u e= l o c a l h o s t /> <property name= p o r t v a l u e= 1050 />
/>
<target name= I n s t a l l > < ! C r e a t e t h e time stamp > <tstamp /> < ! C r e a t e t h e b u i l d d i r e c t o r y s t r u c t u r e used by c o m p i l e > <delete d i r= s r c /> <mkdir d i r= s r c /> <delete d i r= p u b l i c />
4.2. CORBA
101
23 24 25 26 28 29 30 31 32 33 34 36 37 38 39 40 41 42 43 44 45 46 47 49 50 51 52 53 55 56 57 58 59 60 61 62 63 64
<mkdir d i r= p u b l i c /> <delete d i r= p u b l i c / c l a s s e s /> <mkdir d i r= p u b l i c / c l a s s e s /> </ target> <target name= I n i t > <mkdir d i r= s r c /$ { package } /> <mkdir d i r= p u b l i c / c l a s s e s /$ { package } /> <copy f i l e = $ { i n t e r f a c e j a r } /$ { j a r f i l e } t o d i r= p u b l i c / c l a s s e s /> <unjar src= p u b l i c / c l a s s e s /$ { j a r f i l e } d e s t= p u b l i c / c l a s s e s /> <delete d i r= p u b l i c / c l a s s e s /META INF /> </ target> <target name= Compile depends= I n i t description= c o m p i l e t h e s o u r c e > <javac s r c d i r= s r c d e s t d i r= p u b l i c / c l a s s e s i n c l u d e s= $ { package }\ classpath= p u b l i c \ c l a s s e s \ $ { j a r f i l e } i n c l u d e a n t r u n t i m e= f a l s e /> <rmic c l a s s n a m e= $ { package } . $ { i m p l e m e n t a t i o n c l a s s } s o u r c e b a s e= s r c i i o p= y e s b a s e= p u b l i c / c l a s s e s classpath= p u b l i c / c l a s s e s /> </ target> <target name=Orb> <exec e x e c u t a b l e= orbd > <arg l i n e= O R B I n i t i a l P o r t $ { p o r t } O R B I n i t i a l H o s t $ { h o s t } /> </ exec> </ target> <target name= S e r v e r description= S t a r t t h r s e r v e r > <java c l a s s n a m e= $ { package } . $ { s e r v i c e c l a s s } f o r k= t r u e > <classpath> <pathelement l oc a t io n= p u b l i c / c l a s s e s /$ { j a r f i l e } /> <pathelement path= p u b l i c / c l a s s e s /> </ classpath> <arg l i n e= $ { h o s t } $ { p o r t } /> </ java> </ target> </ project>
1 2 3 4 5 6 8 9
package cmmdciiop ; import j a v a x . rmi . P o r t a b l e R e m o t e O b j e c t ; import j a v a x . naming . Context ; import j a v a x . naming . I n i t i a l C o n t e x t ; import j a v a . u t i l . S c a n n e r ; import cmmdc . ICmmdc ; public c l a s s CmmdcClient { public s t a t i c void main ( S t r i n g a r g s [ ] ) {
102
10 11 12 13 14 15 17 18 19 20 21 22 23 24 25 26 27 29 30 31 32 34 35 36 37 38 39 40 41 42 43 44
S t r i n g h o s t= l o c a l h o s t ; S t r i n g p o r t= 1050 ; i f ( a r g s . l e n g t h > 0) h o s t=a r g s [ 0 ] ; i f ( a r g s . l e n g t h > 1) p o r t=a r g s [ 1 ] ; S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ; System . out . p r i n t l n ( Primul numar : ) ; long m =Long . par se Lo ng ( s c a n n e r . n e x t ( ) ) ; System . out . p r i n t l n ( Al d o i l e a numar : ) ; long n=Long . p ars eL ong ( s c a n n e r . n e x t ( ) ) ; try { System . s e t P r o p e r t y ( j a v a . naming . f a c t o r y . i n i t i a l , com . sun . j n d i . cosnaming . CNCtxFactory ) ; System . s e t P r o p e r t y ( j a v a . naming . p r o v i d e r . u r l , i i o p : / / +h o s t+ : +p o r t ) ; Context c t x = new I n i t i a l C o n t e x t ( ) ; // STEP 1 : Get t h e O b j e c t r e f e r e n c e from t h e Name S e r v c t x e // u s i n g JNDI c a l l . O b j e c t o b j r e f = c t x . l o o k u p ( CmmdcService ) ; System . out . p r i n t l n ( C l i e n t : Obtained a r e f . t o Cmmdc s e r v e r . ) ; // STEP 2 : Narrow t h e o b j e c t r e f e r e n c e t o t h e c o n c r e t e t y p e and // i n v o k e t h e method . ICmmdc o b j =(ICmmdc) P o r t a b l e R e m o t e O b j e c t . narrow ( o b j r e f , ICmmdc . c l a s s ) ; long x=o b j . cmmdc(m, n ) ; System . out . p r i n t l n ( Cmmdc=+x ) ; } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( E x c e p t i o n + e . g e t M e s s a g e ( ) ) ; } } }
9. Compilarea si lansarea clientului n execut ie. Clientul trebuie s a dispun a de sierul stub (cmmdc. ICmmdc Stub.class) si bine nt eles de interfat a ICmmdc.jar. Fi sierul buildle pentru executarea clientului:
1 2 4 6 7 8 9 10 11 12 13 14 15
<project name= C l i e n t d e f a u l t= I n s t a l l b a s e d i r= . > <description> C l i e n t a c t i o n s</ description> <property name= path l oc a t io n= . . . /> <property name= package v a l u e= cmmdciiop /> <property name= i n t e r f a c e j a r l oc a t io n= $ { path } / i / p u b l i c / c l a s s e s /cmmdc /> <property name= j a r f i l e v a l u e=cmmdc . j a r /> <property name= s e r v e r package v a l u e= cmmdciiop /> <property name= i n t e r f a c e package v a l u e=cmmdc /> <property name= i n t e r f a c e stub l o c a t i o n l oc a t io n= $ { path } / s / p u b l i c / c l a s s e s /$ { i n t e r f a c e package } /> <property name= stub c l a s s v a l u e= S t u b . c l a s s /> <property name= h o s t v a l u e= l o c a l h o s t />
4.2. CORBA
103
16 17 19 20 21 22 23 24 25 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 45 46 47 48 49 50 52 53 54 55 56 57 58 59 60 61
<property name= p o r t v a l u e= 1050 /> <property name= c l i e n t c l a s s v a l u e= CmmdcClient /> <target name= I n s t a l l > < ! C r e a t e t h e b u i l d d i r e c t o r y s t r u c t u r e used by c o m p i l e > <delete d i r= s r c /> <mkdir d i r= s r c /> <delete d i r= c l a s s e s /> <mkdir d i r= c l a s s e s /> </ target> <target name= I n i t > < ! C r e a t e t h e time stamp > <tstamp /> <mkdir d i r= s r c /$ { package } /> <mkdir d i r= c l a s s e s /$ { package } /> <delete d i r= c l a s s e s /$ { s e r v e r package } /> <mkdir d i r= c l a s s e s /$ { s e r v e r package } /> <delete d i r= c l a s s e s /$ { i n t e r f a c e package } /> <mkdir d i r= c l a s s e s /$ { i n t e r f a c e package } /> <copy f i l e = $ { i n t e r f a c e j a r }\ $ { j a r f i l e } t o d i r= c l a s s e s /> <copy t o d i r= c l a s s e s /$ { i n t e r f a c e package } > < f i l e s e t d i r= $ { i n t e r f a c e stub l o c a t i o n } i n c l u d e s= $ { stub c l a s s } /> </ copy> <unjar src= c l a s s e s /$ { j a r f i l e } d e s t= c l a s s e s /> <delete d i r= c l a s s e s /META INF /> </ target> <target name= Compile depends= I n i t description= c o m p i l e t h e s o u r c e > <javac s r c d i r= s r c d e s t d i r= c l a s s e s i n c l u d e s= $ { package } \ . j a v a classpath= c l a s s e s i n c l u d e a n t r u n t i m e= f a l s e /> </ target> <target name=Run depends= Compile description=Run t h e c l i e n t > <java c l a s s n a m e= $ { package } . $ { c l i e n t c l a s s } f o r k= t r u e > <classpath> <pathelement l oc a t io n= c l a s s e s /$ { j a r f i l e } /> <pathelement path= c l a s s e s /> </ classpath> <arg l i n e= $ { h o s t } $ { p o r t } /> </ java> </ target> </ project>
4.2.2
Scopul acestei sect iuni este prezentarea dezvolt arii unei aplicat ii pe baza unei interfet e bazat pe IDL. Pentru dezvoltarea aplicat iilor n limbajul de programare Java, translatarea interfet ei IDL n Java se realizeaz a cu utilitarul idlj din distribut ia jdk. Corespondent a ntre entit a tile IDL si Java este dat a n Tabelul 4.1
104
Tip IDL module boolean char, wchar octet string, wstring short, unsigned short long, unsigned long long long, unsigned long long oat double xed enum, struct, union sequence, array interface (non-abstract)
Any
Tip Java package boolean char byte java.lang.String short int long oat double java.math.BigDecimal class array signature interface, operations interface, helper class, holder class org.omg.CORBA.Any
Legarea cererii unui client de codul serviciului care satisface cererea utilizeaz a componenta CORBA Portable Object Adapter (POA).
module CmmdcApp{ i n t e r f a c e Cmmdc{ long long cmmdc( i n long long a , i n long long b ) ; }; };
4.2. CORBA
105 Salv am acest text ntr-un sier denumit Cmmdc.idl. Cmmdc va numele interfet ei utilizat de un client si implementat de server. Serviciul cont ine o singur a metod a cmmdc.
(b) Translatarea interfet ei n Java idlj -fall Cmmdc.idl Programul idlj creaz a un subcatalog CmmdcApp cu un pachet Java CmmdcApp cont in and sierele: Cmmdc.java CmmdcPOA.java ; CmmdcOperations.java; CmmdcStub.java; CmmdcHelper.java; CmmdcHolder.java. 2. Realizarea programelor server. Punem n evident a programul servant CmmdcImpl.java ce implementeaz a interfat a Cmmdc.
1 2 4 5 7 8 9 11 12
im po rt CmmdcApp . ; im po rt o r g . omg .CORBA.ORB; p u b l i c c l a s s CmmdcImpl e x t e n d s CmmdcPOA { p r i v a t e ORB orb ; p u b l i c CmmdcImpl (ORB orb ) { t h i s . orb = orb ; } p u b l i c l o n g cmmdc( l o n g a , l o n g b ) { . . . } }
si programul CmmdcServer.java, care nscrie n registrul ORB referint ele servantului. Activit a tile ce trebuie ntreprinse sunt declarate prin comentarii n textul surs a al programului
1 2 3 4 5 6 7
im po rt im po rt im po rt im po rt im po rt im po rt im po rt
CmmdcApp . ; o r g . omg . CosNaming . NameComponent ; o r g . omg . CosNaming . NamingContextExtHelper ; o r g . omg . CosNaming . NamingContextExt ; o r g . omg .CORBA.ORB; o r g . omg . P o r t a b l e S e r v e r .POA; o r g . omg . P o r t a b l e S e r v e r . POAHelper ;
106
9 10 11 12 13 15 16 17 18 19 21 22 24 25 26 28 29 30 31 33 34 35 36 38 40 41 42 43 44 45 46 47 48
p u b l i c c l a s s CmmdcServer { p u b l i c s t a t i c v o i d main ( S t r i n g a r g s [ ] ) { try { // C r e a s e s i i n i t i a l i z a r e ORB ORB orb = ORB. i n i t ( a r g s , n u l l ) ; // O b t i n e r e a u n e i r e f e r i n t e POA s i // a c t i v a r e a g e s t i o n a r u l u i POAManager POA rootPOA = POAHelper . narrow ( orb . r e s o l v e i n i t i a l r e f e r e n c e s ( RootPOA ) ) ; rootPOA . the POAManager ( ) . a c t i v a t e ( ) ; // C r e a r e a unui s e r v a n t CmmdcImpl cmmdcImpl = new CmmdcImpl ( orb ) ; // O b t i n e r e a u n e i r e f e r i n t e p e n t r u s e r v a n t o r g . omg .CORBA. O b j e c t r e f=rootPOA . s e r v a n t t o r e f e r e n c e ( cmmdcImpl ) ; Cmmdc h r e f = CmmdcHelper . narrow ( r e f ) ; // O b t i n e r e a s e r v i c i u l u i NameService o r g . omg .CORBA. O b j e c t o b j R e f = orb . r e s o l v e i n i t i a l r e f e r e n c e s ( NameService ) ; NamingContextExt ncRef=NamingContextExtHelper . narrow ( o b j R e f ) ; // L e g a r e a s e r v a n t u l u i i n NameService S t r i n g name = CmmdcService ; NameComponent path [ ] = ncRef . to name ( name ) ; ncRef . r e b i n d ( path , h r e f ) ; System . out . p r i n t l n ( CmmdcServer r e a d y and w a i t i n g // Gata p e n t r u s a t i s f a c e r e a orb . run ( ) ; clientilor . . . );
Aceast a clas a corespunde unui sablon de programare adaptat exemplului tratat. In acest caz numele serviciului inregistrat n ORB va CmmdcService. Evident a numelor serviciilor CORBA nregistrate n ORB este f acut a de serviciul NameService. 3. Realizarea programului client CmmdcClient.java :
1 2 3 4 5 7 8
im po rt im po rt im po rt im po rt im po rt
CmmdcApp . ; o r g . omg . CosNaming . NamingContextExtHelper ; o r g . omg . CosNaming . NamingContextExt ; o r g . omg .CORBA.ORB; java . u t i l . Scanner ;
4.2. CORBA
107
10 11 12 13 15 16 17 18 19 21 22 23 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
p u b l i c s t a t i c v o i d main ( S t r i n g a r g s [ ] ) { try { // c r e a r e a s i i n i t i a l i z a r e a unui r e p r e z e n t a n t ORB ORB orb = ORB. i n i t ( a r g s , n u l l ) ; // o b t i n e r e a u n e i r e f e r i n t e p e n t r u s e r v i c i u l d e n u m i r i l o r // s e r v i c i i l o r i n r e g i s t r a t e o r g . omg .CORBA. O b j e c t o b j R e f = orb . r e s o l v e i n i t i a l r e f e r e n c e s ( NameService ) ; NamingContextExt ncRef = NamingContextExtHelper . narrow ( o b j R e f ) ; // o b t i n e r e a u n e i r e f e r i n t e l a s e r v i c i u l d o r i t S t r i n g name = CmmdcService ; cmmdc = CmmdcHelper . narrow ( ncRef . r e s o l v e s t r ( name ) ) ; System . out . p r i n t l n ( Obtained a h a n d l e on s e r v e r o b j e c t : + cmmdc ) ; S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ; l o n g m, n ; System . out . p r i n t l n ( m = ) ; m =s c a n n e r . nextLong ( ) ; System . out . p r i n t l n ( n= ) ; n=s c a n n e r . nextLong ( ) ; System . out . p r i n t l n ( Cmmdc=+cmmdc . cmmdc(m, n ) ) ; } catch ( Exception e ) { System . out . p r i n t l n ( ERROR : + e ) ; e . p r i n t S t a c k T r a c e ( System . out ) ; } } }
Din nou clasa client cont ine sablonul de accesare a unui serviciu CORBA. Programele se compileaz a javac CmmdcApp\*.java 4. Pornirea serviciului de intregistrare a numelor cu programul orbd.exe din distribut ia jdk. start orbd -ORBInitialHost localhost -ORBInitialPort 1050 5. Pornirea programului server prin start java CmmdcServer -ORBInitialHost localhost -ORBInitialPort 1050 6. Lansarea programului client prin
108
im po rt im po rt im po rt im po rt im po rt im po rt im po rt im po rt im po rt
java . u t i l . Properties ; o r g . omg .CORBA.ORB; o r g . omg .CORBA. P o l i c y ; o r g . omg . CosNaming . NamingContextExtHelper ; o r g . omg . CosNaming . NamingContextExt ; o r g . omg . CosNaming . NameComponent ; o r g . omg . P o r t a b l e S e r v e r .POA; o r g . omg . P o r t a b l e S e r v e r . POAHelper ; o r g . omg . P o r t a b l e S e r v e r . L i f e s p a n P o l i c y V a l u e ;
public class PersistentServer { p u b l i c s t a t i c v o i d main ( S t r i n g a r g s [ ] ) { P r o p e r t i e s p r o p e r t i e s = System . g e t P r o p e r t i e s ( ) ; p r o p e r t i e s . put ( o r g . omg .CORBA. O R B I n i t i a l H o s t , l o c a l h o s t ) ; p r o p e r t i e s . put ( o r g . omg .CORBA. O R B I n i t i a l P o r t , 1050 ) ; try { // Pas 1 : C r e a s e s i i n i t i a l i z a r e ORB ORB orb = ORB. i n i t ( a r g s , p r o p e r t i e s ) ; // Pas 2 : C r e a r e a unui s e r v a n t CmmdcImpl cmmdcImpl = new CmmdcImpl ( orb ) ; // Pas 3 : O b t i n e r e a u n e i r e f e r i n t e POA s i // a c t i v a r e a g e s t i o n a r u l u i POAManager // // Pas 31 : O b t i n e r e a r a d a c i n i i rootPOA POA rootPOA = POAHelper . narrow ( orb . r e s o l v e i n i t i a l r e f e r e n c e s ( RootPOA ) ) ; // Pas 32 : C r e a t e s e c u r i t a t i i P e r s i s t e n t P o l i c y P o l i c y [ ] p e r s i s t e n t P o l i c y = new P o l i c y [ 1 ] ; p e r s i s t e n t P o l i c y [ 0 ] = rootPOA . c r e a t e l i f e s p a n p o l i c y ( L i f e s p a n P o l i c y V a l u e . PERSISTENT ) ; // Pas 33 : C r e a r e a o b i e c t u l u i POA cu s e c u r i t a t e a t h e P e r s i s t e n t P o l i c y POA p e r s i s t e n t P O A=rootPOA . create POA ( childPOA , n u l l , p e r s i s t e n t P o l i c y ) ; // Pas 34 : A c t i v a r e a m a n a g e r u l u i PersistentPOA POAManager , p e r s i s t e n t P O A . the POAManager ( ) . a c t i v a t e ( ) ; // // Pas 4 : A s o c i e r e a s e r v a n t u l u i cu PersistentPOA
4.2. CORBA
109
40 42 43 44 45 47 48 49 50 51 53 54 55 56 57 58 59 60 61
o r g . omg .CORBA. O b j e c t o b j R e f= orb . r e s o l v e i n i t i a l r e f e r e n c e s ( NameService ) ; NamingContextExt r o o t C o n t e x t=NamingContextExtHelper . narrow ( o b j R e f ) ; NameComponent [ ] nc = r o o t C o n t e x t . to name ( P e r s i s t e n t C m m d c S e r v e r ) ; r o o t C o n t e x t . r e b i n d ( nc , p e r s i s t e n t P O A . s e r v a n t t o r e f e r e n c e ( cmmdcImpl ) ) ; // Pas 6 : Gata p e n t r u s a t i s f a c e r e a orb . run ( ) ; clientilor
Programul client
1 2 3 5 6 7 8 9 10 11 12 13 14 15 17 18 19 20 21 22 23 25 26 27 28 29 30 31 32 33 34
im po rt CmmdcApp . ; im po rt o r g . omg .CORBA.ORB; im po rt j a v a . u t i l . S c a n n e r ; public class PersistentClient { p u b l i c s t a t i c v o i d main ( S t r i n g a r g s [ ] ) { S t r i n g h o s t= l o c a l h o s t ; S t r i n g p o r t= 1050 ; i f ( a r g s . l e n g t h > 0) h o s t=a r g s [ 0 ] ; i f ( a r g s . l e n g t h > 1) p o r t=a r g s [ 1 ] ; try { // Pas 1 : I n i t i a l i z a r e ORB ORB orb = ORB. i n i t ( a r g s , n u l l ) ; // Pas 2 : R e z o l v a r e a p e r s i s t e n t e i // S e r v i c i u l NameService r u l e a z a pe h o s t cu p o r t u l p o r t // Numele s e r v i c i u l u i c e r u t l u i NameService e s t e // P e r s i s t e n t C m m d c S e r v e r o r g . omg .CORBA. O b j e c t o b j = orb . s t r i n g t o o b j e c t ( c o r b a n a m e : : +h o s t+ : +p o r t+#P e r s i s t e n t C m m d c S e r v e r ) ; Cmmdc cmmdc=CmmdcHelper . narrow ( o b j ) ; // Pas 3 : U t i l i z a r e a s e r v i c i u l u i S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ; System . out . p r i n t l n ( C a l l i n g P e r s i s t e n t S e r v e r . . ) ; i n t m, n , r ; System . out . p r i n t l n ( m = ) ; m =s c a n n e r . n e x t I n t ( ) ; System . out . p r i n t l n ( n= ) ; n=s c a n n e r . n e x t I n t ( ) ; System . out . p r i n t l n (cmmdc . cmmdc(m, n ) ) ; }
110
35 36 37 38 39 40
Serverul trebuie s a e pe acela si calculator pe care ruleaz a orbd. Executarea aplicat iei presupune: 1. Pornirea serviciului de intregistrare a numelor cu programul orbd.exe din distribut ia jdk. orbd -ORBInitialPort 1050 -serverPollingTime 200 2. Activarea serverului: (a) Se lanseaz a utilitarul servertool servertool -ORBInitialPort 1050 (b) Se nregistreaz a serverul mpreun a cu numele serviciului pe care l ndepline ste: servertool > register -server PersistentServer -applicationName PersistentCmmdcServer -classpath cale_catre_fisierele_server\ Indeplinirea act iunii de nregistrare a serverului este indicat printr-un mesaj de forma server registered (serverid=257). Alte comenzi servertool Comanda servertool> servertool> servertool> servertool> Semnicat ie shutdown -serverid 257 Oprirea serviciului unregister -serverid 257 S tergerea serviciului quit Inchiderea utilitarului help
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
112
5.1
JMS dene ste un cadru de programare Java (API) pentru realizarea aplicat iilor bazate pe comunicat ii asincrone. Prezentarea se bazeaz a pe interfat a de programare (API) JMS-2, pentru care exist a implementarea de referint a Open Message Queue 5.* de la Oracle. Pentru interfat a de programare (API) JMS-1, exist a mai multe implement ari JMS, dintre care semnal am: Open Message Queue * apache ActiveMQ apache qpid
1
113
114
Apache-qpid implementeaz a protocolul Advanced Message Queue Protocol (AMQP) referitor la modul de reprezentare a datelor ntr-un mesaj. Scopul protocolului este asigurarea interoperabilit a tii ntre aplicat ii de mesagerie realizate n diferite limbaje de programare. Versiunea Java a lui apache-qpid are n vedere interfat a de programare JMS 1. O aplicat ie JMS este alc atuit a din un furnizor JMS (provider JMS) : un sistem de mesagerie ce implementeaz a specicat iile JMS; client JMS : aplicat ie Java care trimite si recept ioneaz a mesaje; mesaje : obiecte utilizate n schimbul de informat ii de client i JMS; obiecte administrator - obiecte (resurse) create de administrator pentru a utilizate de client ii JMS, precum fabrica de conexiuni, obiectele destinat ie pentru ret inerea mesajelor. Aplicat iile dezvoltate pe baza JMS 1 functioneaz a si n cazul utiliz arii unui furnizor de servicii realizat pentru JMS-2. In esent a , JMS-2 simplic a programarea fat a de JMS-1. Modele de comunicat ie: Comunicat ii punctuale : Un mesaj este generat de un produc ator (expeditor) si la care va avea acces un singur consumator (destinatar). Mesajul este depus ntr-o coad a, de unde este preluat de c atre consumatorul care s-a legat de coad a. Dac a de coad a nu se leag a nici un consumator, atunci mesajul este p astrat n coad a. Comunicat ii axate pe subiect (topic) : Mesajele sunt depuse (publicate) n destinat ii specice subiectului. Consumatorii ce au subscris la acel subiect au acces la mesajele respective. Mai multi produc atori pot genera mesaje specice unui subiect, mesaje care pot accesate de consumatorii care au subscris subiectului. Consumatorii abonat i pe un subiect pot abonat simplu - valabi, adic a are acces la mesajele emise dup a momentul abon arii, pe durata conexiunii la furnizorul de servicii JMS; abonat permanent - valabil si dup a o ntrerupere a conexiunii la furnizorul de servicii JMS;
115
abonat partajat - mai multi abonat i utilizeaz a acea si conexiune; abonat partajat si permanent. Structura unui mesaj Un mesaj este alc atuit din Antet (header) : cont ine informat ii pentru identicarea destinat iei c at si pentru identicarea mesajului. Propriet a ti : au caracter opt ional si sunt sub forma (nume, valoare). Propriet a tile ajut a consumatorii s a selecteze mesajele. Corpul mesajului : opt ional. Potrivit specicat iilor JMS exist a 6 tipuri de mesaje. javax.jms.Message : mesaj f ar a corp; javax.jms.StreamMessage : corpul mesajului cont ine un ux Java de date de tip predenit; javax.jms.ByteMessage : javax.jms.MapMessage : corpul mesajului cont ine o familie de perechi (nume, valoare); javax.jms.TextMessage : corpul mesajului cont ine un string; javax.jms.ObjectMessage : corpul mesajului cont ine un obiect serializat. Ata sament (opt ional).
5.2
Instalarea variantei de sine st at atoare. In mediul Windows, n funct ie de resursa desc arcat a instalarea const a din: Se dezarhiveaz a sierul openmq*-binary-Windows.zip Se xeaz a atributele sierului etc\mq\imqenv.conf. Lansarea serviciului JMS. Orice aplicat ie JMS necesit a funct ionarea serviciului JMS. Serviciul JMS se instaleaz a prin imqbrokerd Funct ionarea corect a este indicat a prin mesajul
116
imqbroker@hostname:7676 ready Dac a se dore ste schimbarea portului atunci se folose ste opt iunea -port port. Pe un calculator pot coexista mai multe servicii JMS doar dac a folosesc porturi distincte si au nume diferite. In acest caz, lansarea unui nou serviciu se face prin imqbrokerd -port port -name name Cu utilitarul imqsvcadmin putem dezinstala : imqsvcadmin remove verica : imqsvcadmin query instala : imqsvcadmin install serviciul JMS ca serviciu Windows. Dezinstalarea si instalarea are efect odat a cu repornirea calculatorului. Compilarea si executarea unui program necesit a completarea variabilei sistem classpath cu sierele JMS HOME\lib\jms.jar JMS HOME\lib\imq.jar
5.3
Semnal am dou a modalit a ti de programare / generare / reg asire a obiectelor administrator: Programat: obiectele administrator se instant iaz a prin API-ul oferit de produsul informatic; Prin JNDI. Codul surs a al programelor este independent de furnizorul de servicii de mesagerie. Elementele specice se declar a n siere de propriet a ti.
5.3.1
117
Clasa com.sun.messaging.ConnectionFactory are descendent ii QueueConnectionFactor TopicConnectionFactory. (b) Obiectul destinat ie. In cazul comunicat iilor punctuale obiectul destinat ie este de tip javax.jms.Queue, iar crearea se face prin Queue q=new com.sun.messaging.Queue(numeCoada); Pentru comunicat ii axate pe subiect, obiectul destinat ie, de tip javax.jms.Topic se instant iaz a prin Topic t=new com.sun.messaging.Topic(subiect); 2. Instant ierea unui obiect de tip javax.jms.JMSContext JMSContext ctx=cf.createContext(); In nal, contextul se nchide ctx.close(); Prin intermediul unui obiect de tip JMSContext se obt in produc atorii de mesaje, de tip javax.jms.JMSProducer, dar si consumatorii de mesaje, de tip javax.jms.JMSConsumer. 3. Instant ierea unui produc ator de mesaje JMSProducer producer=ctx.createProducer(); Crearea si expedierea mesajelor se realizeaz a cu metodele clasei JMSProducer 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 )
118
JMSProducer send(Destination destination, Message message ) Un obiect care implementeaz a interfat a javax.jms.Message se obt ine prin ctx.createMessage(). Exemplul 5.3.1 Clasa urm atoare genereaz a ntr-un r de execut ie, un num ar de mesaje de tip TextMessage ntr-o comunicat ie punctual a. Sf ar situl expedierii mesajelor se indic a prin generarea unui mesaj de tip Message. Num arul mesajelor este indicat de un parametru al constructorului.
1 2 3 5 6 7 9 10 11 12 14 15 16 17 18 19 20 21 22 24 25 26 27 28 29 30 31 32 33 34 35
import j a v a x . jms . Queue ; import j a v a x . jms . JMSContext ; import j a v a x . jms . JMSProducer ; public c l a s s MsgSenderT extends Thread { int n ; S t r i n g queueName ; MsgSenderT ( S t r i n g queueName , i n t n ) { t h i s . queueName=queueName ; t h i s . n=n ; } public void run ( ) { try { com . sun . m e s s a g i n g . QueueConnectionFactory c f= new com . sun . m e s s a g i n g . QueueConnectionFactory ( ) ; // c f . s e t P r o p e r t y ( imqBrokerHostName , h o s t ) ; // c f . s e t P r o p e r t y ( imqBrokerHostPort , 7 6 7 6 ) ; Queue q=new com . sun . m e s s a g i n g . Queue ( queueName ) ; JMSContext c t x=c f . c r e a t e C o n t e x t ( ) ; JMSProducer p r o d u c e r=c t x . c r e a t e P r o d u c e r ( ) ; f o r ( i n t i =0; i <n ; i ++){ p r o d u c e r . send ( q , H e l l o +i ) ; } p r o d u c e r . send ( q , c t x . c r e a t e M e s s a g e ( ) ) ; ctx . c l o s e ( ) ; } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( JMSException : +e . g e t M e s s a g e ( ) ) ; } System . out . p r i n t l n ( Sen de r f i n i s h e d ) ; } }
5.3.2
Primele dou a act iuni sunt identice cu cele de la trimiterea unui mesaj: 1. Generarea obiectelor administrator.
119
2. Instant ierea unui obiect de tip javax.jms.JMSContext. 3. Instant ierea unui consumator de mesaje JMSConsumer consumer = ctx.createConsumer(q); Recept ia unui mesaj se obt ine cu una din metode Message receive() Recept ie blocant a. Message receive(long timeout ) Recept ie ntr-un interval de timp. Message receiveNoWait() Recept ie neblocant a. Exemplul 5.3.2 Recept ia de tip sincron a mesajelor ntr-un r de execut ie este efectuat de clasa urm atoare:
1 2 3 4 5 7 8 10 11 12 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
j a v a x . jms . TextMessage ; j a v a x . jms . Message ; j a v a x . jms . Queue ; j a v a x . jms . JMSContext ; j a v a x . jms . JMSConsumer ;
public c l a s s SyncMsgReceiverT extends Thread { S t r i n g queueName ; SyncMsgReceiverT ( S t r i n g queueName ) { t h i s . queueName=queueName ; } public void run ( ) { try { com . sun . m e s s a g i n g . QueueConnectionFactory c f= new com . sun . m e s s a g i n g . QueueConnectionFactory ( ) ; // c f . s e t P r o p e r t y ( imqBrokerHostName , h o s t ) ; // c f . s e t P r o p e r t y ( imqBrokerHostPort , 7 6 7 6 ) ; Queue q=new com . sun . m e s s a g i n g . Queue ( queueName ) ; JMSContext c t x=c f . c r e a t e C o n t e x t ( ) ; JMSConsumer consumer = c t x . createConsumer ( q ) ; Message msg=n u l l ; while ( ( msg=consumer . r e c e i v e ( ) ) ! = n u l l ) { i f ( msg instanceof TextMessage ) { TextMessage m=(TextMessage ) msg ; System . out . p r i n t l n (m. g e t T e x t ( ) ) ; } else break ; }
120
32 33 34 35 36 37 38 39
c l a s s MsgHelloT { public s t a t i c void main ( S t r i n g [ ] a r g s ) { i n t n=3; S t r i n g queueName=MyQueue ; i f ( a r g s . l e n g t h > 0) queueName=a r g s [ 0 ] ; i f ( a r g s . l e n g t h > 1) n=I n t e g e r . p a r s e I n t ( a r g s [ 1 ] ) ; MsgSenderT s e n d e r=new MsgSenderT ( queueName , n ) ; SyncMsgReceiverT r e c e i v e r =new SyncMsgReceiverT ( queueName ) ; receiver . start (); sender . s t a r t ( ) ; } }
5.3.3
Recept ia asincron a a mesajelor presupune implementarea interfet ei MessageListener ce cont ine o singur a metod a public void onMessage(Message mesaj); care xeaz a prelucrarea mesajului. Metoda setMessageListener(MessageListener obj ) a clasei JMSConsumer xeaz a obiectul ce implementeaz a interfat a Messagelistener. Astfel, caracterul asincron const a din faptul c a mesajele sunt preluate de ascult ator - adic a obiectul ce implementeaz a interfat a MessageListener si nu de clientul JMS. ideea exemplelor anterioare, un consumator de tip asinExemplul 5.3.4 In cron al mesajelor este dat n clasa urm atoare:
121
1 2 3 4 6 7 9 10 11 13 14 15 16 17 18 19 20 21 23 24 25 26 27 28 29 30 31 32 33
public c l a s s AsyncMsgReceiverT extends Thread { S t r i n g queueName ; AsyncMsgReceiverT ( S t r i n g queueName ) { t h i s . queueName=queueName ; } public void run ( ) { try { com . sun . m e s s a g i n g . QueueConnectionFactory c f= new com . sun . m e s s a g i n g . QueueConnectionFactory ( ) ; // c f . s e t P r o p e r t y ( imqBrokerHostName , h o s t ) ; // c f . s e t P r o p e r t y ( imqBrokerHostPort , 7 6 7 6 ) ; Queue q=new com . sun . m e s s a g i n g . Queue ( queueName ) ; JMSContext c t x=c f . c r e a t e C o n t e x t ( ) ; JMSConsumer consumer = c t x . createConsumer ( q ) ; T e x t L i s t e n e r t e x t L i s t e n e r=new T e x t L i s t e n e r ( ) ; consumer . s e t M e s s a g e L i s t e n e r ( t e x t L i s t e n e r ) ; t e x t L i s t e n e r . run ( ) ; ctx . c l o s e ( ) ; } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ; } System . out . p r i n t l n ( Consumer f i n i s h e d ) ; } }
public c l a s s T e x t L i s t e n e r implements M e s s a g e L i s t e n e r { boolean s f a r s i t = f a l s e ; public void onMessage ( Message message ) { i f ( message instanceof TextMessage ) { TextMessage m=(TextMessage ) message ; try { S t r i n g s= m. g e t T e x t ( ) ; System . out . p r i n t l n ( s ) ; } catch ( JMSException e ) { System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ; } } else s f a r s i t =true ; } public void run ( ) {
122
while ( ! s f a r s i t ) { try { Thread . s l e e p ( 1 ) ; } catch ( I n t e r r u p t e d E x c e p t i o n e ) { } }; } }
24 25 26 27 28 29 30 31
5.3.4
Publicarea mesajelor
Publicarea mesajelor corespunz atoare unui subiect se face asem an ator cu transmiterea mesajelor n comunicat ia punctual a, dar folosind instant e ale claselor dedicate acestui tip de comunicat ie. Exemplul 5.3.5
1 2 3 5 6 7 9 10 11 12 13 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
import j a v a x . jms . Topic ; import j a v a x . jms . JMSContext ; import j a v a x . jms . JMSProducer ; public c l a s s MsgPublisherT extends Thread { int n ; String subiect ; MsgPublisherT ( S t r i n g s u b i e c t , i n t n ) { super ( ) ; t h i s . n=n ; t h i s . s u b i e c t=s u b i e c t ; } public void run ( ) { try { com . sun . m e s s a g i n g . T o p i c C o n n e c t i o n F a c t o r y c f= new com . sun . m e s s a g i n g . T o p i c C o n n e c t i o n F a c t o r y ( ) ; // c f . s e t P r o p e r t y ( imqBrokerHostName , h o s t ) ; // c f . s e t P r o p e r t y ( imqBrokerHostPort , 7 6 7 6 ) ; Topic t=new com . sun . m e s s a g i n g . Topic ( s u b i e c t ) ; JMSContext c t x=c f . c r e a t e C o n t e x t ( ) ; JMSProducer p r o d u c e r=c t x . c r e a t e P r o d u c e r ( ) ; f o r ( i n t i =0; i <n ; i ++){ p r o d u c e r . send ( t , H e l l o +i ) ; } p r o d u c e r . send ( t , c t x . c r e a t e M e s s a g e ( ) ) ; ctx . c l o s e ( ) ; } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( JMSException : +e . g e t M e s s a g e ( ) ) ; } System . out . p r i n t l n ( P u b l i s h e r f i n i s h e d ) ; } }
123
5.3.5
Dac a t este obiectul de tip Topic, client ii se aboneaz a - subscriu - unui subiect prin JMSConsumer consumer = ctx.createConsumer(t); Subscrierea este valabil a at ata timp c at clientul este activ. Pentru a primi toate mesajele specice subiectului, chiar si c and clientul este inactiv, acesta trebuie s a e durabil, adic a crearea consumatorului s a se fac a prin ctx.setClientID(clientID); JMSConsumer consumer = ctx.createDurableConsumer(t,clientName); In ambele cazuri, clientul prime ste doar mesajele publicate din momentul subscrierii. Exemplul 5.3.6
1 2 3 4 5 7 8 9 10 12 13 14 15 16 18 19 20 21 22 23 24 25 26 27 29 30 31 32 33 34
j a v a x . jms . TextMessage ; j a v a x . jms . Message ; j a v a x . jms . Topic ; j a v a x . jms . JMSContext ; j a v a x . jms . JMSConsumer ;
public c l a s s MsgSubscriberT extends Thread { String subiect ; String clientID ; S t r i n g clientName ; MsgSubscriberT ( S t r i n g s u b i e c t , S t r i n g c l i e n t I D , S t r i n g c l i e n t N a m e ) { t h i s . s u b i e c t=s u b i e c t ; t h i s . c l i e n t I D=c l i e n t I D ; t h i s . c l i e n t N a m e=c l i e n t N a m e ; } public void run ( ) { try { com . sun . m e s s a g i n g . T o p i c C o n n e c t i o n F a c t o r y c f= new com . sun . m e s s a g i n g . T o p i c C o n n e c t i o n F a c t o r y ( ) ; // c f . s e t P r o p e r t y ( imqBrokerHostName , h o s t ) ; // c f . s e t P r o p e r t y ( imqBrokerHostPort , 7 6 7 6 ) ; Topic t=new com . sun . m e s s a g i n g . Topic ( s u b i e c t ) ; JMSContext c t x=c f . c r e a t e C o n t e x t ( ) ; ctx . setClientID ( c l i e n t I D ) ; JMSConsumer consumer = c t x . c r e a t e D u r a b l e C o n s u m e r ( t , c l i e n t N a m e ) ; Message msg=n u l l ; while ( ( msg=consumer . r e c e i v e ( ) ) ! = n u l l ) { i f ( msg instanceof TextMessage ) { TextMessage m=(TextMessage ) msg ; System . out . p r i n t l n ( c l i e n t N a m e+ r e c e i v e d : + m. g e t T e x t ( ) ) ; }
124
35 36 37 38 39 40 41 42 43 44 45
c l a s s MsgPS { public s t a t i c void main ( S t r i n g [ ] a r g s ) { S t r i n g s u b i e c t=JMS ; i n t n=3 , noAbonati =3; i f ( a r g s . l e n g t h > 0) s u b i e c t=a r g s [ 0 ] ; i f ( a r g s . l e n g t h > 1) n=I n t e g e r . p a r s e I n t ( a r g s [ 1 ] ) ; MsgPublisherT p u b l i s h e r=new MsgPublisherT ( s u b i e c t , n ) ; MsgSubscriberT [ ] abonat=new MsgSubscriberT [ noAbonati ] ; publisher . start ( ) ; f o r ( i n t i =0; i <noAbonati ; i ++){ abonat [ i ]=new MsgSubscriberT ( s u b i e c t , ID+i , i d +i ) ; abonat [ i ] . s t a r t ( ) ; } } }
5.3.6
Mai mult i client JMS folosesc acea si conexiune iar abonamentul se identic a printr-un nume (String). Dintre ace si client i doar unul recept ioneaz a mesajele care sunt emise dup a momentul abon arii. Exemplul 5.3.8 Fat a de exemplul anterior se vor expedia mai multe mesaje de tip Message.
1 2 3 5 6 7
import j a v a x . jms . Topic ; import j a v a x . jms . JMSContext ; import j a v a x . jms . JMSProducer ; public c l a s s MsgPublisherT extends Thread { int n ; String subiect ;
125
9 10 11 12 13 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
MsgPublisherT ( S t r i n g s u b i e c t , i n t n ) { super ( ) ; t h i s . n=n ; t h i s . s u b i e c t=s u b i e c t ; } public void run ( ) { try { com . sun . m e s s a g i n g . T o p i c C o n n e c t i o n F a c t o r y c f= new com . sun . m e s s a g i n g . T o p i c C o n n e c t i o n F a c t o r y ( ) ; // c f . s e t P r o p e r t y ( imqBrokerHostName , h o s t ) ; // c f . s e t P r o p e r t y ( imqBrokerHostPort , 7 6 7 6 ) ; Topic t=new com . sun . m e s s a g i n g . Topic ( s u b i e c t ) ; JMSContext c t x=c f . c r e a t e C o n t e x t ( ) ; JMSProducer p r o d u c e r=c t x . c r e a t e P r o d u c e r ( ) ; f o r ( i n t i =0; i <n ; i ++){ p r o d u c e r . send ( t , H e l l o +i ) ; } f o r ( i n t i =0; i <n ; i ++)p r o d u c e r . send ( t , c t x . c r e a t e M e s s a g e ( ) ) ; ctx . c l o s e ( ) ; } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( JMSException : +e . g e t M e s s a g e ( ) ) ; } System . out . p r i n t l n ( P u b l i s h e r f i n i s h e d ) ; } }
Pentru a folosi acea si conexiune recept ia mesajelor este programat a n dou a clase : Se instant iaz a o fabric a de conexiuni si un num ar de client i care vor utiliza acea si conexiune. Fiecare client este un r de execut ie care este gestionat de o cuv a (pool ) de re de execut ie.
1 2 3 4 5 6 7 9 10 11 12 13 15 16 17 18 19 20 22 23
j a v a x . jms . TextMessage ; j a v a x . jms . Message ; j a v a x . jms . Topic ; j a v a x . jms . JMSContext ; j a v a x . jms . JMSConsumer ; java . u t i l . concurrent . ExecutorService ; java . u t i l . concurrent . Executors ;
public c l a s s R e c e i v e r s T extends Thread { String subiect ; String sharedSubscriptionName ; i n t noAbonati ; com . sun . m e s s a g i n g . T o p i c C o n n e c t i o n F a c t o r y c f ; R e c e i v e r s T ( i n t noAbonati , S t r i n g s u b i e c t , String sharedSubscriptionName ){ t h i s . s u b i e c t=s u b i e c t ; t h i s . noAbonati=noAbonati ; t h i s . s h a r e d S u b s c r i p t i o n N a m e=s h a r e d S u b s c r i p t i o n N a m e ; } public void run ( ) { E x e c u t o r S e r v i c e e x e c=E x e c u t o r s . newFixedThreadPool ( noAbonati ) ;
126
25 26 27 28 30 31 32 33 34 35 36 37 38 39 41 42 43 44
try { c f=new com . sun . m e s s a g i n g . T o p i c C o n n e c t i o n F a c t o r y ( ) ; // c f . s e t P r o p e r t y ( imqBrokerHostName , h o s t ) ; // c f . s e t P r o p e r t y ( imqBrokerHostPort , 7 6 7 6 ) ; f o r ( i n t i =0; i <noAbonati ; i ++){ S t r i n g c l i e n t N a m e= C l i e n t +i ; MsgSubscriberT t=new MsgSubscriberT ( c f , s u b i e c t , sharedSubscriptionName , clientName ) ; exec . execute ( t ) ; } e x e c . shutdownNow ( ) ; } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( R e c e i v e r s : +e . g e t M e s s a g e ( ) ) ; } System . out . p r i n t l n ( R e c e i v e r s f i n i s h e d ) ; } }
j a v a x . jms . TextMessage ; j a v a x . jms . Message ; j a v a x . jms . Topic ; j a v a x . jms . JMSContext ; j a v a x . jms . JMSConsumer ;
public c l a s s MsgSubscriberT extends Thread { String subiect ; String clientID ; S t r i n g clientName ; String sharedSubscriptionName ; com . sun . m e s s a g i n g . T o p i c C o n n e c t i o n F a c t o r y c f ; MsgSubscriberT ( com . sun . m e s s a g i n g . T o p i c C o n n e c t i o n F a c t o r y c f , S t r i n g subiect , S t r i n g sharedSubscriptionName , S t r i n g clientName ){ t h i s . c f=c f ; t h i s . s u b i e c t=s u b i e c t ; t h i s . s h a r e d S u b s c r i p t i o n N a m e=s h a r e d S u b s c r i p t i o n N a m e ; t h i s . c l i e n t N a m e=c l i e n t N a m e ; } public void run ( ) { try { Topic t=new com . sun . m e s s a g i n g . Topic ( s u b i e c t ) ; JMSContext c t x=c f . c r e a t e C o n t e x t ( ) ; JMSConsumer consumer = c t x . c r e a t e S h a r e d C o n s u m e r ( t , sharedSubscriptionName ) ; Message msg=n u l l ; while ( ( msg=consumer . r e c e i v e ( ) ) ! = n u l l ) { i f ( msg instanceof TextMessage ) { TextMessage m=(TextMessage ) msg ; System . out . p r i n t l n ( c l i e n t N a m e+ r e c e i v e d : + m. g e t T e x t ( ) ) ;
127
35 36 37 38 39 40 41 42 43 44 45 46
public c l a s s MsgPS { public s t a t i c void main ( S t r i n g [ ] a r g s ) { S t r i n g s u b i e c t=JMS ; S t r i n g s h a r e d S u b s c r i p t i o n N a m e= o u r S u b s c r i p t i o n ; i n t n=3 , noAbonati =3; i f ( a r g s . l e n g t h > 0) s u b i e c t=a r g s [ 0 ] ; i f ( a r g s . l e n g t h > 1) n=I n t e g e r . p a r s e I n t ( a r g s [ 1 ] ) ; MsgPublisherT p u b l i s h e r=new MsgPublisherT ( s u b i e c t , n ) ; R e c e i v e r s T a b o n a t i=new R e c e i v e r s T ( noAbonati , s u b i e c t , sharedSubscriptionName ) ; abonati . s t a r t ( ) ; publisher . start ( ) ; } }
5.3.7
Obiectele administrator coada sau topic, care ret in mesajele se precizeaz a n siere de propriet a ti - jndi.properties. Pentru Open Message Queue acest sier este Varianta Oracle-Open Message Queue
1 2 3 5 7 8 9 11 12 13
j a v a . naming . f a c t o r y . i n i t i a l = com . sun . j n d i . f s c o n t e x t . RefFSContextFactory j a v a . naming . p r o v i d e r . u r l= f i l e : /// d : /Temp # use the f o l l o w i n g property to c o n f i g u r e the d e f a u l t connector # r e g i s t e r some q u e u e s i n JNDI u s i n g t h e form # queue . [ jndiName ] = [ physicalName ] queue . queue = myqueue # r e g i s t e r some t o p i c s i n JNDI u s i n g t h e form # t o p i c . [ jndiName ] = [ physicalName ] t o p i c . t o p i c = mytopic
128
In acest caz este nevoie de crearea n prealabil a obiectelor corespunz atoare conexiunii, a cozii (queue) si a subiectului (topic). Aceaste obiecte se creaz a cu utilitarul imqobjmgr din distribut ia Oracle-Open Message Queue. Obiectele se pot crea cu sierul de comenzi:
1 2 3 4 5 6 7 8 9 10 11 12 13
s e t PATH =d : \mq\ b i n ;%PATH % imqobjmgr add t q f l C o n n e c t i o n F a c t o r y j j a v a . naming . p r o v i d e r . u r l= f i l e : /// d : /Temp j j a v a . naming . f a c t o r y . i n i t i a l =com . sun . j n d i . f s c o n t e x t rem imqobjmgr add t t f l C o n n e c t i o n F a c t o r y j j a v a . naming . p r o v i d e r . u r l= f i l e : /// d : /Temp j j a v a . naming . f a c t o r y . i n i t i a l =com . sun . j n d i . f s c o n t e x t imqobjmgr add t q l queue j j a v a . naming . p r o v i d e r . u r l= f i l e : /// d : /Temp j j a v a . naming . f a c t o r y . i n i t i a l =com . sun . j n d i . f s c o n t e x t rem imqobjmgr add t t l t o p i c j j a v a . naming . p r o v i d e r . u r l= f i l e : /// d : /Temp j j a v a . naming . f a c t o r y . i n i t i a l =com . sun . j n d i . f s c o n t e x t
. RefFSContextFactory
. RefFSContextFactory
. RefFSContextFactory
. RefFSContextFactory
s e t PATH =d : \mq\ b i n ;%PATH % imqobjmgr d e l e t e t q f l C o n n e c t i o n F a c t o r y j j a v a . naming . p r o v i d e r . u r l= f i l e : /// d : /Temp j j a v a . naming . f a c t o r y . i n i t i a l =com . sun . j n d i . imqobjmgr d e l e t e t t f l C o n n e c t i o n F a c t o r y j j a v a . naming . p r o v i d e r . u r l= f i l e : /// d : /Temp j j a v a . naming . f a c t o r y . i n i t i a l =com . sun . j n d i . imqobjmgr d e l e t e t q l queue j j a v a . naming . p r o v i d e r . u r l= f i l e : /// d : /Temp j j a v a . naming . f a c t o r y . i n i t i a l =com . sun . j n d i . imqobjmgr d e l e t e t t l t o p i c j j a v a . naming . p r o v i d e r . u r l= f i l e : /// d : /Temp j j a v a . naming . f a c t o r y . i n i t i a l =com . sun . j n d i .
f s c o n t e x t . RefFSContextFactory
f s c o n t e x t . RefFSContextFactory
f s c o n t e x t . RefFSContextFactory
f s c o n t e x t . RefFSContextFactory
Relu am aplicat iile anterioare privind transmiterea / recept ia unui mesaj prin comunicat ie punctual a utiliz and o coad a si publicarea si recept ionarea unui mesaj prin comunicat ie bazat a pe subiect ntr-o variant a independentent a de suportul middleware de serviciu de mesagerie folosit. Reg asirea resurselor gestionate de serviciul de mesagerie se va face utiliz and JNDI.
5.3.8
Aplicat ia este alc atuit a din clasele MsgHelloT, MsgSenderT, SyncMsgReceiverT, AsyncMsgReceiverT, TextListener. Fat a de versiunea prezentat a anterior se modic a doar clasele MsgSenderT, SyncMsgReceiverT, AsyncMsgReceiverT. In clasa MsgHelloT c ampul queueName reprezint a numele JNDI al cozii. Clasa MsgSenderT
1 2
129
3 4 5 6 7 8 10 11 12 13 14 16 17 18 19 21 22 23 24 25 26 27 29 30 31 32 33 34 35 36 37 38 39 40 41 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 59 60 61
j a v a x . jms . JMSContext ; j a v a x . jms . JMSProducer ; j a v a x . naming . I n i t i a l C o n t e x t ; j a v a x . naming . NamingException ; java . u t i l . Properties ; j a v a . i o . IOException ;
public c l a s s MsgSenderT extends Thread { f i n a l S t r i n g CONNECTION JNDI NAME = C o n n e c t i o n F a c t o r y ; S t r i n g QUEUE JNDI NAME = queue ; private I n i t i a l C o n t e x t c t x ; private i n t n ; MsgSenderT ( S t r i n g queueName , i n t n ) { QUEUE JNDI NAME=queueName ; t h i s . n=n ; } public void run ( ) { try { setupJNDI ( ) ; QueueConnectionFactory c f= ( QueueConnectionFactory ) c t x . l o o k u p (CONNECTION JNDI NAME ) ; Queue q=(Queue ) c t x . l o o k u p (QUEUE JNDI NAME ) ; closeJNDI ( ) ; JMSContext j m s c t x=c f . c r e a t e C o n t e x t ( ) ; JMSProducer p r o d u c e r=j m s c t x . c r e a t e P r o d u c e r ( ) ; f o r ( i n t i =0; i <n ; i ++){ p r o d u c e r . send ( q , H e l l o +i ) ; } p r o d u c e r . send ( q , j m s c t x . c r e a t e M e s s a g e ( ) ) ; jmsctx . c l o s e ( ) ; } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( JMSException : +e . g e t M e s s a g e ( ) ) ; } System . out . p r i n t l n ( Sen de r f i n i s h e d ) ; } private void setupJNDI ( ) { P r o p e r t i e s p r o p e r t i e s = new P r o p e r t i e s ( ) ; try { p r o p e r t i e s . load ( this . g e t C l a s s ( ) . getResourceAsStream ( j n d i . p r o p e r t i e s ) ) ; } catch ( IOException e ) { System . out . p r i n t l n ( JNDI P r o p e r t i e s E r r o r : +e . g e t M e s s a g e ( ) ) ; } try { c t x = new I n i t i a l C o n t e x t ( p r o p e r t i e s ) ; } catch ( NamingException e ) { System . e r r . p r i n t l n ( E r r o r S e t t i n g up JNDI Context : + e ) ; } } private void c l o s e J N D I ( ) { try { ctx . c l o s e ( ) ;
130
62 63 64 65 66 67
Clasa SyncMsgReceiverT
1 2 3 4 5 6 7 8 9 10 12 13 14 15 17 18 19 21 22 23 24 25 26 27 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 48 50
import import import import import import import import import import
j a v a x . jms . QueueConnectionFactory ; j a v a x . jms . Queue ; j a v a x . jms . TextMessage ; j a v a x . jms . Message ; j a v a x . jms . JMSContext ; j a v a x . jms . JMSConsumer ; j a v a x . naming . I n i t i a l C o n t e x t ; j a v a x . naming . NamingException ; java . u t i l . Properties ; j a v a . i o . IOException ;
public c l a s s SyncMsgReceiverT extends Thread { f i n a l S t r i n g CONNECTION JNDI NAME = C o n n e c t i o n F a c t o r y ; S t r i n g QUEUE JNDI NAME = queue ; private I n i t i a l C o n t e x t c t x ; SyncMsgReceiverT ( S t r i n g queueName ) { QUEUE JNDI NAME=queueName ; } public void run ( ) { try { setupJNDI ( ) ; QueueConnectionFactory c f= ( QueueConnectionFactory ) c t x . l o o k u p (CONNECTION JNDI NAME ) ; Queue q=(Queue ) c t x . l o o k u p (QUEUE JNDI NAME ) ; closeJNDI ( ) ; JMSContext j m s c t x=c f . c r e a t e C o n t e x t ( ) ; JMSConsumer consumer = j m s c t x . createConsumer ( q ) ; Message msg=n u l l ; while ( ( msg=consumer . r e c e i v e ( ) ) ! = n u l l ) { i f ( msg instanceof TextMessage ) { TextMessage m=(TextMessage ) msg ; System . out . p r i n t l n (m. g e t T e x t ( ) ) ; } else break ; } jmsctx . c l o s e ( ) ; } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( JMSException : +e . g e t M e s s a g e ( ) ) ; } System . out . p r i n t l n ( Consumer f i n i s h e d ) ; } private void setupJNDI ( ) { . . . } private void c l o s e J N D I ( ) { . . . }
131
51
5.3.9
Aplicat ia este alc atuit a din clasele MsgPS, MsgPublisherT, MsgSubscriberT. Fat a de versiunea prezentat a anterior se modic a doar clasele MsgPublisherT si MsgSubscriberT. In clasa MsgPS c ampul subiect reprezint a numele JNDI ata sat topic-ului. Clasa MsgPublisherT
1 2 3 4 5 6 7 8 10 11 12 13 14 16 17 18 19 21 22 23 24 25 26 27 29 30 31 32 33 34 35 36 37 38 39 40 41 43 45
j a v a x . jms . T o p i c C o n n e c t i o n F a c t o r y ; j a v a x . jms . Topic ; j a v a x . jms . JMSContext ; j a v a x . jms . JMSProducer ; j a v a x . naming . I n i t i a l C o n t e x t ; j a v a x . naming . NamingException ; java . u t i l . Properties ; j a v a . i o . IOException ;
public c l a s s MsgPublisherT extends Thread { f i n a l S t r i n g CONNECTION JNDI NAME = C o n n e c t i o n F a c t o r y ; S t r i n g TOPIC JNDI NAME = t o p i c ; private I n i t i a l C o n t e x t c t x ; private i n t n ; MsgPublisherT ( S t r i n g s u b i e c t , i n t n ) { t h i s . n=n ; TOPIC JNDI NAME=s u b i e c t ; } public void run ( ) { try { setupJNDI ( ) ; T o p i c C o n n e c t i o n F a c t o r y c f= ( T o p i c C o n n e c t i o n F a c t o r y ) c t x . l o o k u p (CONNECTION JNDI NAME ) ; Topic t =( Topic ) c t x . l o o k u p (TOPIC JNDI NAME ) ; closeJNDI ( ) ; JMSContext j m s c t x=c f . c r e a t e C o n t e x t ( ) ; JMSProducer p r o d u c e r=j m s c t x . c r e a t e P r o d u c e r ( ) ; f o r ( i n t i =0; i <n ; i ++){ p r o d u c e r . send ( t , Despre JMS+ +i ) ; } p r o d u c e r . send ( t , j m s c t x . c r e a t e M e s s a g e ( ) ) ; jmsctx . c l o s e ( ) ; } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( JMSException : +e . g e t M e s s a g e ( ) ) ; } System . out . p r i n t l n ( P u b l i s h e r f i n i s h e d ) ; } private void setupJNDI ( ) { . . . } private void c l o s e J N D I ( ) { . . . }
132
}
46
Clasa MsgSubscriberT
1 2 3 4 5 6 7 8 9 10 12 13 14 15 16 17 19 20 21 22 23 25 26 27 28 29 30 31 32 33 34 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 53 55
import import import import import import import import import import
j a v a x . jms . T o p i c C o n n e c t i o n F a c t o r y ; j a v a x . jms . Topic ; j a v a x . jms . TextMessage ; j a v a x . jms . Message ; j a v a x . jms . JMSContext ; j a v a x . jms . JMSConsumer ; j a v a x . naming . I n i t i a l C o n t e x t ; j a v a x . naming . NamingException ; java . u t i l . Properties ; j a v a . i o . IOException ;
public c l a s s MsgSubscriberT extends Thread { f i n a l S t r i n g CONNECTION JNDI NAME = C o n n e c t i o n F a c t o r y ; S t r i n g TOPIC JNDI NAME = t o p i c ; private I n i t i a l C o n t e x t c t x ; private S t r i n g c l i e n t I D ; private S t r i n g c l i e n t N a m e ; MsgSubscriberT ( S t r i n g s u b i e c t , S t r i n g c l i e n t I D , S t r i n g c l i e n t N a m e ) { TOPIC JNDI NAME=s u b i e c t ; t h i s . c l i e n t I D=c l i e n t I D ; t h i s . c l i e n t N a m e=c l i e n t N a m e ; } public void run ( ) { try { setupJNDI ( ) ; T o p i c C o n n e c t i o n F a c t o r y c f= ( T o p i c C o n n e c t i o n F a c t o r y ) c t x . l o o k u p (CONNECTION JNDI NAME ) ; Topic t =( Topic ) c t x . l o o k u p (TOPIC JNDI NAME ) ; ; JMSContext j m s c t x=c f . c r e a t e C o n t e x t ( ) ; jmsctx . s e t C l i e n t I D ( c l i e n t I D ) ; JMSConsumer consumer = j m s c t x . c r e a t e D u r a b l e C o n s u m e r ( t , c l i e n t N a m e ) ; closeJNDI ( ) ; Message msg=n u l l ; while ( ( msg=consumer . r e c e i v e ( ) ) ! = n u l l ) { i f ( msg instanceof TextMessage ) { TextMessage m=(TextMessage ) msg ; System . out . p r i n t l n ( c l i e n t N a m e+ r e c e i v e d : + m. g e t T e x t ( ) ) ; } else break ; } jmsctx . c l o s e ( ) ; } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( JMSException : +e . g e t M e s s a g e ( ) ) ; } System . out . p r i n t l n ( S u b s c r i b e r f i n i s h e d ) ; } private void setupJNDI ( ) { . . . } private void c l o s e J N D I ( ) { . . . }
133
56
5.3.10
Aplicat ia va alc atuit a din trei client i: Client care preia si rezolv a cererile iar r aspunsurile sunt trimise solicitantului ntr-un mesaj pe un subiect indicat de acesta. Acest client preia mesajele corespunz atoare unui subiect public. Client care lanseaz a cererea. Acest client va crea un abonat durabil pe subiectul pe care se va prelua r aspunsul. Subiectul face parte din cerere. Client care preia r aspunsul. Exemplul 5.3.9 Calculul celui mai mare divizor comun a dou a numere naturale. Clasa MsgCmmdcServer
1 2 3 4 5 6 8 10 11 12 13 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
j a v a x . jms . TextMessage ; j a v a x . jms . Message ; j a v a x . jms . Topic ; j a v a x . jms . JMSContext ; j a v a x . jms . JMSConsumer ; j a v a x . jms . JMSProducer ; MsgCmmdcServer {
public c l a s s
public s t a t i c void main ( S t r i n g [ ] a r g s ) { MsgCmmdcServer s e r v e r=new MsgCmmdcServer ( ) ; server . service (); } private void s e r v i c e ( ) { try { com . sun . m e s s a g i n g . T o p i c C o n n e c t i o n F a c t o r y c f= new com . sun . m e s s a g i n g . T o p i c C o n n e c t i o n F a c t o r y ( ) ; // c f . s e t P r o p e r t y ( imqBrokerHostName , h o s t ) ; // c f . s e t P r o p e r t y ( imqBrokerHostPort , 7 6 7 6 ) ; Topic t=new com . sun . m e s s a g i n g . Topic ( Cmmdc ) ; JMSContext c t x=c f . c r e a t e C o n t e x t ( ) ; JMSConsumer consumer = c t x . c r e a t e S h a r e d C o n s u m e r ( t , Cmmdc ) ; JMSProducer p r o d u c e r = c t x . c r e a t e P r o d u c e r ( ) ; while ( true ) { Message msg=n u l l ; while ( ( msg=consumer . r e c e i v e ( ) ) ! = n u l l ) { i f ( msg instanceof TextMessage ) { TextMessage tm=(TextMessage ) msg ; S t r i n g s=tm . g e t T e x t ( ) ; S t r i n g [ ] s s=s . s p l i t ( ) ; long m =Long . par se Lon g ( s s [ 0 ] ) ;
134
33 34 35 36 37 38 39 40 41 43 44 45 46 47 49 50
long n=Long . p ars eL ong ( s s [ 1 ] ) ; S t r i n g t o p i c=s s [ 2 ] ; long c=cmmdc(m, n ) ; Topic t 1=new com . sun . m e s s a g i n g . Topic ( t o p i c ) ; p r o d u c e r . send ( t1 , ( new Long ( c ) ) . t o S t r i n g ( ) ) ; System . out . p r i n t l n ( S e r v e r s e n t +c+ t o +t o p i c ) ; } } } } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( JMSException : +e . g e t M e s s a g e ( ) ) ; } } private long cmmdc( long m, long n ) { . . . } }
Clasa MsgClientSender
1 2 3 4 5 7 8 10 11 12 13 14 15 16 17 18 19 20 21 22 23 25 26 27 28 29 30 31 32 34 35 36 37 38
j a v a x . jms . Topic ; j a v a x . jms . JMSContext ; j a v a x . jms . JMSProducer ; j a v a x . jms . JMSConsumer ; java . u t i l . Scanner ;
public c l a s s MsgClientSender { private S t r i n g msg , c l i e n t I D , clientName , t o p i c R e s u l t ; MsgClientSender ( S t r i n g c l i e n t I D , S t r i n g clientName ){ t h i s . c l i e n t I D=c l i e n t I D ; t h i s . c l i e n t N a m e=c l i e n t N a m e ; S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ; System . out . p r i n t l n ( I n t r o d u c e t i m : ) ; long m =s c a n n e r . nextLong ( ) ; S t r i n g sm=new Long (m) . t o S t r i n g ( ) ; System . out . p r i n t l n ( I n t r o d u c e t i n : ) ; long n=s c a n n e r . nextLong ( ) ; S t r i n g sn=new Long ( n ) . t o S t r i n g ( ) ; System . out . p r i n t l n ( I n t r o d u c e t i Topic u l r a s p u n s u l u i ) ; t o p i c R e s u l t=s c a n n e r . n e x t ( ) ; msg=sm+ +sn+ +t o p i c R e s u l t ; } private void s e r v i c e ( ) { try { com . sun . m e s s a g i n g . T o p i c C o n n e c t i o n F a c t o r y c f= new com . sun . m e s s a g i n g . T o p i c C o n n e c t i o n F a c t o r y ( ) ; // c f . s e t P r o p e r t y ( imqBrokerHostName , h o s t ) ; // c f . s e t P r o p e r t y ( imqBrokerHostPort , 7 6 7 6 ) ; Topic t=new com . sun . m e s s a g i n g . Topic ( Cmmdc ) ; JMSContext c t x=c f . c r e a t e C o n t e x t ( ) ; Topic t 1=new com . sun . m e s s a g i n g . Topic ( t o p i c R e s u l t ) ; ctx . setClientID ( c l i e n t I D ) ; JMSConsumer consumer = c t x . c r e a t e D u r a b l e C o n s u m e r ( t1 , c l i e n t N a m e ) ; JMSProducer p r o d u c e r=c t x . c r e a t e P r o d u c e r ( ) ; p r o d u c e r . send ( t , msg ) ;
135
39 40 41 42 43 44 46 47 48 49 50 51 52 53 54 55
ctx . c l o s e ( ) ; } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( JMSException : +e . g e t M e s s a g e ( ) ) ; } } public s t a t i c void main ( S t r i n g [ ] a r g s ) { i f ( a r g s . l e n g t h < 2) { System . out . p r i n t l n ( Usage : ) ; System . out . p r i n t l n ( j a v a M s g C l i e n t S e n d e r c l i e n t I D c l i e n t N a m e ) ; System . e x i t ( 0 ) ; } M s g C l i e n t S e n d e r c l i e n t=new M s g C l i e n t S e n d e r ( a r g s [ 0 ] , a r g s [ 1 ] ) ; client . service (); } }
Clasa MsgClientReceiver
1 2 3 4 5 6 8 9 11 12 13 14 15 16 17 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
j a v a x . jms . TextMessage ; j a v a x . jms . Message ; j a v a x . jms . Topic ; j a v a x . jms . JMSContext ; j a v a x . jms . JMSConsumer ; java . u t i l . Scanner ;
public c l a s s MsgClientReceiver { private S t r i n g t o p i c R e s u l t , c l i e n t I D , c l i e n t N a m e ; MsgClientReceiver ( S t r i n g c l i e n t I D , S t r i n g clientName ){ t h i s . c l i e n t I D=c l i e n t I D ; t h i s . c l i e n t N a m e=c l i e n t N a m e ; S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ; System . out . p r i n t l n ( I n t r o d u c e t i Topic u l r a s p u n s u l u i ) ; t o p i c R e s u l t=s c a n n e r . n e x t ( ) ; } public void s e r v i c e ( ) { try { com . sun . m e s s a g i n g . T o p i c C o n n e c t i o n F a c t o r y c f= new com . sun . m e s s a g i n g . T o p i c C o n n e c t i o n F a c t o r y ( ) ; // c f . s e t P r o p e r t y ( imqBrokerHostName , h o s t ) ; // c f . s e t P r o p e r t y ( imqBrokerHostPort , 7 6 7 6 ) ; Topic t=new com . sun . m e s s a g i n g . Topic ( t o p i c R e s u l t ) ; JMSContext c t x=c f . c r e a t e C o n t e x t ( ) ; ctx . setClientID ( c l i e n t I D ) ; JMSConsumer consumer = c t x . c r e a t e D u r a b l e C o n s u m e r ( t , c l i e n t N a m e ) ; Message msg=n u l l ; while ( ( msg=consumer . r e c e i v e ( ) ) ! = n u l l ) { i f ( msg instanceof TextMessage ) { TextMessage m=(TextMessage ) msg ; System . out . p r i n t l n ( Cmmdc : + m. g e t T e x t ( ) ) ; break ; } } ctx . c l o s e ( ) ; } catch ( E x c e p t i o n e ) {
136
40 41 42 44 45 46 47 48 49 50 51 52 53
System . out . p r i n t l n ( JMSException : +e . g e t M e s s a g e ( ) ) ; } } public s t a t i c void main ( S t r i n g [ ] a r g s ) { i f ( a r g s . l e n g t h < 2) { System . out . p r i n t l n ( Usage : ) ; System . out . p r i n t l n ( j a v a MsgSOAPClientReceiver c l i e n t I D c l i e n t N a m e ) ; System . e x i t ( 0 ) ; } M s g C l i e n t R e c e i v e r c l i e n t=new M s g C l i e n t R e c e i v e r ( a r g s [ 0 ] , a r g s [ 1 ] ) ; client . service (); } }
5.3.11
Diferent a fat a de versiunile amintite mai sus constau n obiectele administrator, fabrica de conexiuni, obiectul / sursa destinat ie care se creaz a de administratorul glasssh.
1. Se lanseaz a serverul de aplicat ii glasssh set GLASSFISH_HOME=. . .\glassfish3 set PATH=%GLASSFISH_HOME%\bin;%PATH% asadmin start-domain domain1 Lansarea serverului de aplicat ie implic a pornirea serverului JMS. 2. Dintr-un navigator se apeleaz a administratorul http://localhost:4848. 3. Resources JMS Resources Destination Resources Se creaz a c ate un obiect destinat ie cu datele: JNDI Name myQueue myTopic Physical Name myQueue myTopic Resource Type javax.jms.Queue javax.jms.Topic Resources JMS Resources Connection Factories Se creaz a c ate o fabric a de conexiuni cu datele: Pool Name myQueueConnectionFactory, respectiv myTopicConnectionFactory Resource Type javax.jms.QueueConnectionFactory, respectiv javax.jms.TopicConnectionFactory
137
import javax.annotation.Resource; . . . public class . . . @Resource(lookup="myQueueConnectionFactory") private static QueueConnectionFactory cf; @Resource(lookup="myQueue") private static Queue q; O aplicat ie se arhiveaz a cu jar cu indicarea clasei cu metoda main si se lanseaz a prin intermediul procedurii acoperitoare glassfish\bin\ appclient.bat appclient -client numeArhiva.jar [-targetserver host:3700]
j a v a x . jms . QueueConnectionFactory ; j a v a x . jms . Queue ; j a v a x . jms . JMSContext ; j a v a x . jms . JMSProducer ; javax . annotation . Resource ;
public c l a s s MsgSender { @Resource ( l o o k u p= myQueueConnectionFactory ) private s t a t i c QueueConnectionFactory c f ; @Resource ( l o o k u p=myQueue ) private s t a t i c Queue q ; private s t a t i c i n t n=3; public s t a t i c void main ( S t r i n g [ ] a r g s ) { try { JMSContext j m s c t x=c f . c r e a t e C o n t e x t ( ) ; JMSProducer p r o d u c e r=j m s c t x . c r e a t e P r o d u c e r ( ) ; f o r ( i n t i =0; i <n ; i ++){ p r o d u c e r . send ( q , H e l l o +i ) ; } p r o d u c e r . send ( q , j m s c t x . c r e a t e M e s s a g e ( ) ) ; jmsctx . c l o s e ( ) ; } catch ( E x c e p t i o n e ) { // System . o u t . p r i n t l n ( JMSException : +e . g e t M e s s a g e ( ) ) ; e . printStackTrace ( ) ; } System . out . p r i n t l n ( Sen de r f i n i s h e d ) ; } }
138
1 2 3 4 5 6 7 9 10 11 12 13 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
j a v a x . jms . QueueConnectionFactory ; j a v a x . jms . Queue ; j a v a x . jms . JMSContext ; j a v a x . jms . JMSConsumer ; j a v a x . jms . Message ; j a v a x . jms . TextMessage ; javax . annotation . Resource ;
public c l a s s SyncMsgReceiver { @Resource ( l o o k u p= myQueueConnectionFactory ) private s t a t i c QueueConnectionFactory c f ; @Resource ( l o o k u p=myQueue ) private s t a t i c Queue q ; public s t a t i c void main ( S t r i n g [ ] a r g s ) { try { JMSContext j m s c t x=c f . c r e a t e C o n t e x t ( ) ; JMSConsumer consumer = j m s c t x . createConsumer ( q ) ; Message msg=n u l l ; while ( ( msg=consumer . r e c e i v e ( ) ) ! = n u l l ) { i f ( msg instanceof TextMessage ) { TextMessage m=(TextMessage ) msg ; System . out . p r i n t l n (m. g e t T e x t ( ) ) ; } else break ; } jmsctx . c l o s e ( ) ; } catch ( E x c e p t i o n e ) { // System . o u t . p r i n t l n ( JMSException : +e . g e t M e s s a g e ( ) ) ; e . printStackTrace ( ) ; } System . out . p r i n t l n ( Consumer f i n i s h e d ) ; } }
139
6.1
Transact ie http
Protocolul http este de tip client-server: Navigatoarele Google Chrome, Mozilla Firefox, Microsoft Internet Explorer, Opera, Apple Safari sunt aplicat ii client uzuale. Informat iile sunt g azduite / generate de servere Web de c atre site-uri si servicii Web. Exemple de servere Web sunt apache HTTP Server, Microsoft Internet Interchange Server. O categorie aparte - esent ial a pentru platforma Java - este dat a de servere Web container de servlet si Java Server Pages (JSP). Protocolul http este unidirect ional. Transmiterea unui mesaj conform protocolului http const a din 141
142
1. stabilirea unei conexiuni c atre un destinatar; 2. expedierea mesajului; 3. nchiderea conexiunii. Acest ciclu de act iuni se nume ste tranzact ie http. Practic, ntr-o aplicat ie Web, expedierea unei cereri de un client c atre un server Web si receptionarea r aspunsului furnizat de server presupun dou a tranzact ii http. Un mesaj de tip cerere difer a de un mesaj de tip r aspuns prin structura unor elemente constitutive. Serverul nu ret ine informat ii ntre dou a tranzact ii http. Acest comportament se exprim a prin terminologia: protocolul http este f ar a stare - stateless. Transmisia datelor se realizeaz a utiliz and de obicei protocolul TCP. Referint ele resurselor se indic a folosind URI / URL. Cererile si r aspunsurile sunt reprezentate ca linii de text separate de caracterul <CR><LF>, av and structura 1. preambul - format dintr-o linie; 2. antete (header ) - 0 sau mai multe atribute (nume:valoare); 3. o linie goal a; 4. corpul mesajului - opt ional. Preambulul unei cereri cont ine: 1. numele metodei {GET, POST, PUT, DELETE, HEAD, CONNECT, TRACE, OPTIONS}; 2. referint a resursei (URL); 3. Versiunea protocolului http. Preambulul unui r aspuns cont ine: 1. Versiunea protocolului http; 2. codul r aspunsului: num ar natural format din trei cifre cu semnicat iile
143
Indic a mesaj de informare mesaj de succes redirectare c atre alt URL eroare in mesajul clientului eroare din partea serverului
Categoria este dat a de prima cifr a. 3. String explicit and codul r aspunsului. Un antet (header ) este un atribut, adic a o pereche (nume:valoare). Protocolul http dene ste o palet a larg a de atribute. Exemple de antete sunt date n tabelul urm ator: Antet Semnicat ie Exemplu host Gazda si portul serverului Web localhost:8080 user-agent Navigatorul care a lansat cererea Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.106 Safari/535.2 referer URL-ul cererii http://localhost:8080/apphello/ accept-encoding Tipuri de arhive acceptate gzip,deate,sdch accept-charset Tipuri de codicare acceptate ISO-8859-1,utf-8;q=0.7,*;q=0.3 accept-language Cea mai potrivit a limb a pentru nt elegerea cont inutului en-US,en;q=0.8 content-type Tipul MIME al corpului mesajului http://application/x-www-form-urlencoded content-length Lungimea corpului mesajului 22 Corpul mesajului este reprezentat printr-un text. Dac a cont inutul este imagine, cod binar, etc., atunci acesta este codicat n text. Codul Multipurpose Internet Mail Exchange (MIME) precizeaz a natura cont inutului unei resurse:
144
text/plain text/html text/xml image/png image/jpg application/octet-stream application/x-www-form-urlencoded Ne propunem s a punem n evident a mesajele http.
java . net . ServerSocket ; java . net . Socket ; j a v a . i o . InputStream ; j a v a . i o . InputStreamReader ; java . i o . BufferedReader ; j a v a . i o . IOException ; java . io . BufferedWriter ; java . io . FileWriter ;
public c l a s s RequestHTTPMsg { public s t a t i c void main ( S t r i n g [ ] a r g s ) { S o c k e t s o c k e t=n u l l ; try { S e r v e r S o c k e t s e r v e r S o c k e t=new S e r v e r S o c k e t ( 8 0 8 0 ) ; s o c k e t=s e r v e r S o c k e t . a c c e p t ( ) ; } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ; } try ( InputStream i s=s o c k e t . g e t I n p u t S t r e a m ( ) ; InputStreamReader i s r =new InputStreamReader ( i s ) ; B u f f e r e d R e a d e r br=new B u f f e r e d R e a d e r ( i s r ) ; F i l e W r i t e r fw=new F i l e W r i t e r ( ou tp ut . t x t , true ) ; B u f f e r e d W r i t e r bw=new B u f f e r e d W r i t e r ( fw ) ) { for ( ; ; ) { S t r i n g s=br . r e a d L i n e ( ) ; i f ( s==n u l l ) break ; System . out . p r i n t l n ( s ) ; bw . w r i t e ( s ) ; bw . newLine ( ) ; } } catch ( IOException e ) { System . out . p r i n t l n ( I n p u t E x c e p t i o n : +e . g e t M e s s a g e ( ) ) ;
145
36 37 38
} } }
Rezultatul cererii depinde de metoda GET sau POST utilizat a n formularul html folosit. Pentru metoda GET cererea http este
GET /apphello/hello?name=mk&tip=text%2Fhtml HTTP/1.1 Host: localhost:8080 Connection: keep-alive User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.106 Safari/535.2 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
<html> <head>< t i t l e > S e r v l e t u l H e l l o</ t i t l e ></ head> <body> <center> <h1> Pagina de a p e l a r e a s e r v l e t u l u i H e l l o S e r v l e t </ h1> <form method= p o s t action= h t t p : / / l o c a l h o s t : 8 0 8 0 / a p p h e l l o / h e l l o > <p> I n t r o d u c e t i numele : <input type= t e x t name=name s i z e =20> <p> <input type= submit value= A p e l e a z a > <input type= h id de n name= t i p value= t e x t / html > </ form> </ center> </ body> </htm
146
java . net . Socket ; j a v a . i o . InputStreamReader ; java . i o . BufferedReader ; j a v a . i o . IOException ; java . io . BufferedWriter ; java . io . FileWriter ; java . io . PrintWriter ; java . u t i l . Scanner ;
public c l a s s ResponseHTTPMsg { public s t a t i c void main ( S t r i n g [ ] a r g s ) { S t r i n g reqGET=GET / a p p h e l l o / h e l l o ?name=mk&t i p=t e x t%2Fhtml HTTP/ 1 . 1 \ r \ n+ Host : l o c a l h o s t : 8 0 8 0 \ r \ n+ C o n n e c t i o n : keep a l i v e \ r \ n+ User Agent : M o z i l l a / 5 . 0 ( Windows NT 6 . 1 ; WOW64) + AppleWebKit / 5 3 5 . 2 (KHTML, l i k e Gecko ) + Chrome / 1 5 . 0 . 8 7 4 . 1 0 6 S a f a r i / 5 3 5 . 2 \ r \ n+ Accept : t e x t / html , a p p l i c a t i o n / xhtml+xml , a p p l i c a t i o n /xml ; + q = 0 . 9 , / ; q =0.8 \ r \ n+ Accept Encoding : g z i p , d e f l a t e , sdch \ r \ n+ Accept Language : enUS , en ; q =0.8 \ r \ n+ Accept C h a r s e t : ISO 8859 1, u t f 8; q = 0 . 7 , ; q =0.3 \ r \ n ; S t r i n g reqPOST=POST / a p p h e l l o / h e l l o HTTP/ 1 . 1 \ r \ n+ Host : l o c a l h o s t : 8 0 8 0 \ r \ n+ C o n n e c t i o n : keep a l i v e \ r \ n+ Content Length : 23 \ r \ n+ CacheC o n t r o l : maxage =0\ r \ n+ O r i g i n : n u l l \ r \ n+ User Agent : M o z i l l a / 5 . 0 ( Windows NT 6 . 1 ; WOW64) + AppleWebKit / 5 3 5 . 2 (KHTML, l i k e Gecko ) + Chrome / 1 5 . 0 . 8 7 4 . 1 0 6 S a f a r i / 5 3 5 . 2 \ r \ n+ Content Type : a p p l i c a t i o n /xwww form u r l e n c o d e d \ r \ n+ Accept : t e x t / html , a p p l i c a t i o n / xhtml+xml , a p p l i c a t i o n /xml ; + q = 0 . 9 , / ; q =0.8 \ r \ n+ Accept Encoding : g z i p , d e f l a t e , sdch \ r \ n+ Accept Language : enUS , en ; q =0.8 \ r \ n+ Accept C h a r s e t : ISO 8859 1, u t f 8; q = 0 . 7 , ; q =0.3 \ r \ n+ \ r \ n+ name=mk&t i p=t e x t%2Fhtml ; S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ; System . out . p r i n t l n ( P r e c i z a t i metoda HTTP : ) ; System . out . p r i n t l n ( 1 : GET; 2 : POST ) ; i n t metoda ; do { metoda=s c a n n e r . n e x t I n t ( ) ; } while ( ( metoda!=1)&&(metoda ! = 2 ) ) ; try ( S o c k e t s o c k e t=new S o c k e t ( l o c a l h o s t , 8 0 8 0 ) ;
147
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
InputStreamReader i s r =new InputStreamReader ( s o c k e t . g e t I n p u t S t r e a m ( ) ) ; B u f f e r e d R e a d e r br=new B u f f e r e d R e a d e r ( i s r ) ; F i l e W r i t e r fw=new F i l e W r i t e r ( ou tp ut . t x t , true ) ; B u f f e r e d W r i t e r bw=new B u f f e r e d W r i t e r ( fw ) ; P r i n t W r i t e r pw=new P r i n t W r i t e r ( s o c k e t . getOutputStream ( ) , true ) ){ switch ( metoda ) { case 1 : // Lansarea u n e i c e r e r i GET pw . p r i n t l n ( reqGET ) ; break ; case 2 : // Lansarea u n e i c e r e r i POST pw . p r i n t l n ( reqPOST ) ; } for ( ; ; ) { S t r i n g s=br . r e a d L i n e ( ) ; i f ( s==n u l l ) break ; System . out . p r i n t l n ( s ) ; bw . w r i t e ( s ) ; bw . newLine ( ) ; } } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( E x c e p t i o n : +e . g e t M e s s a g e ( ) ) ; } } }
6.2
In prezent sunt disponibile mai multe servere Web n care poate instalat un servlet si un sier JSP Java Server Pages. Despre un asemenea server Web se spune c a este container de servlet si JSP. Dintre produsele gratuite amintim apache-tomcat
Acest server Web este utilizat n Glasssh - o implementare JEE (Java Enterprise Edition) sprijinit de Oracle. jboss application server Geronimo, o alta implementare JEE dezvoltat a de fundat ia apache, poate utiliza containerul apache-tomcat sau jetty. Serverul Apache HTTP Server si Windows Internet Information Server nu sunt servere Web containere de servlet si JSP.
6.3
Serverul Web apache-tomcat, (pe scurt tomcat ) este distribuit gratuit si poate desc arcat pornind de la adresa www.apache.org. Instalarea serverului n mediul Windows revine la dezarhivarea sierului desc arcat apache-tomcat-***, ntr-un catalog TOMCAT HOME. Utilizarea serverului necesit a xarea a doi parametri sistem: CATALINA HOME= calea la catalogul n care s-a instalat produsul - TOMCAT HOME; ia Java utilizat a. JAVA HOME=calea la distribut Pachetul cont ine cataloagele1 : bin, common, conf, logs, server, shared, temp, webapps, work. Serverul se lanseaz a prin comanda TOMCAT HOME\bin\startup si se opre ste cu comanda TOMCAT HOME\bin\shutdown Din catalogul TOMCAT HOME, lansarea se poate obt ine cu ajutorul sierului de comenzi (*.bat) set CATALINA_HOME=. . . set JAVA_HOME=. . . bin\startup
1
149
Opt ional se poate instala / activa managerul / administatorul serverului Web tomcat. Vericarea funct ion arii serverului Web tomcat se face apel and dintr-un navigator pagina http://host:port unde host este numele calculatorului pe care ruleaz a tomcat; Portul implicit este 8080. Reu sita este ilustrat a de imaginea motanului
Toate aplicat iile se depun n catalogul TOMCAT HOME\webapps. Asem an ator se procedeaz a si n cazul serverului Web jetty. Nu este nevoie de nici o congurare suplimentar a, lansarea f ac andu-se prin cd . . .\jetty-hightide-* java -jar start.jar Din nou aplicat iile se depun n catalogul \jetty-hightide-8.0.*\webapps.
Parametrul keystore xeaz a locat ia si denumirea sierului certicatului de securitate. Se denesc dou a parole keypass parola certicatului de securitate;
150
storepass parola de protect ie a locat iei certicatului de securitate. Parametrul cale desemneaz a calea c atre catalogul unde n care se creaz a sierul tomcatKeystore - certicatul de securitate. Uzual, certicatul de securitate se mut a n catalogul TOMCAT HOME\conf. 2. Modicarea sierului apache-tomcat-*\conf\server.xml Se decomenteaz a elementul
<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true" maxThreads="150" scheme="https" secure="true" clientAuth="false" sslProtocol="TLS" />
6.4
Glasssh
Instalarea si lansarea serverului. Instalarea const a din dezarhivarea arhivei desc arcate. Este recomandat includerea n sierul GLASSFISH HOME\grassfish\config\ asenv.bat a liniei set AS_JAVA=c:\Progra~1\Java\jdk1.* Utilizarea paginilor JSP necesit a aceast a setare. Prin intermediul paginii de administrare se poate schimba parola administratorului (admin ). Containerele n care se depun aplicat iile se a a ntr-un domeniu. Implicit, n catalogul glasssh\domain se creaz a domeniul cu numele domain1: GLASSFISH HOME\glassfish\domains\domain1. Lansarea serverului se poate face prin: a Din GLASSFISH HOME\glassfish\bin se comand asadmin start-domain domain1 Oprirea serverului se poate face prin:
6.4. GLASSFISH
Administrarea serverului se face prin pagina Web http://localhost:4848 utilitarul GLASSFISH HOME\bin\asadmin.bat Administratorul serverului are posibilitatea s a creeze domenii noi: Astfel crearea unui domeniu nou, av and numele numeDomeniu, situat n catalogul dirDomeniu se obt ine prin asadmin create-domain --adminport 4848 --domaindir dirDomeniu numeDomeniu S tergerea domeniului se obt ine prin asadmin delete-domain --domaindir dirDomeniu numeDomeniu Lansarea si oprirea serverului glasssh se comand a prin asadmin start-domain --domaindir dirDomeniu numeDomeniu asadmin stop-domain --domaindir dirDomeniu numeDomeniu
152
154
Interfat a grac a, n cazul extinderii clasei Applet, va utiliza controlurile apart in and interfet ei de programare AWT (Abstract Window Toolkit ), iar n cazul extinderii clasei JApplet se vor utiliza controluri JavaFX / Swing.
7.1
Clasa Applet
Structura unui applet este import java.applet.*; import java.awt.*; public classNumeClas a extends Applet{ public void init(){ Act iuni efectuate la instant ierea clasei applet-ului. } public void start(){ Act iuni efectuate la lansarea applet-ului n execut ie sau la re ntoarcerea n pagina applet-ului. } public void paint(Graphics g){ Act iuni efectuate ori de c ate ori este necesar a redesenarea ferestrei applet-ului. } public void stop(){ Act iuni efectuate la oprirea applet-ului, ca urmare a nchiderii ferestrei corespunz atoare applet-ului. } public void destroy(){ Act iuni efectuate la distrugerea applet-ului, ce au loc c and navigatorul p ar ase ste documentul html din care s-a apelat applet-ul. } } Executarea applet-ului este controlat de programul navigator si revine la apelarea metodelor init, start, stop. Acest fenomen se nume ste inversarea controlului.
155
7.2
Prin desf a surarea (deployment) unei aplicat ii se nt elege realizarea structurilor de cataloage si siere dar si a operat iilor care trebuie ntreprinse n vederea funct ion arii unei aplicat ii distribuite. Desf a surarea unui applet se poate face n mai multe feluri: Varianta 1 1. Arhivarea sierelor class ale applet-ului. 2. Certicarea arhivei jar se realizeaz a rul and succesiv (a) (b) (c)
keytool -genkey -keystore myKeystore -alias myself -dname "cn=XYZ, ou=cs, o=unitbv, l=brasov, c=RO" -keypass abc123 -storepass 123abc keytool -selfcert -alias myself -keystore myKeystore -keypass abc123 -storepass 123abc jarsigner -keystore myKeystore -keypass abc123 -storepass 123abc resursa.jar myself
keytool.exe si jarsigner.exe se g asesc n distribut ia jdk. Primele dou a act iuni au ca rezultat obt inerea certicatului myKeystore iar ultima act iune reprezint a nglobarea certic arii n arhiva resursa.jar. 3. Editarea sierului html de apelare a applet-ului. S ablonul specic apel arii applet-ului este
<BODY> . . . <script src="http://java.com/js/deployJava.js"></script> <script> var attributes={ code:numele_clasei_Applet, archive:numele_arhivei_jar,width:...,height:...}; var parameters={. . .}; var minimumVersion=1.6; deployJava.runApplet(attributes, parameters, minimumVersion); </script> . . . </BODY>
4. Cele dou a siere (arhiva jar, sierul html) se depun ntr-un catalog al unui server Web, asigur and vizibilitatea aplicat iei n Internet.
156
Vericarea aplicat iei se poate face, dintr-un program navigator, prin simpla apelare a sierului html. In acest caz, calculatorul trebuie s a e conectat la internet. Dac a dispunem de deployJava.js atunci acest sier se al atur a celorlalte dou a resurse, iar atributul src al elementului script va src="deployJava.js". Exemplul 7.2.1 Hello +nume. Numele se transmite miniaplicat iei ca parametru. Codul applet-ului este:
1 2 4 5 7 8 9 10 11
import j a v a . awt . ; import j a v a . a p p l e t . ; public c l a s s I n c e p u t extends Applet { public void i n i t ( ) { } public void p a i n t ( G r a p h i c s g ) { S t r i n g name=g e t P a r a m e t e r ( nume ) ; g . d r a w S t r i n g ( H e l l o +name+ ! ! , 5 0 , 60 ) ; } }
< ! doctype html> <head> <meta charset= u t f 8> </ head> <body> < s c r i p t src= h t t p : / / j a v a . com/ j s / d e p l o y J a v a . j s ></ s c r i p t> < s c r i p t> v a r a t t r i b u t e s = { code : I n c e p u t . c l a s s , a r c h i v e : i n c e p u t . j a r , width : 3 0 0 , h e i g h t : 3 0 0 } ; v a r p a r a m e t e r s={nume : XYZ } ; v a r minimumVersion = 1 . 6 . 0 ; d e p l o y J a v a . runApplet ( a t t r i b u t e s , p a r a m e t e r s , minimumVersion ) ; </ s c r i p t> </ body> </ html>
Varianta 2 Pe aceast a cale se va edita un sier de congurare cu extensia jnlp. Realizarea applet-ului const a din: 1. Arhivarea sierelor class ale applet-ului. 2. Certicarea arhivei jar. 3. Editarea unui sier de congurare jnlp. Structura acestui sier este
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 sierului html de apelare a applet-ului. S ablonul specic apel arii applet-ului este
<BODY> . . . <script src="http://java.com/js/deployJava.js"></script> <script> var attributes={code:numele_arhivei_jar,width:...,height:...}; var parameters={jnlp_href: cmmdc.jnlp}; var minimumVersion=1.6; deployJava.runApplet(attributes, parameters, minimumVersion); </script> . . . </BODY>
158
5. Cele trei siere (eventual patru cu deployJava.js ) se depun ntr-un catalog al unui server Web, asigur and vizibilitatea aplicat iei n Internet. Exemplul 7.2.2 Calculul celui mai mare divizor comun a dou a naturale. Introducerea datelor exterioare se face prin intermediul unei interfet e grace. Applet-ul extinz and clasa Applet are codul
1 2 3 5 6 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 28 29 30 31 32 33 34 35 37 38 39 41 42
import j a v a . awt . ; import j a v a . a p p l e t . ; import j a v a . awt . e v e n t . ; public c l a s s VisualCmmdc extends Applet implements A c t i o n L i s t e n e r { T e x t F i e l d tm , tn , r e z ; public void i n i t ( ) { setBackground ( Color . yellow ) ; GridLayout g l=new GridLayout ( 3 , 2 , 3 0 , 2 0 ) ; setLayout ( g l ) ; L a b e l lm=new L a b e l ( Primul numar : ) ; add ( lm ) ; tm=new T e x t F i e l d ( 1 , 5 ) ; add ( tm ) ; L a b e l l n=new L a b e l ( Al d o i l e a numar : ) ; add ( l n ) ; tn=new T e x t F i e l d ( 1 , 5 ) ; add ( tn ) ; Button compute=new Button ( C a l c u l e a z a ) ; compute . a d d A c t i o n L i s t e n e r ( t h i s ) ; add ( compute ) ; r e z=new T e x t F i e l d ( 1 , 5 ) ; rez . setEditable ( false ) ; add ( r e z ) ; } public void p a i n t ( G r a p h i c s g ) { S t r i n g sm=tm . g e t T e x t ( ) ; long m =Long . par se Lo ng ( sm ) ; S t r i n g sn=tn . g e t T e x t ( ) ; long n=Long . p ars eL ong ( sn ) ; long c=cmmdc(m, n ) ; r e z . s e t T e x t ( ( new Long ( c ) ) . t o S t r i n g ( ) ) ; } public void a c t i o n P e r f o r m e d ( ActionEvent ae ) { repaint ( ) ; } long cmmdc( long m, long n ) { . . . } }
159
6 7 8 9 10 11 12 13 15 16 18 19 20 21 22 23 24 25 26 27 28 29 31 32 33 34 35 37 38 39 40 42 43 44 45 47 48 49 50 51 52 53 54 55 56 57 58 59 61 62 63 64
. scene . control . TextField ; . s c e n e . c o n t r o l . Button ; . scene . paint . Color ; . e v e n t . ActionEvent ; . e v e n t . EventHandler ; . s c e n e . Group ; . s c e n e . Scene ; . s c e n e . l a y o u t . GridPane ;
public c l a s s VisualCmmdc extends JApplet { s t a t i c private T e x t F i e l d tm , tn , r e z ; public void i n i t ( ) { C o n t a i n e r c o n t e n t = getContentPane ( ) ; f i n a l JFXPanel f x P a n e l = new JFXPanel ( ) ; c o n t e n t . add ( f x P a n e l ) ; c o n t e n t . s e t V i s i b l e ( true ) ; P l a t f o r m . r u n L a t e r ( new Runnable ( ) { @Override public void run ( ) { initFX ( fxPanel ) ; } }); } private s t a t i c void i n i t F X ( JFXPanel f x P a n e l ) { Group r o o t = new Group ( ) ; Scene s c e n e = new Scene ( r o o t , 6 0 0 , 2 5 0 , C o l o r .LIGHTGREEN ) ; fxPanel . setScene ( scene ) ; GridPane g r i d P a n e = new GridPane ( ) ; L a b e l mLabel = new L a b e l ( Primul numar ) ; g r i d P a n e . add ( mLabel , 1 , 1 ) ; // column=1 row=1 tm=new T e x t F i e l d ( ) ; g r i d P a n e . add ( tm , 2 , 1 ) ; L a b e l nLabel = new L a b e l ( Al d o i l e a numar ) ; g r i d P a n e . add ( nLabel , 1 , 2 ) ; // column=1 row=1 tn=new T e x t F i e l d ( ) ; g r i d P a n e . add ( tn , 2 , 2 ) ; Button b ut to n = new Button ( C a l c u l e a z a ) ; bu tt on . se tO nA ct ion ( new EventHandler <ActionEvent > () { @Override public void h a n d l e ( ActionEvent e ) { S t r i n g sm = tm . g e t T e x t ( ) ; S t r i n g sn = tn . g e t T e x t ( ) ; long m =Long . par se Lo ng ( sm ) ; long n=Long . pa rs eL ong ( sn ) ; long r=cmmdc(m, n ) ; r e z . s e t T e x t ( ( new Long ( r ) ) . t o S t r i n g ( ) ) ; } }); g r i d P a n e . add ( button , 1 , 3 ) ; r e z = new T e x t F i e l d ( ) ; g r i d P a n e . add ( r e z , 2 , 3 ) ; r o o t . g e t C h i l d r e n ( ) . add ( g r i d P a n e ) ; fxPanel . setScene ( scene ) ;
160
}
65 67 68
<? xml version= 1 . 0 e n c o d i n g=UTF8 ?> < j n l p s p e c= 1.0+ c o d e b a s e= h r e f= > < i n f o r m a t i o n> < t i t l e > V i s u a l Cmmdc</ t i t l e > < vendor> T r a n s i l v a n i a U n i v e r s i t y o f Brasov</ vendor> </ i n f o r m a t i o n> < r e s o u r c e s> < ! A p p l i c a t i o n R e s o u r c e s > < j 2 s e version= 1.6+ h r e f= h t t p : // j a v a . sun . com/ p r o d u c t s / a u t o d l / j 2 s e maxheap s i z e= 128m /> < j a r h r e f=cmmdc . j a r main= t r u e /> </ r e s o u r c e s> < r e s o u r c e s o s=Windows> < j f x : j a v a f x r u n t i m e version= 2.0+ h r e f= h t t p : // j a v a d l . sun . com/ webapps / download / G e t F i l e / j a v a f x l a t e s t / windows i 5 8 6 / j a v a f x 2 . j n l p /> </ r e s o u r c e s> < s e c u r i t y> < a l l p e r m i s s i o n s /> </ s e c u r i t y > < a p p l e t d e s c name=VisualCmmdc Applet main c l a s s=VisualCmmdc width= 300 h e i g h t= 300 > </ a p p l e t d e s c> </ j n l p>
< ! d o c t y p e html> <head> <meta c h a r s e t= u t f 8> < 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 > </ head> <body> < c e n t e r> <h1> Cel mai mare d i v i z o r comun </ h1> < s c r i p t s r c= h t t p : // j a v a . com/ j s / d e p l o y J a v a . j s ></ s c r i p t > < s c r i p t> v a r a t t r i b u t e s = { c o d e : cmmdc , w i d t h : 3 0 0 , h e i g h t : 3 0 0 } ; v a r p a r a m e t e r s = { j n l p h r e f : cmmdc . j n l p } ; v a r minimumVersion= 1 . 6 ; d e p l o y J a v a . runApplet ( a t t r i b u t e s , p a r a m e t e r s , minimumVersion ) ; </ s c r i p t > </ c e n t e r> </ body> </ html>
161
7.3
Se pot apela funct ii JavaScript denite n documentul html din care se apeleaz a applet-ul. Prin intermediul unui obiect de tip netscape.javascript.JSObject, creat prin static JSObject getWindow(java.applet.Applet applet ) se apeleaz a metoda call(String numeFunct ieJavaScript, java.lang.Object[] args ). S ablonul de utilizare este import netscape.javascript.*; public void init(){ . . . JSObject window=JSObject.getWindow(null); window.call("numeFunctieJavaScript",args); . . . } Pachetul netscape.javascript se a a n distribut ia jdk n catalogul JAVA HOME\ jre\lib\plugin.jar. Pentru compilare, variabila de sistem classpath trebuie s a cont in a aceast a referint a .
162
8.1
Clasa java.net.URL
Clasa java.net.URL permite realizarea unei conexiuni cu un server Web1 potrivit protocolurilor http, https, ftp, le, jar. Constructori URL(String spec ) throws MalformedURLException Creaz a un obiect URL legat de resursa specicat a de spec, care trebuie s a e o referint a URL valid a. Metode InputStream openStream() throws IOException Returneaz a uxul de intrare pentru citirea resursei. URLConnection openConnection() throws IOException Returneaz a o instant a a conexiunii cu obiectul denit de URL.
1
163
164
Exemplul 8.1.1 Pe baza referint ei c atre un sier html dintr-un catalog vizibil al unui server Web, s a se a seze cont inutul sierului. In codul reprodus mai jos, sierul Hello.html se a a pe serverul apachetomcat, n catalogul webapps\url.
1 2 3 4 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
im po rt im po rt im po rt im po rt
p u b l i c c l a s s ReadHTTP{ p u b l i c s t a t i c v o i d main ( S t r i n g [ ] a r g s ) { S t r i n g adr= h t t p : // l o c a l h o s t : 8 0 8 0 / u r l / H e l l o . html ; // System . s e t P r o p e r t y ( h t t p . proxyHost , 1 0 . 3 . 5 . 1 3 3 ) ; // System . s e t P r o p e r t y ( h t t p . pr o x y P o r t , 3128 ) ; URL u r l=n u l l ; try { u r l=new URL( adr ) ; } catch ( Exception e ){ System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ; } try ( InputStream i n=u r l . openStream ( ) ; InputStreamReader i s r =new InputStreamReader ( i n ) ; B u f f e r e d R e a d e r br=new B u f f e r e d R e a d e r ( i s r ) ; ){ String s ; do { s=br . r e a d L i n e ( ) ; i f ( s != n u l l ) System . out . p r i n t l n ( s ) ; } w h i l e ( s != n u l l ) ; } catch ( Exception e ){ System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ; } } }
In cazul n care resursa - n exemplul dat reprezentat de sierul Hello.html - este accesibil doar n urma autentic arii basic sau digest (Cap. Servlet, Autenticare, 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()); } });
Capitolul 9 Servlet
Printre aplicat iile distribuite de tip client-server, n care comunicat iile se bazeaz a pe protocolul http, se disting: Aplicat ii Web (site): Cererea adresat a serverului este lansat a uzual de o persoan a utiliz and un program navigator: Google Chrome, Mozilla Firefox, Microsoft InternetExplorer, Opera, Apple Safari, etc. Servicii Web: Cererea c atre server se face de un program. Aplicat ia server si client se programeaz a utiliz and interfet e de programare specice. Un servlet este un program Java care se excut a pe un server Web, compatibil; gestionat de serverul Web; capabil s a recept ioneze si s a r apund a cererilor formulate de client i. De asemenea vom utiliza termenul servlet si pentru aplicat ia Web corespunz atoare. Pe platforma de programare Java, servlet-ul este componenta care st a la baza majorit a tii cadrelor de dezvoltare (framework ) pentru aplicat ii si servicii Web. Programarea si utilizarea unui servlet necesit a: Cunoa sterea marcajului html <form> pentru realizarea formularelor de introducere a datelor; Utilizarea unui server Web, container de servlet i. 165
166
CAPITOLUL 9. SERVLET
9.1
Marcajul <form>
Intr-un document html introducerea datelor se poate obt ine utiliz and marcajul <form> ...</form> . Atribute ale marcajului <form> . Reamintim c a atributele se prezint a ca perechi (nume, valoare) si se scriu n antetul marcajului sub forma nume = valoare. Nume action method Valoare adresa tip URL GET Semnicat ia valorii Resursa care prelucreaz a formularul. Mesajul trimis serverului Web cont ine dup a adresa URL numele si valorile parametrilor introdu si. Ad augarea se face potrivit sintaxei ?numeParam1=valoare&numeParam2=valoare. . . Lungimea mesajului nu poate dep a si 255 caractere. Transmisia datelor se face n uxuri de date. Permite transferul unor siere de pe ma sina clientului pe ma sina serverului. Parametru de identicare a formularului (opt ional). Nume atribuit formularului (opt ional). Metod a JavaScript executat a naintea apel arii serverului Web (opt ional).
POST
id name onSubmit
In cont inutul marcajului <form> putem include elemente de control prin marcajele <input> <option> <select> <textarea> Atributele marcajului < input> sunt:
167
Nume type
Valoare Semnicat ie text Se a steapt a introducerea unui text password Se a steapt a introducerea unei parole submit Se marcheaz a sf ar situl complet arii formularului reset Se reinit ializeaz a formularul file Permite selectarea unui sier hidden Transmite mai departe un atribut f ar a vizualizarea lui name numele controlului value valoarea (init ial a) a controlului size num arul caracterelor ata sat controlului In cazul marcajului < select> utilizarea este <select name="nume"> <option value="valoare"> Valoare . . . . . . . . . . . . . . . . </select> Valoarea atributului nume este dat a de valoarea selectat a.
9.2
Interfat a de programare (API) pentru servlet nu face parte din JDK, ind implementat de ecare produc ator de server Web container de servlet. Structura minimal a a unui servlet este catalogAppServlet |--> WEB-INF | |--> classes | | | *.class | |--> lib | | | *.jar | index.html Catalogul classes cont ine sierele class ale aplicat iei servlet. Catalogul lib este opt ional si va cont ine resursele jar suplimentare cerute de clasele servlet-ului. Prin intermediul sierului index.html se apeleaz a aplicat ia servlet. Adresa de apelare (URL - Universal Resource Locator ) a aplicat iei servlet este http://host:port/catalogAppServlet
168
CAPITOLUL 9. SERVLET
Dac a n loc de index sierul html de apelare are alt nume, de exemplu xyz.html atunci adresa de apelare va http://host:port/catalogAppServlet/xyz.html host este numele calculatorului pe care ruleaz a serverul Web - gazda aplicat iei servlet. Portul implicit utilizat de un server Web container de servlet este 8080. Catalogul aplicat iei este denumit context -ul servlet-ului. Apelarea servlet-ului se poate face: din meniul File/Open al unui navigator; ca referint a ntr-un document html <a href="URL-servlet ">...</a> Din documentul html pomenit anterior, apelarea clasei servlet se face uzual prin intermediul atributului action a elementului form. Valoarea atributului este numele de apel al servlet-ului. Prin Asynchronous JavaScript And Xml - AJAX un servlet se poate apela dintr-o funct ie Javascript. Leg atura cu clasa servlet-ului se poate realiza programat prin adnot ari n codul servlet-ului; descriptiv n catalogul WEB-INF se editeaz a sierul web.xml. In versiunile anterioare ale interfet ei de programare servlet aceasta a fost unica opt iune. Trebuie demarcat a diferent a dintre apelarea / lansarea n execut ie a clasei servlet de apelarea aplicat iei Web. Modul programat se bazeaz a pe adnotarea javax.servlet.annotation. WebServlet cu elementele: String name String[ ] urlPatterns @WebInitParams[ ] initParams boolean asyncSupported long asyncTimeout Modul descriptiv In sierul web.xml apar elementele
169
1. <servlet> leag a numele servlet-ului denit n elementul <servlet-name> de clasa servlet-ului dat n elementul <servlet-class> . 2. <servlet-mapping> dene ste numele sub care servlet-ul identicat prin <servlet-name>nume servlet < /servlet-name> se invoc a din programul navigator. Acest identicator - numeApel - se xeaz a n elementul <url-pattern> . Identicatorul are ca prex caracterul / (slash). Structura unui sier web.xml este
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
<? xml version= 1 . 0 e n c o d i n g=UTF8 ?> <webapp version= 3 . 0 xmlns= h t t p : // j a v a . sun . com/xml/ ns / j a v a e e x m l n s : x s i= h t t p : //www. w3 . o r g /2001/XMLSchema i n s t a n c e > < s e r v l e t> < s e r v l e t name> n u m e s e r v l e t 1</ s e r v l e t name> < s e r v l e t c l a s s >Nume clasa</ s e r v l e t c l a s s > </ s e r v l e t > < s e r v l e t> < s e r v l e t name> n u m e s e r v l e t 2</ s e r v l e t name> < s e r v l e t c l a s s >Nume clasa</ s e r v l e t c l a s s > </ s e r v l e t > . . . < s e r v l e t mapping> < s e r v l e t name> n u m e s e r v l e t 1</ s e r v l e t name> < u r l p a t t e r n>/ numeApel 1</ u r l p a t t e r n> </ s e r v l e t mapping> < s e r v l e t mapping> < s e r v l e t name> n u m e s e r v l e t 2</ s e r v l e t name> < u r l p a t t e r n>/ numeApel 2</ u r l p a t t e r n> </ s e r v l e t mapping> . . . </webapp>
Unui element <servlet> i pot corespunde mai multe elemente <servlet-mapping>, prin utilizarea de numeApel diferite. Opt ional web.xml poate cont ine elementul
<welcome-file-list> <welcome-file> fisier.html sau jsp </welcome-file> </welcome-file-list>
cu precizarea sierelor html sau jsp care apeleaz a aplicat ia Web. Declarat ia sierului index.html este implicit a. Compilarea clasei servlet necesit a completarea variabilei de mediu classpath cu sierul TOMCAT HOME\lib\servlet-api.jar. Odat a completat a structura de cataloage si siere ale aplicat iei servlet aceast a structur a trebuie copiat a n catalogul TOMCAT HOME\webapps. Aceast a operat ie se nume ste desf a surarea (deployment ) sau instalarea servlet-ului. Copierea se poate executa si cu serverul Web pornit. Pentru instalarea unui servlet exist a mai multe alternative:
170
CAPITOLUL 9. SERVLET
Din catalogul catalogAppServlet se realizeaz a arhiva catalogAppServlet.war jar cfv catAppServlet.war WEB-INF\ index.html care se copiaz a n catalogul TOMCAT HOME\webapps. Serverul Web tomcat va dezarhiveaza arhiva. Astfel servlet-ul este instalat. Aceast a instalare se nume ste instalare dinamic a - hot deployment. Dac a sierul war este creat, atunci n locul copierii, instalarea se poate face prin componenta manager a lui tomcat. O aplicat ie servlet arhivat a war se poate instala de la distat a prin produsele: apache-tomcat-deployer cargo
9.2.1
Un servlet implementeaz a interfat a Servlet sau extinde una din clasele GenericServlet sau HttpServlet. GenericServlet implementeaz a interfat a Servlet, iar HttpServlet extinde clasa GenericServlet. Extinz and clasa GenericServlet nu este nevoie de rescrierea tuturor metodelor abstracte ale interfet ei Servlet. Metodele interfet ei Servlet sunt: abstract public void init(ServletConfig cong ) Se apeleaz a o singur a dat a la lansarea servlet-ului. abstract public void service(ServletRequest req, ServletResponse res )throws ServletException,IOException Metoda este apelat a de serverul Web pentru rezolvarea cererii unui client. abstract public void destroy() Se apeleaz a o singur a dat a la distrugerea servlet-ului. public String getServletInfo() public ServletConfig getServletConfig()
171
In cele ce urmeaz a o clasa servlet va o clas a care extinde clasa HttpServlet. In locul metodei service(...), programatorul suprascrie metodele doGet(...) sau doPost(...), n funct ie de metoda utilizat a de client la lansarea cererii. Practic, un servlet const a din scrierea metodelor void init(ServletConfig cong ) Aceast a metod a este opt ional a. public void init(ServletConfig config) throws ServletException{ super.init(config); // cod de initializare } Obiectul cong are o metod a String getInitParameter(String numeParam ) cu ajutorul c areia se pot recupera parametri de initializare asociat i servlet-ului si care se dau e prin adnotarea WebInitParam prin sablonul import javax.servlet.annotation.WebInitParam; @WebServlet(urlPatterns = "/numeApel", initParams = { @WebInitParam(name = "numeParam", value = "valoareParam"), . . . } ) e n sierul web.xml prin elementele <init-param> <param-name> NumeleParametrului </param-name> <param-value> Valoare </param-value> </init-param> cuprinse n elementul <servlet>. protected void doGet(HttpServletRequest req, HttpServletResponse res ) throws IOException, ServletException Trateaz a o cerere trimis a cu metoda GET (vezi marcajul <form>).
172
CAPITOLUL 9. SERVLET
protected void doPost(HttpServletRequest req, HttpServletResponse res ) throws IOException, ServletException Trateaz a o cerere trimis a cu metoda POST (vezi marcajul <form>). Activit a tile de ntreprins ntr-o metod a doGet() sau doPost() sunt 1. Stabilirea naturii r aspunsului: res.setContentType(String tip ) unde tip specic a tipul MIME - Multipurpose Internet Mail Extensions al r aspunsului: "text/html" - pagin a html; "text/xml" - document xml; "text/plain" - text; "image/jpg" - imagine jpg; "image/gif" - imagine gif. 2. Se obt ine o referint a c atre un obiect care realizeaz a transmisia datelor c atre navigatorul clientului: ServletOutputStream out = res.getOutputStream(); sau PrintWriter out=res.getWriter(); 3. Se preiau datele cererii cu una din metodele interfet ei HttpServletRequest: String getParameter(String numeParametru ) java.util.Enumeration getParameterNames() Adit ional se pot aa calculatorul cu serverul web: getServerName(); portul: getServerPort(); catalogul servlet-ului: getContextPath(). 4. Rezolv a cererea clientului; 5. Formeaz a si scrie r aspunsul; 6. Inchide conexiunea obiectului prin care s-a realizat transmisia datelor c atre navigatorul clientului prin out.close().
173
Un c amp (global) declarat n clasa servletului este comun ec arei instant e a servletului. Un utilizator lanseaz a o cerere c atre servlet. De obicei acest lucru se realizeaz a prin completarea unui formular al unui document html. Programul navigator trimite cererea serverului Web prin intermediul c aruia este lansat servlet-ul n act iune. Ciclul de viat a al unui servlet. C and un servlet este apelat prima dat a de c atre serverul Web se execut a metoda init. Dup a aceasta, ec arei cereri lansate de un utilizator i se asociaz a un r de execut ie n care se apeleaz a metoda service. Metoda service apeleaz a apoi metodele doGet(), doPost(). Exemplul 9.2.1 Servlet-ul Hello: Clientul transmite numele servlet-ului care i r aspunde cu mesajul de salut Hi + nume!. Formularul html prin care clientul introduce numele este (index.html )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
< ! doctype html> <head> <meta charset= u t f 8> < l i n k r e l = s t y l e s h e e t href= mycss . c s s > </ head> <body> <center> <h1> Pagina de a p e l a r e a s e r v l e t u l u i H e l l o S e r v l e t </ h1> <form method= p o s t action= h e l l o > <table> < tr> <td>< l a b e l> I n t r o d u c e t i numele </ l a b e l></ td> <td> <input type= t e x t name=name s i z e= 20 > </ td> </ tr> < tr> <td> <input type= submit value= C a l c u l e a z a > </ td> </ tr> </ table> <input type= h id de n name= t i p value= t e x t / html > </ form> </ center> </ body> </ html>
174
CAPITOLUL 9. SERVLET
5 6 7 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 28 29 30 31 32
import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t R e s p o n s e ; import j a v a x . s e r v l e t . S e r v l e t O u t p u t S t r e a m ; import j a v a x . s e r v l e t . a n n o t a t i o n . WebServlet ; @WebServlet ( u r l P a t t e r n s = / h e l l o ) public c l a s s H e l l o S e r v l e t extends H t t p S e r v l e t { public void doGet ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { r e s . setContentType ( t e x t / html ) ; S e r v l e t O u t p u t S t r e a m out=r e s . getOutputStream ( ) ; S t r i n g nume=r e q . g e t P a r a m e t e r ( name ) ; out . p r i n t l n ( <html> ) ; out . p r i n t l n ( <head>< t i t l e > H e l l o S e r v l e t </ t i t l e ></head> ) ; out . p r i n t l n ( <body> ) ; out . p r i n t l n ( <h1> H e l l o S e r v l e t </h1> ) ; out . p r i n t l n ( <p> ) ; out . p r i n t l n ( Hi + nume+ ! ) ; out . p r i n t l n ( </p> ) ; out . p r i n t l n ( </body> ) ; out . p r i n t l n ( </html> ) ; out . c l o s e ( ) ; } public void doPost ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { doGet ( req , r e s ) ; } }
<? xml version= 1 . 0 e n c o d i n g=UTF8 ?> <webapp version= 3 . 0 xmlns= h t t p : // j a v a . sun . com/xml/ ns / j a v a e e x m l n s : x s i= h t t p : //www. w3 . o r g /2001/XMLSchema i n s t a n c e > < s e r v l e t> < s e r v l e t name> h e l l o </ s e r v l e t name> < s e r v l e t c l a s s > H e l l o S e r v l e t </ s e r v l e t c l a s s > </ s e r v l e t > < s e r v l e t mapping> < s e r v l e t name> h e l l o </ s e r v l e t name> < u r l p a t t e r n>/ h e l l o </ u r l p a t t e r n> </ s e r v l e t mapping> </webapp>
Compilarea si arhivarea servlet-ului o vom realiza prin intermediul lui apache-ant. In acest scop se creaz a structura:
hello | |---> src | | | HelloServlet.java | |---> web | | |---> WEB-INF | | | |---> classes | | | |---> lib | | | | web.xml | | | index.html | build.xml
175
< p r o j e c t b a s e d i r= . default= g e n e r a t e . war > < p r o p e r t y name=TOMCAT HOME v a l u e= . . . /> < p r o p e r t y name= d i s t . name v a l u e= a p p h e l l o P /> < p r o p e r t y name= d i s t . d i r v a l u e= d i s t /> <path i d= m y c l a s s p a t h > < f i l e s e t d i r=web/WEB INF/ l i b > < i n c l u d e name= . j a r /> </ f i l e s e t > < p a t h e l e m e n t path= $ {TOMCAT HOME} / l i b / s e r v l e t a p i . j a r /> </ path> < t a r g e t name= i n i t > < d e l e t e d i r= $ { d i s t . d i r } /> < d e l e t e d i r=web/WEB INF/ c l a s s e s /> <mkdir d i r=web/WEB INF/ c l a s s e s /> <mkdir d i r= $ { d i s t . d i r } /> </ t a r g e t> < t a r g e t name= c o m p i l e depends= i n i t > < j a v a c c l a s s p a t h r e f= m y c l a s s p a t h i n c l u d e a n t r u n t i m e= f a l s e s r c d i r= $ { b a s e d i r } / s r c d e s t d i r=web/WEB INF/ c l a s s e s /> </ t a r g e t> < t a r g e t name= g e n e r a t e . war depends= c o m p i l e > < j a r d e s t f i l e = $ { d i s t . d i r } /$ { d i s t . name } . war b a s e d i r=web /> </ t a r g e t> </ p r o j e c t>
Observat ie. Valoarea parametrului dist.name dene ste parametrul catalogAppServlet. Se lanseaz a n execut ie serverul Web tomcat, se ncarc a servlet-ul n serverul Web si dintr-un navigator se deschide pagina http://localhost:8080/apphello Exemplul 9.2.2 Servlet pentru calculul celui mai mare divizor comun a dou a numere.
1 2 3 4 5 6 7 9 10 12 14
j a v a . i o . IOException ; java . io . PrintWriter ; javax . s e r v l e t . ServletException ; javax . s e r v l e t . http . HttpServlet ; javax . s e r v l e t . http . HttpServletRequest ; javax . s e r v l e t . http . HttpServletResponse ; j a v a x . s e r v l e t . a n n o t a t i o n . WebServlet ;
@WebServlet ( u r l P a t t e r n s = /cmmdc ) public c l a s s CmmdcServlet extends H t t p S e r v l e t { public long cmmdc( long m, long n ) { . . . } public void doGet ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s )
176
CAPITOLUL 9. SERVLET
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 38 39 40 41 42
throws S e r v l e t E x c e p t i o n , IOException { S t r i n g sm=r e q . g e t P a r a m e t e r ( m ) , sn=r e q . g e t P a r a m e t e r ( n ) ; S t r i n g t i p=r e q . g e t P a r a m e t e r ( t i p ) ; long m =Long . par se Lo ng ( sm ) , n=Long . par se Lo ng ( sn ) ; long x=cmmdc(m, n ) ; P r i n t W r i t e r out=r e s . g e t W r i t e r ( ) ; i f ( t i p . e q u a l s ( t e x t / html ) ) { S t r i n g t i t l e = CmmdcServlet ; r e s . setContentType ( t e x t / html ) ; out . p r i n t l n ( <HTML ><HEAD ><TITLE> ) ; out . p r i n t l n ( t i t l e ) ; out . p r i n t l n ( </TITLE></HEAD >< BODY > ) ; out . p r i n t l n ( <H1>+ t i t l e +</H1> ) ; out . p r i n t l n ( <P>Cmmdc i s +x ) ; out . p r i n t l n ( </BODY ></HTML > ) ; } else { r e s . setContentType ( t e x t / p l a i n ) ; out . p r i n t l n ( x ) ; } out . c l o s e ( ) ; } public void doPost ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { doGet ( req , r e s ) ; } }
< ! doctype html> <head> <meta charset= u t f 8> < l i n k r e l = s t y l e s h e e t href= mycss . c s s > </ head> <body> <center> <h1> Pagina de a p e l a r e CmmdcServlet </ h1> <form method= g e t action=cmmdc> <table> < tr> <td>< l a b e l> Primul numar </ l a b e l></ td> <td> <input type= t e x t name=m s i z e= 5 r e q u i r e d p a t t e r n= [ 0 9 ] { 1 , } > </ td> </ tr> < tr> <td>< l a b e l> Al d o i l e a numar </ l a b e l></ td> <td> <input type= t e x t name=n s i z e= 5 r e q u i r e d p a t t e r n= [ 0 9 ] { 1 , } > </ td> </ tr> < tr> <td> <p><input type= submit value= C a l c u l e a z a >
177
29 30 31 32 33 34 35 36
</ td> </ tr> </ table> <input type= h id de n name= t i p value= t e x t / html > </ form> <center> </ body> </ html>
Pentru xarea naturii r aspunsului text/html sau text/plain s-a introdus variabila tip, care n sierul de invocare index.html prime ste pe ascuns valoarea text/html. In cazul n care vom apela servlet-ul dintr-un program, va avantajos s a primim r aspunsul ca text/plain.
9.3
Rezolvarea unei cereri adresat de un client unui servlet (metoda doGet / doPost) se execut a de c atre serverul Web ntr-un r de execut ie. Aceast a execut ie este sincron a n sensul n care trecerea la instruct iunea urm atoare are loc doar la ncheierea execut iei instruct iunii curente. Firul de execut ie este creat si lansat de serverul Web. Interfat a de programare Servlet 3.0 ofer a posibilitatea unui execut ii asincrone: satisfacerea cererii clientului se face ntr-un r de execut ie lansat de clasa servlet-ului. Terminarea activit a tii clasei servlet nu mai este legat a de rezolvarea cererii clientului si de trimiterea r aspunsului. Acest mod de execut ie se indic a prin adnotarea @WebServlet(urlPaterns="/numeApel " ,asyncSupported=true) Suportul asincron necesit a un context, obiect de tip AsyncContext AsyncContext asyncCtx=req.startAsync(req,res); Activit a tile ce trebuie ndeplinite pentru satisfacerea cererii clientului se lanseaz a ntr-un r de execut ie, obiect care este parte a unei familii gestionate de o clas a ce implementeaz a interfat a Executor: public ScheduledThreadPoolExecutor(int corePoolSize ) public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue ) Interfat a AsyncListener permite noticarea evenimentelor void onComplete(AsyncEvent ae ) void onTimeout(AsyncEvent ae )
CAPITOLUL 9. SERVLET
Obiectul de tip AsyncEvent este creat n momentul satisfacerii cererii clientului, dep a sirii timpului alocat sau producerii unei erori. Exemplul 9.3.1 Varianta asincron a a servlet-ului de calcul a celui mare divizor comun.
1 2 3 4 5 6 7 8 9 10 11 13 14 15 16 17 18 19 20 21 23 24 25 26 27
package m y s e r v l e t ; import j a v a x . s e r v l e t . S e r v l e t E x c e p t i o n ; import j a v a x . s e r v l e t . AsyncContext ; import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t ; import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t R e q u e s t ; import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t R e s p o n s e ; import j a v a x . s e r v l e t . a n n o t a t i o n . WebServlet ; import j a v a . u t i l . c o n c u r r e n t . E x e c u t o r ; import j a v a . u t i l . c o n c u r r e n t . S c h e d u l e d T h r e a d P o o l E x e c u t o r ; import j a v a . i o . IOException ; import l i s t e n e r s . MyAsyncListener ; @WebServlet ( u r l P a t t e r n s= /cmmdc , a s y n c S u p p o r t e d=true ) public c l a s s A s y n c S e r v l e t extends H t t p S e r v l e t { public void doGet ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { AsyncContext asyncCtx=r e q . s t a r t A s y n c ( req , r e s ) ; asyncCtx . a d d L i s t e n e r ( new MyAsyncListener ( ) ) ; E x e c u t o r e x e c u t o r=new S c h e d u l e d T h r e a d P o o l E x e c u t o r ( 1 0 ) ; e x e c u t o r . e x e c u t e ( new AsyncWebService ( asyncCtx ) ) ; } public void doPost ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { doGet ( req , r e s ) ; } }
package m y s e r v l e t ; import j a v a x . s e r v l e t . S e r v l e t R e q u e s t ; import j a v a x . s e r v l e t . S e r v l e t R e s p o n s e ; import j a v a x . s e r v l e t . AsyncContext ; import j a v a . i o . IOException ; import j a v a . i o . P r i n t W r i t e r ; public c l a s s AsyncWebService implements Runnable { AsyncContext asyncCtx ; public AsyncWebService ( AsyncContext asyncCtx ) { t h i s . asyncCtx=asyncCtx ; } public void run ( ) {
179
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 40 41
S e r v l e t R e q u e s t r e q=asyncCtx . g e t R e q u e s t ( ) ; S e r v l e t R e s p o n s e r e s=asyncCtx . g e t R e s p o n s e ( ) ; S t r i n g sm=r e q . g e t P a r a m e t e r ( m ) ; S t r i n g sn=r e q . g e t P a r a m e t e r ( n ) ; long m =Long . par se Lo ng ( sm ) , n=Long . par se Lo ng ( sn ) ; long x=cmmdc(m, n ) ; S t r i n g r e s u l t=new Long ( x ) . t o S t r i n g ( ) ; try { P r i n t W r i t e r out=r e s . g e t W r i t e r ( ) ; S t r i n g t i t l e =Cmmdc S e r v l e t ; r e s . setContentType ( t e x t / html ) ; out . p r i n t l n ( <HTML ><HEAD ><TITLE> ) ; out . p r i n t l n ( t i t l e ) ; out . p r i n t l n ( </TITLE></HEAD >< BODY > ) ; out . p r i n t l n ( <H1>+ t i t l e +</H1> ) ; out . p r i n t l n ( <P>Cmmdc i s +x ) ; out . p r i n t l n ( </BODY ></HTML > ) ; out . c l o s e ( ) ; } catch ( IOException e ) { System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ; } } public long cmmdc( long m, long n ) { . . . } }
package l i s t e n e r s ; import j a v a x . s e r v l e t . AsyncEvent ; import j a v a x . s e r v l e t . A s y n c L i s t e n e r ; import j a v a x . s e r v l e t . S e r v l e t R e q u e s t ; public c l a s s MyAsyncListener implements A s y n c L i s t e n e r { public MyAsyncListener ( ) { } public void onComplete ( AsyncEvent ae ) { S e r v l e t R e q u e s t r e q=ae . getAsyncContext ( ) . g e t R e q u e s t ( ) ; S t r i n g r=r e q . g e t P a r a m e t e r ( m)+ <> +r e q . g e t P a r a m e t e r ( n ) ; System . out . p r i n t l n ( A s y n c L i s t e n e r : onComplete f o r r e q u e s t : +r ) ; } public void onTimeout ( AsyncEvent ae ) { S e r v l e t R e q u e s t r e q=ae . getAsyncContext ( ) . g e t R e q u e s t ( ) ; S t r i n g r=r e q . g e t P a r a m e t e r ( m)+ <> +r e q . g e t P a r a m e t e r ( n ) ; System . out . p r i n t l n ( A s y n c L i s t e n e r : onTimeout f o r r e q u e s t : +r ) ; } public void o n E r r o r ( AsyncEvent ae ) { S e r v l e t R e q u e s t r e q=ae . getAsyncContext ( ) . g e t R e q u e s t ( ) ; S t r i n g r=r e q . g e t P a r a m e t e r ( m)+ <> +r e q . g e t P a r a m e t e r ( n ) ; System . out . p r i n t l n ( A s y n c L i s t e n e r : o n E r r o r f o r r e q u e s t : +r ) ; } public void o n S t a r t A s y n c ( AsyncEvent ae ) { S e r v l e t R e q u e s t r e q=ae . getAsyncContext ( ) . g e t R e q u e s t ( ) ; S t r i n g r=r e q . g e t P a r a m e t e r ( m)+ <> +r e q . g e t P a r a m e t e r ( n ) ;
180
CAPITOLUL 9. SERVLET
31 32 33
System . out . p r i n t l n ( A s y n c L i s t e n e r : o n S t a r t A s y n c f o r r e q u e s t : +r ) ; } }
9.4
9.4.1
Diferent a major a const a n faptul c a solicitarea clientului este trimis a nemijlocit si ndeplinit a de o clas a tip listener. Clasa javax.servlet.ServletInputStream Metode public int readLine(byte[] b, int o, int len ) throws IOException public void setReadListener(ReadListenerreadListener ) Interfat a javax.servlet.ReadListener declar a metodele void onDataAvailable() throws IOException void onAllDataRead() throws IOException) void onError(Throwable t) Exemplul 9.4.1
1 2 3 4 5 6 7 8 9 10 12 13 14 15 16 17 18
import import import import import import import import import import
j a v a . i o . IOException ; java . io . PrintWriter ; j a v a . n e t .URL; j a v a x . s e r v l e t . AsyncContext ; javax . s e r v l e t . ServletException ; javax . s e r v l e t . ServletInputStream ; j a v a x . s e r v l e t . a n n o t a t i o n . WebServlet ; javax . s e r v l e t . http . HttpServlet ; javax . s e r v l e t . http . HttpServletRequest ; javax . s e r v l e t . http . HttpServletResponse ;
@WebServlet ( u r l P a t t e r n s = { / n o n b l o c k } , a s y n c S u p p o r t e d=true ) public c l a s s N o n B l o c k i n g S e r v l e t extends H t t p S e r v l e t { protected void doGet ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { r e s . setContentType ( t e x t / html ; c h a r s e t=UTF8 ) ; try ( P r i n t W r i t e r ou tp ut = r e s . g e t W r i t e r ( ) ) { ou tp ut . p r i n t l n ( <html> ) ;
181
19 20 21 23 24 25 26 27 28 29 31 32 33 34 35 36
ou tp ut . p r i n t l n ( <body> ) ; ou tp ut . p r i n t l n ( <h1> S e r v l e t N o n B l o c k i n g S e r v l e t a t + r e q . g e t C o n t e x t P a t h ( ) + </h1> ) ; AsyncContext c o n t e x t = r e q . s t a r t A s y n c ( ) ; ServletInputStream input = req . getInputStream ( ) ; i n p u t . s e t R e a d L i s t e n e r ( new CmmdcListener ( i n p u t , c o n t e x t , ou tp ut ) ) ; ou tp ut . p r i n t l n ( </body> ) ; ou tp ut . p r i n t l n ( </html> ) ; } } @Override protected void doPost ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { doGet ( req , r e s ) ; } }
mpreun a cu
1 2 3 4 5 7 9 10 11 13 14 15 16 17 18 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
public c l a s s CmmdcListener implements R e a d L i s t e n e r { private S e r v l e t I n p u t S t r e a m i n p u t = n u l l ; private AsyncContext c o n t e x t = n u l l ; private P r i n t W r i t e r out = n u l l ; public CmmdcListener ( S e r v l e t I n p u t S t r e a m in , AsyncContext ac , P r i n t W r i t e r ou tp ut ) { input = in ; c o n t e x t = ac ; out = ou tp ut ; } @Override public void o n D a t a A v a i l a b l e ( ) { try { S t r i n g B u i l d e r sb = new S t r i n g B u i l d e r ( ) ; i n t l e n = 1; byte b [ ] = new byte [ 1 0 2 4 ] ; while ( i n p u t . i s R e a d y ( ) && ( l e n = i n p u t . r e a d ( b ) ) != 1) { S t r i n g data = new S t r i n g ( b , 0 , l e n ) ; out . w r i t e ( data ) ; out . w r i t e ( <p> ) ; S t r i n g r e z=s o l v e r ( data ) ; out . w r i t e ( r e z ) ; } } catch ( IOException e ) { System . out . p r i n t l n ( o n A v a i l a b l e E x c e p t i o n : +e . g e t M e s s a g e ( ) ) ; } }
182
CAPITOLUL 9. SERVLET
39 40 41 42 43 45 46 47 48 49 51 52 53 54 55 56 57 58 59 61 62
@Override public void onAllDataRead ( ) { System . out . p r i n t l n ( onAllDataRead ) ; context . complete ( ) ; } @Override public void o n E r r o r ( Throwable t ) { t . printStackTrace ( ) ; context . complete ( ) ; } private S t r i n g s o l v e r ( S t r i n g data ) { S t r i n g [ ] s=data . s p l i t ( & ) ; S t r i n g [ ] s 0=s [ 0 ] . s p l i t ( = ) ; long m =Long . par se Lo ng ( s 0 [ 1 ] ) ; S t r i n g [ ] s 1=s [ 1 ] . s p l i t ( = ) ; long n=Long . p ars eL ong ( s 1 [ 1 ] ) ; S t r i n g r =(new Long (cmmdc(m, n ) ) ) . t o S t r i n g ( ) ; return Cmmdc : +r ; } private long cmmdc( long m, long n ) { . . . } }
9.4.2
Schema este utilizat a deja pentru utilizarea protocolului websocket. In apelul http trebuie inserat antetul (header ) Upgrade. Odat a aceast antet recunoscut, solicitarea clientului este rezolvat a ntr-o clas a care implementeaz a interfat a javax.servlet.http.HttpUpgradeHandler. Interfat a declar a metodele void init(WebConnection wc ) void destroy() Interfat a javax.servlet.http.WebConnection Metode ServletInputStream getInputStream() throws IOException ServletOutputStream getOutputStream() throws IOException Clasa care implementeaz a interfat a HttpUpgradeHandler se declar a n servlet prin metoda interfet ei HttpServletRequest <T extends HttpUpgradeHandler> T upgrade(Class<T> handlerClass ) throws IOException, ServletException In principiu clasa servlet-ului este independent a de specicul aplicat iei.
183
1 2 3 4 5 7 9 11 12 13 14 15 16 17 18 19 20 21 22 23 24 26 27 28 29 30
@WebServlet ( u r l P a t t e r n s = { / upgrade } ) public c l a s s U p g r a d e S e r v l e t extends H t t p S e r v l e t { public void doGet ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { i f ( upgrade . e q u a l s ( r e q . g e t H e a d e r ( Upgrade ) ) ) { res . setStatus (101); r e s . s e t H e a d e r ( Upgrade , upgrade ) ; r e s . s e t H e a d e r ( C o n n e c t i o n , Upgrade ) ; res . flushBuffer () ; System . out . p r i n t l n ( Upgrade OK +r e q . g e t H e a d e r ( Upgrade ) ) ; MyHttpUpgradeHandler h a n d l e r = r e q . upgrade ( MyHttpUpgradeHandler . c l a s s ) ; } else { System . out . p r i n t l n ( No upgrade : ) ; } } public void doPost ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { doGet ( req , r e s ) ; } }
Problema care r am ane de rezolvat este inserarea antetului Update. Rezolvarea consta n generarea unui mesaj http care se va transmite printr-un soclu TCP. Mesajul http folose ste metoda post, iar datele din corpul mesajului sunt preluate prin interfat a HttpInputStream. Pentru problema calculului celui mai mare divizor comun a dou a numere naturale clasa MyHttpUpgradeHandler este
1 2 3 4 6 7 9 10 11 12 13 14 15 16 17 18 19
public c l a s s MyHttpUpgradeHandler implements HttpUpgradeHandler { private WebConnection wc = n u l l ; @Override public void i n i t ( WebConnection wc ) { t h i s . wc=wc ; try { S e r v l e t I n p u t S t r e a m i n p u t = wc . g e t I n p u t S t r e a m ( ) ; S e r v l e t O u t p u t S t r e a m o ut pu t=wc . getOutputStream ( ) ; S t r i n g CRLF = \ r \ n ; S t r i n g r e s S t r = update / 1 . 0 + CRLF ; r e s S t r += S e r v e r : G l a s s f i s h / S e r v e r T e s t + CRLF ; r e s S t r += Content Type : t e x t / html + CRLF ; r e s S t r += C o n n e c t i o n : Upgrade + CRLF ;
184
CAPITOLUL 9. SERVLET
20 21 22 23 24 25 26 27 28 29 30 31 32 34 35 36 37 38 39 40 41 42 44 45 46 47 48 49 50 51 52 53 54 55 56 57 59 60
r e s S t r += CRLF ; byte [ ] b=new byte [ 2 5 6 ] ; input . read (b ) ; S t r i n g data=new S t r i n g ( b ) . t r i m ( ) ; S t r i n g r e z=s o l v e r ( data ) ; r e s S t r +=r e z + CRLF ; ou tp ut . w r i t e ( r e s S t r . g e t B y t e s ( ) ) ; ou tp ut . f l u s h ( ) ; } catch ( E x c e p t i o n ex ) { throw new RuntimeException ( ex ) ; } } @Override public void d e s t r o y ( ) { try { wc . c l o s e ( ) ; } catch ( E x c e p t i o n ex ) { System . out . p r i n t l n ( D e s t r o y wc E x c e p t i o n : +ex . g e t M e s s a g e ( ) ) ; } } private S t r i n g s o l v e r ( S t r i n g data ) { System . out . p r i n t l n ( S o l v e r : +data ) ; S t r i n g [ ] s=data . s p l i t ( ) ; S t r i n g r=1 ; try { long m =Long . par se Lo ng ( s [ 0 ] ) ; long n=Long . pa rs eL ong ( s [ 1 ] ) ; r =(new Long (cmmdc(m, n ) ) ) . t o S t r i n g ( ) ; } catch ( NumberFormatException e ) { System . out . p r i n t l n ( NumberFormatException : +e . g e t M e s s a g e ( ) ) ; } return Cmmdc : +r ; } private long cmmdc( long m, long n ) { . . . } }
iar lansarea aplicat iei se face dintr-un program client, n care se genereaz a mesajul http cu anterul Upgrade, mesaj expediat printr-un soclu TCP. Client Java
1 2 3 4 5 6 7 9 10 11 12
java . net . Socket ; j a v a . i o . InputStream ; j a v a . i o . OutputStream ; j a v a . i o . InputStreamReader ; java . i o . BufferedReader ; j a v a . i o . IOException ; java . u t i l . Scanner ;
185
13 14 15 16 17 18 19 20 21 23 24 25 26 27 28 29 30 31 32 33 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
long m =s c a n n e r . nextLong ( ) ; S t r i n g sm=new Long (m) . t o S t r i n g ( ) ; System . out . p r i n t l n ( n= ) ; long n=s c a n n e r . nextLong ( ) ; S t r i n g sn=new Long ( n ) . t o S t r i n g ( ) ; S t r i n g data=sm+ +sn ; S t r i n g h o s t= l o c a l h o s t ; S t r i n g p o r t= 8080 ; S t r i n g c o n t e x t R o o t= / upgrade ; S t r i n g CRLF = \ r \ n ; S t r i n g r e q S t r = POST + c o n t e x t R o o t + / upgrade HTTP/ 1 . 1 + CRLF ; r e q S t r += User Agent : Java / 1 . 7 + CRLF ; r e q S t r += Host : + h o s t + : + p o r t + CRLF ; r e q S t r += Accept : t e x t / html , image / g i f , image / j p e g , ; q = . 2 , / ; q =.2 + CRLF ; r e q S t r += Upgrade : upgrade + CRLF ; r e q S t r += C o n n e c t i o n : Upgrade + CRLF ; r e q S t r += Content t y p e : a p p l i c a t i o n /xwww form u r l e n c o d e d + CRLF ; r e q S t r += T r a n s f e r Encoding : chunked + CRLF ; r e q S t r += CRLF ; r e q S t r += data + CRLF ; S o c k e t s o c k e t=n u l l ; try { s o c k e t=new S o c k e t ( hos t , I n t e g e r . p a r s e I n t ( p o r t ) ) ; } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ; } try ( OutputStream out=s o c k e t . getOutputStream ( ) ; InputStream i n=s o c k e t . g e t I n p u t S t r e a m ( ) ; InputStreamReader i s r =new InputStreamReader ( i n ) ; B u f f e r e d R e a d e r br=new B u f f e r e d R e a d e r ( i s r ) ; ){ out . w r i t e ( r e q S t r . g e t B y t e s ( ) ) ; out . f l u s h ( ) ; String s ; while ( ( s=br . r e a d L i n e ( ) ) ! = n u l l ) { System . out . p r i n t l n ( s ) ; }; socket . close ( ) ; // System . e x i t ( 0 ) ; } catch ( IOException e ) { System . out . p r i n t l n ( I n p u t E x c e p t i o n : +e . g e t M e s s a g e ( ) ) ; } } }
Client servlet
1 2 3 4 5 6 7
java . i o . BufferedReader ; j a v a . i o . IOException ; j a v a . i o . InputStream ; j a v a . i o . InputStreamReader ; j a v a . i o . OutputStream ; java . io . PrintWriter ; java . net . Socket ;
186
CAPITOLUL 9. SERVLET
9 10 11 12 13 15 16 18 19 20 21 23 24 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 43 44 45 46 47 48 49 50 51 52 53 54 56 57 58 59 60 62 63 64 66
@WebServlet ( u r l P a t t e r n s = { / c l i e n t } ) public c l a s s C l i e n t S e r v l e t extends H t t p S e r v l e t { protected void doGet ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { String m =r e q . g e t P a r a m e t e r ( m ) ; S t r i n g n=r e q . g e t P a r a m e t e r ( n ) ; r e s . setContentType ( t e x t / html ; c h a r s e t=UTF8 ) ; P r i n t W r i t e r out = r e s . g e t W r i t e r ( ) ; f i n a l S t r i n g CRLF = \ r \ n ; f i n a l S t r i n g h o s t = r e q . getServerName ( ) ; // l o c a l h o s t ; f i n a l i n t p o r t = r e q . g e t S e r v e r P o r t ( ) ; // 8 0 8 0 ; f i n a l S t r i n g c o n t e x t R o o t = / upgrade ; f i n a l S t r i n g data = m + +n ; InputStream i n p u t = n u l l ; OutputStream o ut pu t = n u l l ; BufferedReader r e a d e r = null ; Socket s = null ; try { out . p r i n t l n ( <html> ) ; out . p r i n t l n ( <head> ) ; out . p r i n t l n ( < t i t l e > S e r v l e t C l i e n t T e s t </ t i t l e > ) ; out . p r i n t l n ( </head> ) ; out . p r i n t l n ( <body> ) ; out . p r i n t l n ( <h1>Http Upgrade P r o c e s s </h1> ) ; // S e t t i n g t h e HTTP u p g r a d e r e q h e a d e r S t r i n g r e q S t r = POST + c o n t e x t R o o t + / upgrade HTTP/ 1 . 1 + CRLF ; r e q S t r += User Agent : Java / 1 . 7 + CRLF ; r e q S t r += Host : + h o s t + : + p o r t + CRLF ; r e q S t r += Accept : t e x t / html , image / g i f , image / j p e g , ; q = . 2 , / ; q =.2 + CRLF ; r e q S t r += Upgrade : upgrade + CRLF ; r e q S t r += C o n n e c t i o n : Upgrade + CRLF ; r e q S t r += Content t y p e : a p p l i c a t i o n /xwww form u r l e n c o d e d + CRLF ; r e q S t r += T r a n s f e r Encoding : chunked + CRLF ; r e q S t r += CRLF ; r e q S t r += data + CRLF ; s = new S o c k e t ( hos t , p o r t ) ; input = s . getInputStream ( ) ; ou tp ut = s . getOutputStream ( ) ; ou tp ut . w r i t e ( r e q S t r . g e t B y t e s ( ) ) ; ou tp ut . f l u s h ( ) ; out . p r i n t l n ( <h2>S e n d i n g upgrade r e q t o s e r v e r . . . . . . < / h2> ) ; out . p r i n t l n ( <h3>Request h e a d e r with data : < /h3> ) ; out . p r i n t l n ( ) ; S t r i n g r e q S t r D i s p l a y = r e q S t r . r e p l a c e A l l ( \ r \ n , </br > ) ;
187
67 68 69 71 73 74 75 77 78 79 80 82 83 85 86 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 119 120 121 122 123 124 125
out . p r i n t l n ( r e q S t r D i s p l a y ) ; out . p r i n t l n ( </br ></br > ) ; out . f l u s h ( ) ; r e a d e r = new B u f f e r e d R e a d e r ( new InputStreamReader ( i n p u t ) ) ; out . p r i n t l n ( <h2> S e r v e r a c c e p t upgrade req , send back t h e r e s : < /h2> ) ; out . p r i n t l n ( <h3>Response h e a d e r : < /h3> ) ; out . p r i n t l n ( ) ; // Reading t h e r e s , and d i s p l a y i n g t h e h e a d e r from s e r v e r p r i n t H e a d e r ( r e a d e r , out ) ; out . p r i n t l n ( </br ></br > ) ; out . f l u s h ( ) ; out . p r i n t l n ( <h2> S e r v e r send back t h e r e s with new p r o t o c o l and data : < /h2> ) ; out . p r i n t l n ( <h3>Response h e a d e r with data : < /h3> ) ; // Reading t h e r e s , and d i s p l a y i n g t h e h e a d e r from s e r v e r p r i n t H e a d e r ( r e a d e r , out ) ; // Reading t h e echo d a t a S t r i n g dataOutput ; i f ( ( dataOutput = r e a d e r . r e a d L i n e ( ) ) != n u l l ) { // P r i n t o u t t h e d a t a a f t e r h e a d e r out . p r i n t l n ( </br > + dataOutput + </br > ) ; out . p r i n t l n ( </br ></br > ) ; out . p r i n t l n ( <h2>C o n n e c t i o n with new p r o t o c o l e s t a b l i s h e d </h2> ) ; } out . f l u s h ( ) ; out . p r i n t l n ( </body> ) ; out . p r i n t l n ( </html> ) ; } catch ( IOException e ) { System . out . p r i n t l n ( C l i e n t S e r v l e t E x c e p t i o n : +e . g e t M e s s a g e ( ) ) ; } finally { i f ( r e a d e r != n u l l ) { reader . close ( ) ; } i f ( ou tp ut != n u l l ) { o ut pu t . c l o s e ( ) ; } i f ( i n p u t != n u l l ) { input . c l o s e ( ) ; } i f ( s != n u l l ) { s . close (); } } } protected void p r i n t H e a d e r ( B u f f e r e d R e a d e r r e a d e r , P r i n t W r i t e r out ) throws IOException { f o r ( S t r i n g l i n e ; ( l i n e = r e a d e r . r e a d L i n e ( ) ) != n u l l ; ) { i f ( l i n e . isEmpty ( ) ) { break ; } out . p r i n t l n ( l i n e + </br > ) ;
188
} }
CAPITOLUL 9. SERVLET
9.5
9.5.1
Apelarea unui servlet dintr-un program Java adic a lansarea unei cereri si recept ionarea r aspunsului furnizat de servlet se poate obt ine sincron cu produsul httpcomponents-client, asincron cu produsul httpcomponents-asyncclient. Ambele produse sunt dezvoltate de apache. Caracterul sincron / asincron const a n faptul c a recept ia si prelucrarea r aspunsului oferit de servlet are loc n metoda din care s-a lansat cererea, respectiv ntr-un alt obiect. Intr-un asemenea caz, din punctul de vedere al clientului este mai avantajos ca r aspunsul servlet-ului e text/plain, n loc de text/html. Cazul sincron Catalogul lib din httpcomponents-client cont ine, printre altele, sierele httpcore-*.jar, httpclient-*.jar, commons-logging-*.jar. Pentru compilare trebuie declarat a n variabila de sistem classpath referint a c atre httpclient-*.jar si httpcore-*.jar dar pentru execut ie este nevoie si de referint a c atre commons-logging-*.jar. Dezvoltarea unui client presupune: 1. Crearea unui obiect de tip org.apache.http.client.CloseableHttpClient: CloseableHttpClient httpclient = HttpClients.createDefault(); 2. Declararea metodei de transmitere a datelor get, post cu inserarea datelor din cerere.
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 solut ie mai elegant a 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 apart in pachetului org.apache.http.client.methods. 3. Lansarea cererii.
190
CAPITOLUL 9. SERVLET
HttpResponse response=httpclient.execute(httpget); respectiv HttpResponse response=httpclient.execute(httppost); 4. Preluarea r aspunsului. 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 Dezvolt am un program client pentru servlet-ul CmmdcServlet (post).
1 2 4 5 6 7 8 9 10 11 13 14 16 17 19 20 21 22 23 24 26 27 28 29
import j a v a . u t i l . S c a n n e r ; import o r g . apache . h t t p . H t t p E n t i t y ; import import import import import import import import o r g . apache . h t t p . impl . c l i e n t . C l o s e a b l e H t t p C l i e n t ; o r g . apache . h t t p . c l i e n t . methods . HttpPost ; o r g . apache . h t t p . c l i e n t . methods . C l o s e a b l e H t t p R e s p o n s e ; o r g . apache . h t t p . impl . c l i e n t . H t t p C l i e n t s ; java . u t i l . List ; java . u t i l . ArrayList ; o r g . apache . h t t p . NameValuePair ; o r g . apache . h t t p . message . BasicNameValuePair ;
import o r g . apache . h t t p . c l i e n t . e n t i t y . UrlEncodedFormEntity ; import j a v a . i o . ; public c l a s s ClientCmmdcServlet { s t a t i c S t r i n g u r i= h t t p : / / l o c a l h o s t : 8 0 8 0 / m y s e r v l e t /cmmdc ; public s t a t i c void main ( S t r i n g [ ] a r g s ) { S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ; System . out . p r i n t l n ( m = ) ; String m =s c a n n e r . n e x t L i n e ( ) . t r i m ( ) ; System . out . p r i n t l n ( n= ) ; S t r i n g n=s c a n n e r . n e x t L i n e ( ) . t r i m ( ) ; CloseableHttpClient httpclient = HttpClients . createDefault ( ) ; L i s t <NameValuePair > qparams = new A r r a y L i s t <NameValuePair > ( ) ; qparams . add ( new BasicNameValuePair ( m , m) ) ; qparams . add ( new BasicNameValuePair ( n , n ) ) ;
191
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
qparams . add ( new BasicNameValuePair ( t i p , t e x t / p l a i n ) ) ; try { UrlEncodedFormEntity params=new UrlEncodedFormEntity ( qparams , UTF8 ) ; HttpPost h t t p p o s t=new HttpPost ( u r i ) ; h t t p p o s t . s e t E n t i t y ( params ) ; C l o s e a b l e H t t p R e s p o n s e r e s p o n s e=h t t p c l i e n t . e x e c u t e ( h t t p p o s t ) ; H t t p E n t i t y e n t i t y=r e s p o n s e . g e t E n t i t y ( ) ; i f ( e n t i t y != n u l l ) { InputStream i s=e n t i t y . g e t C o n t e n t ( ) ; int l ; byte [ ] tmp=new byte [ 2 0 4 8 ] ; while ( ( l=i s . r e a d ( tmp))!= 1) {} System . out . p r i n t l n ( Cmmdc = +(new S t r i n g ( tmp ) . t r i m ( ) ) ) ; } } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( E x c e p t i o n : +e . g e t M e s s a g e ( ) ) ; } } }
public c l a s s CmmdcClient { public s t a t i c void main ( S t r i n g [ ] a r g s ) { S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ; System . out . p r i n t l n ( m = ) ; long m =s c a n n e r . nextLong ( ) ; System . out . p r i n t l n ( n= ) ; long n=s c a n n e r . nextLong ( ) ; S t r i n g msg=m =+ m +&n=+n+&t i p=t e x t / p l a i n ; try { S t r i n g urlGET= h t t p : / / l o c a l h o s t : 8 0 8 0 / m y s e r v l e t /cmmdc? +msg ; URL u r l=new URL( urlGET ) ; HttpURLConnection conn=(HttpURLConnection ) u r l . op enConne ction ( ) ; conn . setRequestMethod ( GET ) ; System . out . p r i n t l n ( conn . getResponseCode ( ) ) ; System . out . p r i n t l n ( conn . g e t R e s p o n s e M e s s a g e ( ) ) ; B u f f e r e d R e a d e r br= new B u f f e r e d R e a d e r ( new InputStreamReader ( conn . g e t I n p u t S t r e a m ( ) ) ) ; String s ; while ( ( s=br . r e a d L i n e ( ) ) ! = n u l l ) { System . out . p r i n t l n ( s ) ; } br . c l o s e ( ) ; conn . d i s c o n n e c t ( ) ; } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ; } try { S t r i n g urlPOST= h t t p : / / l o c a l h o s t : 8 0 8 0 / m y s e r v l e t /cmmdc ;
192
CAPITOLUL 9. SERVLET
37 38 39 40 41 42 43 44 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
URL u r l=new URL( urlPOST ) ; HttpURLConnection conn=(HttpURLConnection ) u r l . op enConne ction ( ) ; conn . setRequestMethod ( POST ) ; conn . s e t U s e C a c h e s ( f a l s e ) ; conn . s e t D o I n p u t ( true ) ; conn . setDoOutput ( true ) ; conn . s e t R e q u e s t P r o p e r t y ( Content Type , a p p l i c a t i o n /xwww form u r l e n c o d e d ) ; P r i n t W r i t e r pw=new P r i n t W r i t e r ( conn . getOutputStream ( ) ) ; pw . p r i n t l n ( msg ) ; pw . f l u s h ( ) ; System . out . p r i n t l n ( conn . getResponseCode ( ) ) ; System . out . p r i n t l n ( conn . g e t R e s p o n s e M e s s a g e ( ) ) ; B u f f e r e d R e a d e r br= new B u f f e r e d R e a d e r ( new InputStreamReader ( conn . g e t I n p u t S t r e a m ( ) ) ) ; String s ; while ( ( s=br . r e a d L i n e ( ) ) ! = n u l l ) { System . out . p r i n t l n ( s ) ; } br . c l o s e ( ) ; pw . c l o s e ( ) ; conn . d i s c o n n e c t ( ) ; } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ; } } }
Cazul asincron Variabila classpath cont ine referent ele c atre serele jar aate n catalogul lib din httpcomponent-asyncclient. Programarea const a din
1. Crearea unei instant e a clasei org.apache.http.impl.nio.client.DefaultHttpAsync CloseableHttpAsyncClient httpclient = HttpAsyncClient.createDefault(); httpclient.start(); 2. Lansarea unei cereri apel and o metod a 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 instant a de tip HttpAsyncRequestProducer se obt ine prin
193
HttpAsyncMethods.createGet(uri) Drept instant a a clasei HttpAsyncResponseConsumer poate o clas a ce extinde clasa org.apache.http.nio.client.methods.AsyncCharConsumer. Exemplul 9.5.2
1 3 4 5 6 7 8 9 11 12 13 15 16 18 19 20 21 22 23 24 25 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 48 49
import j a v a . u t i l . S c a n n e r ; import import import import import import import o r g . apache . h t t p . HttpResponse ; o r g . apache . h t t p . impl . n i o . c l i e n t . C l o s e a b l e H t t p A s y n c C l i e n t ; o r g . apache . h t t p . n i o . IOControl ; o r g . apache . h t t p . impl . n i o . c l i e n t . H t t p A s y n c C l i e n t s ; o r g . apache . h t t p . n i o . c l i e n t . methods . AsyncCharConsumer ; o r g . apache . h t t p . n i o . c l i e n t . methods . HttpAsyncMethods ; o r g . apache . h t t p . p r o t o c o l . HttpContext ;
import j a v a . n i o . C h a r B u f f e r ; import j a v a . i o . IOException ; import j a v a . u t i l . c o n c u r r e n t . Future ; public c l a s s AsyncClientCmmdcServlet { s t a t i c S t r i n g u r i= h t t p : / / l o c a l h o s t : 8 0 8 0 / m y s e r v l e t /cmmdc ; public s t a t i c void main ( S t r i n g [ ] a r g s ) throws E x c e p t i o n { S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ; System . out . p r i n t l n ( m = ) ; String m =s c a n n e r . n e x t L i n e ( ) . t r i m ( ) ; System . out . p r i n t l n ( n= ) ; S t r i n g n=s c a n n e r . n e x t L i n e ( ) . t r i m ( ) ; S t r i n g r e q u e s t D a t a= ?m =+ m +&n=+n+&t i p=t e x t / p l a i n ; System . out . p r i n t l n ( r e q u e s t D a t a ) ; CloseableHttpAsyncClient h t t p c l i e n t = HttpAsyncClients . c r e a t e D e f a u l t ( ) ; httpclient . start (); try { Future <Boolean > f u t u r e = h t t p c l i e n t . e x e c u t e ( HttpAsyncMethods . c r e a t e G e t ( u r i+r e q u e s t D a t a ) , new MyResponseConsumer ( ) , n u l l ) ; Boolean r e s u l t = f u t u r e . g e t ( ) ; i f ( r e s u l t != n u l l && r e s u l t . b o o l e a n V a l u e ( ) ) { System . out . p r i n t l n ( Request s u c c e s s f u l l y e x e c u t e d ) ; } else { System . out . p r i n t l n ( Request f a i l e d ) ; } System . out . p r i n t l n ( S h u t t i n g down ) ; } finally { httpclient . close (); } System . out . p r i n t l n ( Done ) ; } s t a t i c c l a s s MyResponseConsumer extends AsyncCharConsumer<Boolean >{ @Override
194
CAPITOLUL 9. SERVLET
50 52 53 54 55 56 57 58 59 61 62 64 65 66 67 68 69
protected void o n R e s p o n s e R e c e i v e d ( f i n a l HttpResponse r e s p o n s e ) {} @Override protected void onCharReceived ( f i n a l C h a r B u f f e r buf , f i n a l IOControl i o c t r l ) throws IOException { System . out . p r i n t l n ( Cmmdc : ) ; while ( b u f . hasRemaining ( ) ) { System . out . p r i n t ( b u f . g e t ( ) ) ; } } @Override protected void r e l e a s e R e s o u r c e s ( ) {} @Override protected Boolean b u i l d R e s u l t ( f i n a l HttpContext c o n t e x t ) { return Boolean .TRUE; } } }
9.5.2
Un servlet apeleaz a la un moment dat alt servlet. S ablonul 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 veric a parametri cererii. Pentru problema calculului celui mai mare divizor comun a dou a numere, dac a cei doi parametri sunt numere ntregi, atunci se apeleaz a servlet-ul ComputeServlet, altfel se formeaz a un mesaj de eroare. Codurile celor dou a servlete sunt: VerifServlet.java
1 2 3 4 5 6 7 8 9 11 12 13
package cmmdc ; import j a v a . i o . IOException ; import j a v a . i o . P r i n t W r i t e r ; import j a v a x . s e r v l e t . S e r v l e t E x c e p t i o n ; import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t ; import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t R e q u e s t ; import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t R e s p o n s e ; import j a v a x . s e r v l e t . R e q u e s t D i s p a t c h e r ; import j a v a x . s e r v l e t . a n n o t a t i o n . WebServlet ; @WebServlet ( u r l P a t t e r n s = / v e r i f ) public c l a s s V e r i f S e r v l e t extends H t t p S e r v l e t { public void doGet ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s )
195
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 58 59 60 61 62
throws S e r v l e t E x c e p t i o n , IOException { P r i n t W r i t e r out=r e s . g e t W r i t e r ( ) ; r e s . setContentType ( t e x t / html ) ; S t r i n g sm=r e q . g e t P a r a m e t e r ( m ) , sn=r e q . g e t P a r a m e t e r ( n ) ; S t r i n g message= ; long m, n ; i f ( ( sm==n u l l ) | | ( sm . e q u a l s ( ) ) ) { message=Numar a b s e n t ; } else { try { m =Long . par se Lon g ( sm ) ; } catch ( NumberFormatException e ) { message=Nu e s t e numar ; } } i f ( ( sn==n u l l ) | | ( sn . e q u a l s ( ) ) ) { message=Numar a b s e n t ; } else { try { n=Long . p ars eL ong ( sn ) ; } catch ( NumberFormatException e ) { message=Nu e s t e numar ; } } out . p r i n t l n ( <html><body> ) ; i f ( message . e q u a l s ( ) ) { out . p r i n t l n ( <h3> R e z u l t a t u l obţ i n u t </h3> ) ; R e q u e s t D i s p a t c h e r d i s p a t c h e r= getServletContext ( ) . getRequestDispatcher ( / c a l c u l ) ; i f ( d i s p a t c h e r != n u l l ) d i s p a t c h e r . i n c l u d e ( req , r e s ) ; } else { out . p r i n t l n ( <h3> Date e r o n a t e </h3> ) ; out . p r i n t l n ( message ) ; } out . p r i n t l n ( </body ></html> ) ; out . c l o s e ( ) ; } public void doPost ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { doGet ( req , r e s ) ; } }
ComputeServlet.java
1 2 3 4 5 6 7
196
CAPITOLUL 9. SERVLET
8 10 11 13 15 16 17 18 19 20 21 23 24 25 26 27
import j a v a x . s e r v l e t . a n n o t a t i o n . WebServlet ; @WebServlet ( u r l P a t t e r n s = / c a l c u l ) public c l a s s ComputeServlet extends H t t p S e r v l e t { public long cmmdc( long m, long n ) { . . . } public void doGet ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { long m =Long . par se Lo ng ( r e q . g e t P a r a m e t e r ( m ) ) ; long n=Long . p ars eL ong ( r e q . g e t P a r a m e t e r ( n ) ) ; P r i n t W r i t e r out=r e s . g e t W r i t e r ( ) ; out . p r i n t l n ( <H1> Cmmdc = +cmmdc(m, n)+</H1> ) ; } public void doPost ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { doGet ( req , r e s ) ; } }
9.5.3
Sesiune de lucru
In cazul protocolului HTTP, de ecare dat a c and un client deschide sau revine la o pagin a Web se deschide o nou a conexiune cu serverul Web iar acesta nu ret ine informat iile referitoare la client pe perioada conexiunii respective. Perioada de timp c at un client este n conexiune cu o pagin a Web se nume ste sesiune. Exist a posibilitatea p astr arii unor informat ii pe durata unei sesiuni prin intermediul unui obiect de tip javax.servlet.http.HttpSession. Inaintea satisfacerii unei cereri, servlet-ul veric a existent a unui obiect HttpSession. Acest obiect se creaz a la prima apelare de c atre un client a servlet-ului prin HttpSession sesiune =request.getSession(true); Un obiect HttpSession poate ret ine atribute, adic a perechi de forma (nume, valoare). Introducerea unui atribut se realizeaz a prin void setAttribute(String nume , Object valoare ) iar extragerea valorii unui atribut se obt ine prin Object getAttribute(String nume ) Metoda String nume [ ] getValueNames() returneaz a numele tuturor atributelor denite. Un atribut se elimin a cu metoda void removeAttribute(String nume ).
197
Exemplul 9.5.4 Exemplul urm ator num ar a de c ate ori se apeleaz a servletul ntr-o sesiune. Se dene ste un atribut noAcces, care la prima apelare este init ializat iar apoi este m arit cu c ate o unitate la ecare nou a apelare a servletului.
1 2 3 4 5 6 7 8 10 11 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 37 38 39 40 41
j a v a . i o . IOException ; java . io . PrintWriter ; javax . s e r v l e t . ServletException ; javax . s e r v l e t . http . HttpServlet ; javax . s e r v l e t . http . HttpServletRequest ; javax . s e r v l e t . http . HttpServletResponse ; javax . s e r v l e t . http . HttpSession ; j a v a x . s e r v l e t . a n n o t a t i o n . WebServlet ;
@WebServlet ( u r l P a t t e r n s = / s e s i u n e ) public c l a s s S e s i u n e extends H t t p S e r v l e t { public void doGet ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { r e s . setContentType ( t e x t / html ) ; S t r i n g mesaj ; P r i n t W r i t e r out=r e s . g e t W r i t e r ( ) ; H t t p S e s s i o n s e s s i o n=r e q . g e t S e s s i o n ( true ) ; I n t e g e r c o n t o r =( I n t e g e r ) s e s s i o n . g e t A t t r i b u t e ( noAcces ) ; i f ( c o n t o r==n u l l ) { c o n t o r=new I n t e g e r ( 1 ) ; mesaj= S a l u t ! ; } else { c o n t o r=new I n t e g e r ( c o n t o r . i n t V a l u e ( ) + 1 ) ; mesaj= Bine a t i r e v e n i t ! ; } s e s s i o n . s e t A t t r i b u t e ( noAcces , c o n t o r ) ; out . p r i n t l n ( <html><body> ) ; out . p r i n t l n ( <h1>+mesaj+</h1> ) ; out . p r i n t l n ( Numarul de a c c e s a r i a l a c e a s t e i p a g i n i e s t e + contor . intValue ( ) ) ; out . p r i n t l n ( </body ></html> ) ; out . c l o s e ( ) ; } public void doPost ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { doGet ( req , r e s ) ; } }
< ! doctype html> <head> <meta charset= u t f 8> < l i n k r e l = s t y l e s h e e t href= mycss . c s s > </ head> <body> <center> <h1> Formular de a c c e s </ h1>
198
CAPITOLUL 9. SERVLET
9 10 11 12 13 14 15 16
<form method= g e t action= s e s i u n e > <p> <input type= submit value= A c c e s e a z a > </ form> </ center> </ body> </ html>
9.5.4
Cookie
Un Cookie este un sier de dimensiune mic a trimis de c atre programul server clientului ca parte a header-ului Http. Acesta cont ine informat ii despre sesiunea curent a care salvate pe disc vor putea accesate n sesiuni ulterioare. C and un navigator emite o cerere c atre un server, cookie-urile anterioare primite de c atre client de la serverul respectiv sunt trimise din nou serverului ca parte a cererii formulat a de client. Cookie-urile sunt sterse automat n momentul expir arii. Unii client i nu permit memorarea cookie-urilor. In acest caz, clientul este informat c a acest fapt ar putea duce la imposibilitatea satisfacerii cereri sale / acces arii paginii Web. Implicit, durata de viat a a unui cookie este sesiunea curent a a navigatorului (p an a se nchide navigatorul). Clasa Cookie Contructor Cookie(String nume , String valoare ) Metode void setDomain(String model ) Domeniul este o adres a URL ce restrict ioneaz a accesul cookie-urilor la acel domeniu. model trebuie s a cont in a cel put in dou a caractere .. void setMaxAge(int durat a ) Fixeaz a durata de existent a a cookie-ului - n secunde. Valoarea implicit a este -1, adic a cookie-ul exist a p an a la nchiderea programului navigator. void setComment(String comentariu ) void setSecure(boolean ag ) Valoarea implicit a este false.
199
Trimiterea unui cookie clientului: public void HttpServletResponse.addCookie(Cookie cookie ) Recunoa sterea cookie-urilor de c atre 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 urm Exemplul 9.5.5 In ator se num ar a de c ate ori se apeleaz a servletul pe durata de viat a a cookie-ului.
1 2 3 4 5 6 7 8 9 11 13 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
package c o o k i e ; import j a v a . i o . IOException ; import j a v a . i o . P r i n t W r i t e r ; import j a v a x . s e r v l e t . S e r v l e t E x c e p t i o n ; import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t ; import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t R e q u e s t ; import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t R e s p o n s e ; import j a v a x . s e r v l e t . h t t p . Cookie ; import j a v a x . s e r v l e t . a n n o t a t i o n . WebServlet ; @WebServlet ( u r l P a t t e r n s = / c o o k i e ) public c l a s s A p e l a r i extends H t t p S e r v l e t { public void doGet ( H t t p S e r v l e t R e q u e s t req , HttpServletResponse res ) throws S e r v l e t E x c e p t i o n , IOException { r e s . setContentType ( t e x t / html ) ; S t r i n g mesaj= ; P r i n t W r i t e r out=r e s . g e t W r i t e r ( ) ; Cookie myCookie=n u l l ; i n t c o n t o r =0; Cookie [ ] c o o k i e s=r e q . g e t C o o k i e s ( ) ; boolean sw= f a l s e ; i f ( c o o k i e s != n u l l ) { f o r ( i n t i =0; i < c o o k i e s . l e n g t h ; i ++){ S t r i n g name=c o o k i e s [ i ] . getName ( ) ; i f ( name . e q u a l s ( u r m a r i r e ) ) { sw=true ; c o n t o r=I n t e g e r . p a r s e I n t ( c o o k i e s [ i ] . g e t V a l u e ( ) ) ; c o n t o r ++; mesaj= Bine a t i r e v e n i t ! ; System . out . p r i n t l n ( G a s i t +c o n t o r ) ; } }
200
CAPITOLUL 9. SERVLET
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 54 55 56 57 58 59
} i f ( sw ) { myCookie=new Cookie ( u r m a r i r e , ( new I n t e g e r ( c o n t o r ) ) . t o S t r i n g ( ) ) ; } else { myCookie=new Cookie ( u r m a r i r e , ( new I n t e g e r ( 1 ) ) . t o S t r i n g ( ) ) ; c o n t o r =1; mesaj= S a l u t ! ; } myCookie . setMaxAge ( 1 0 0 0 0 0 0 ) ; r e s . addCookie ( myCookie ) ; out . p r i n t l n ( <html><body> ) ; out . p r i n t l n ( <h1>+mesaj+</h1> ) ; out . p r i n t l n ( Numarul de a c c e s a r i a l a c e a s t e i p a g i n i e s t e +c o n t o r ) ; out . p r i n t l n ( </body ></html> ) ; out . c l o s e ( ) ; } public void doPost ( H t t p S e r v l e t R e q u e s t req , HttpServletResponse res ) throws S e r v l e t E x c e p t i o n , IOException { doGet ( req , r e s ) ; } }
9.5.5
Autenticare
Serverul Web apache-tomcat poate executa autentic arile basic si digest. Autenticarea se face pe baza perechii (nume utilizator, parola) (username,password). Aceste informat ii sunt ret inute n serverul Web, n sierul conf\tomcat-users.xml ind asociate unui element <role>, de exemplu
<role <role . . . <user <user rolename="BASIC_ROLE"/> rolename="DIGEST_ROLE"/> username="basic" password="basic" roles="BASIC_ROLE"/> username="digest" password="digest" roles="DIGEST_ROLE"/>
Codul servlet-ului nu este implicat, iar cerint a de autenticare solicitat a unui client se precizeaz a n sierul 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>
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>
Opt ional poate denit un domeniu (realm). In cazul apel arii dintr-un program Java a unui servlet, la care accesul presupune autenticare, aceasta se realizeaz a prin intermediul claselor pachetului httpcomponents-client :
import import import import org.apache.http.auth.AuthScope; org.apache.http.auth.UsernamePasswordCredentials; org.apache.http.impl.auth.BasicScheme; org.apache.http.protocol.BasicHttpContext;
. . . DefaultHttpClient httpclient = new DefaultHttpClient(); // Activitati pentru autentificare httpclient.getCredentialsProvider().setCredentials( new AuthScope(host,Integer.parseInt(port)), // new AuthScope(host,Integer.parseInt(port),realm), new UsernamePasswordCredentials(username,password) ); BasicHttpContext context=new BasicHttpContext(); BasicScheme schema = new BasicScheme(); // DigestScheme schema = new DigestScheme(); context.setAttribute("preemptive-auth", schema); . . . HttpResponse response=httpclient.execute(httppost,context); . . .
In cazul autentic arii digest, datele de identicare sunt criptate iar in cazul autenticarii basic se utilizeaz a codarea base64.
9.5.6
Folosind Anexa C consider am Exemplul 9.5.6 Consultarea unei agende de adrese e-mail. Se utilizeaz a o baz a de date AgendaEMail alc atuit a dintr-un singur tabel adrese (id int, nume varchar(20), email varchar(30)). Utiliz and SGBD derby servlet-ul este
202
CAPITOLUL 9. SERVLET
1 2 3 4 5 6 7 8 9 10 11 12 13 15 16 17 18 20 21 22 23 24 25 26 27 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 45 46 47 48 49 50 51 52 54 55 56 57 58
import import import import import import import import import import import import import
j a v a . i o . IOException ; javax . s e r v l e t . ServletException ; javax . s e r v l e t . ServletOutputStream ; javax . s e r v l e t . ServletConfig ; javax . s e r v l e t . http . HttpServlet ; javax . s e r v l e t . http . HttpServletRequest ; javax . s e r v l e t . http . HttpServletResponse ; j a v a x . s e r v l e t . a n n o t a t i o n . WebServlet ; j a v a . s q l . Statement ; java . s q l . Connection ; j a v a . s q l . DriverManager ; j a v a . s q l . SQLException ; java . s q l . ResultSet ;
@WebServlet ( u r l P a t t e r n s = / a d r e s e ) public c l a s s A g e n d a E M a i l S e r v l e t extends H t t p S e r v l e t { Statement i n s t r u c t i u n e=n u l l ; C o n n e c t i o n con=n u l l ; public void i n i t ( S e r v l e t C o n f i g c o n f i g ) throws S e r v l e t E x c e p t i o n { super . i n i t ( c o n f i g ) ; // SGBD Derby S t r i n g j d b c D r i v e r= o r g . apache . derby . j d b c . C l i e n t D r i v e r ; S t r i n g URLBazaDate= j d b c : derby : / / l o c a l h o s t : 1 5 2 7 / AgendaEMail ; // SGBD Mysql // S t r i n g j d b c D r i v e r =com . mysql . j d b c . D r i v e r ; // S t r i n g URLBazaDate= j d b c : mysql : / / l o c a l h o s t : 3 3 0 6 / AgendaEMail ? u s e r=r o o t ; try { C l a s s . forName ( j d b c D r i v e r ) . n e w I n s t a n c e ( ) ; con=DriverManager . g e t C o n n e c t i o n ( URLBazaDate ) ; i n s t r u c t i u n e=con . c r e a t e S t a t e m e n t ( ) ; } catch ( ClassNotFoundException e ) { System . out . p r i n t l n ( D r i v e r i n e x i s t e n t JDBC : +j d b c D r i v e r ) ; } catch ( SQLException e ) { System . out . p r i n t l n ( Baza de d a t e i n e x i s t e n t a +URLBazaDate ) ; } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( E r o a r e : +e . g e t M e s s a g e ( ) ) ; } } public void d e s t r o y ( ) { try { i f ( con != n u l l ) con . c l o s e ( ) ; } catch ( SQLException e ) { System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ; } } public void doGet ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { S t r i n g myAtribut , myVal ; r e s . setContentType ( t e x t / html ) ; S e r v l e t O u t p u t S t r e a m out = r e s . getOutputStream ( ) ;
203
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 89 90 91 92 93
myAtribut=r e q . g e t P a r a m e t e r ( c r i t e r i u ) ; myVal=r e q . g e t P a r a m e t e r ( termen ) ; myVal= \ +myVal+ \ ; try { S t r i n g s q l= s e l e c t from a d r e s e where + myAtribut+ = +myVal ; R e s u l t S e t r s=i n s t r u c t i u n e . e x e c u t e Q u e r y ( s q l ) ; out . p r i n t l n ( <html> ) ; out . p r i n t l n ( <head>< t i t l e >AgendaEMail </ t i t l e ></head> ) ; out . p r i n t l n ( <body> ) ; out . p r i n t l n ( <h1>Agenda de Adrese em a i l </h1> ) ; out . p r i n t l n ( <p/> ) ; out . p r i n t l n ( <b> Nume <> Adresa em a i l </b> ) ; out . p r i n t l n ( <br/> ) ; while ( r s . n e x t ( ) ) { out . p r i n t ( r s . g e t S t r i n g ( nume)+ <> +r s . g e t S t r i n g ( e m a i l ) ) ; out . p r i n t l n ( <br/> ) ; } out . p r i n t l n ( </body> ) ; out . p r i n t l n ( </html> ) ; out . c l o s e ( ) ; } catch ( SQLException e ) { System . out . p r i n t l n ( SQLException : +e . g e t M e s s a g e ( ) ) ; } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( E r o a r e : +e . g e t M e s s a g e ( ) ) ; } } public void doPost ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { doGet ( req , r e s ) ; } }
<html> <body> <h1> Cautare i n baza de d a t e AgendaEMail</ h1> <form method= g e t action= a d r e s e > <p> C r i t e r i u de c a u t a r e : < s e l e c t name= c r i t e r i u > <option value=nume>dupa Nume <option value= e m a i l >dupa Email </ s e l e c t> <br> <p> E n t i t a t e a c a u t a t a <input type= t e x t name= termen s i z e =30> <p><input type= submit value= Cauta > </ form> </ body> </ html>
CAPITOLUL 9. SERVLET
(b) Se veric a prezent a n catalogul servlet-ului ...\WEB-INF\lib a sierului derbyclient.jar sau mysql-connector-java-*.*.*-bin.jar. (c) Pornirea serverului tomcat sau re nc arcarea servlet-ului. (d) Apelarea servlet-ului din pagina Web.
9.5.7
Indic am dou a modalit a ti prin care un client obt ine o imagine furnizat a de un servlet. Imaginea poate proveni dintr-un sier extern sau poate creat a de servlet. Imaginea este transmis a direct clientului n uxul de ie sire de tip ServletOutputStream, tipul MIME al r aspunsului ind response.setContentType("image/ext "); ext {gif, jpg, png, . . .}. Textul surs a al servlet-ului este:
1 2 3 4 5 6 7 8 10 11 12 14 16 17 18 19 20 21 22 23 24
package g r a p h g i f ; import j a v a . i o . IOException ; import j a v a x . s e r v l e t . S e r v l e t E x c e p t i o n ; import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t ; import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t R e q u e s t ; import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t R e s p o n s e ; import j a v a x . s e r v l e t . S e r v l e t O u t p u t S t r e a m ; import j a v a x . s e r v l e t . a n n o t a t i o n . WebServlet ; import j a v a . n i o . f i l e . Path ; import j a v a . n i o . f i l e . Paths ; import j a v a . n i o . f i l e . F i l e s ; @WebServlet ( u r l P a t t e r n s = / g r a p h g i f ) public c l a s s MyGraphG extends H t t p S e r v l e t { public void doGet ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { S t r i n g f s=System . g e t P r o p e r t y ( f i l e . s e p a r a t o r ) ; S e r v l e t O u t p u t S t r e a m out = r e s . getOutputStream ( ) ; S t r i n g pathTomcat = new j a v a . i o . F i l e ( . ) . g e t C a n o n i c a l P a t h ( ) ; S t r i n g c o n t e x t P a t h=r e q . g e t C o n t e x t P a t h ( ) ; Path path=Paths . g e t ( pathTomcat+f s+ webapps +f s+ c o n t e x t P a t h+f s+ w a l k i n g s a n t a . g i f ) ;
205
25 26 27 28 29 30 31 32 33 34 35 36
try { r e s . setContentType ( image / g i f ) ; F i l e s . copy ( path , out ) ; } catch ( E x c e p t i o n e ) { r e s . setContentType ( t e x t / p l a i n ) ; System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ; out . p r i n t l n ( C e r e r e a d v o a s t r a nu p o a t e f i } out . c l o s e ( ) ; } }
satisfacuta );
Pe calculatorul serverului Web, imaginea se salveaz a ntr-un sier grac, dup a care servlet-ul scrie n uxul de ie sire un document html cu o leg atur a (link) c atre sierul cu imaginea creat a anterior. Navigatorul clientului va desc arca si vizualiza imaginea. Dac a tipul sierului grac este jpg sau png atunci textul surs a al servletului este:
1 2 3 4 5 6 7 8 10 11 12 13 14 15 17 19 21 22 23 24 25 26 27 29 30 31 32 33
package g r a p h j p g ; import j a v a . i o . IOException ; import j a v a . i o . P r i n t W r i t e r ; import j a v a . i o . F i l e ; import j a v a x . s e r v l e t . S e r v l e t E x c e p t i o n ; import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t ; import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t R e q u e s t ; import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t R e s p o n s e ; import import import import import import j a v a x . s e r v l e t . a n n o t a t i o n . WebServlet ; j a v a x . i m a g e i o . ImageIO ; j a v a . awt . Frame ; j a v a . awt . Font ; j a v a . awt . G r a p h i c s ; j a v a . awt . image . B u f f e r e d I m a g e ;
@WebServlet ( u r l P a t t e r n s = / g r a p h j p g ) public c l a s s MyGraphP extends H t t p S e r v l e t { public void doGet ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { S t r i n g f s=System . g e t P r o p e r t y ( f i l e . s e p a r a t o r ) ; r e s . setContentType ( t e x t / html ) ; P r i n t W r i t e r out=r e s . g e t W r i t e r ( ) ; S t r i n g pathTomcat = new j a v a . i o . F i l e ( . ) . g e t C a n o n i c a l P a t h ( ) ; S t r i n g c o n t e x t P a t h=r e q . g e t C o n t e x t P a t h ( ) ; S t r i n g f i l e R e f=pathTomcat+f s+ webapps +f s+c o n t e x t P a t h+f s ; S t r i n g numeFis= d e s e n ; S t r i n g e x t= j p g ; // sau png // Formarea i m a g i n i i Frame frame = n u l l ;
206
CAPITOLUL 9. SERVLET
34 35 36 37 38 39 40 41 42 43 44 46 48 49 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
Graphics g = null ; B u f f e r e d I m a g e image=n u l l ; try { frame = new Frame ( ) ; frame . a d d N o t i f y ( ) ; image = ( B u f f e r e d I m a g e ) frame . c r e a t e I m a g e ( 8 0 0 , 6 0 ) ; g = image . g e t G r a p h i c s ( ) ; // F i x a r e a f o n t u l u i g . s e t F o n t ( new Font ( S e r i f , Font . ITALIC , 4 8 ) ) ; // E d i t a r e a unui t e x t g . d r a w S t r i n g ( T e h n o l o g i i d i s t r i b u i t e i n Java , 1 0 , 5 0 ) ; // S a l v a r e a i m a g i n i i i n t r un f i s i e r j p g sau png F i l e f=new F i l e ( f i l e R e f+numeFis+ . +e x t ) ; ImageIO . w r i t e ( image , j p g , f ) ; // Raspunsul c a t r e c l i e n t out . p r i n t l n ( <HTML >< BODY > ) ; out . p r i n t l n ( <h2>Imagine p r e l u a t a de pe s e r v e r </h2> ) ; out . p r i n t l n ( <p><a h r e f =\ h t t p : / / l o c a l h o s t : 8 0 8 0 / m y s e r v l e t / + numeFis+ . +e x t+ \> ) ; out . p r i n t l n ( V i z u a l i z a r e a i m a g i n i i </a> ) ; out . p r i n t l n ( </BODY ></HTML > ) ; out . c l o s e ( ) ; } finally { // E l i b e r a r e a r e s u r s e l o r i f ( g != n u l l ) g . d i s p o s e ( ) ; i f ( frame != n u l l ) frame . r e m o v e N o t i f y ( ) ; } } }
Clasa GifEncoder care realizeaz a 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 client al unei aplicat ii RMI. Interfat a la diatant a se depune n catalogul WEB-INF\lib al servlet-ului. Apelarea programului server RMI se face prin InterfataDistanta obj=(InterfataDistanta) Naming.lookup("//"+host+":"+port+"/NumeServiciuRMI");
207
Exemplul 9.5.7 Client servlet pentru aplicat ia RMI de calcul al celui mai mare divizor comun a dou a numere naturale.
1 2 3 4 5 6 7 9 10 12 13 14 15 17 18 19 21 22 23 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 43 44 45 46 47
@WebServlet ( u r l P a t t e r n s = / s e r v l e t r m i ) public c l a s s ServletRMI extends H t t p S e r v l e t { public void doGet ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { r e s . setContentType ( t e x t / html ) ; P r i n t W r i t e r out = r e s . g e t W r i t e r ( ) ; S t r i n g sm=r e q . g e t P a r a m e t e r ( m ) , sn=r e q . g e t P a r a m e t e r ( n ) ; long m=(new Long ( sm ) ) . l o n g V a l u e ( ) , n=(new Long ( sn ) ) . l o n g V a l u e ( ) ; long x =0; S t r i n g h o s t=r e q . g e t P a r a m e t e r ( h o s t ) . t r i m ( ) ; S t r i n g s P o r t=r e q . g e t P a r a m e t e r ( p o r t ) ; i n t p o r t=I n t e g e r . p a r s e I n t ( s P o r t ) ; try { ICmmdc o b j =(ICmmdc) Naming . l o o k u p ( // +h o s t+ : +p o r t+ /CmmdcServer ) ; x=o b j . cmmdc(m, n ) ; } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( CmmdcClient e x c e p t i o n : +e . g e t M e s s a g e ( ) ) ; } S t r i n g t i t l e = CmmdcServlet ; r e s . setContentType ( t e x t / html ) ; out . p r i n t l n ( <HTML ><HEAD ><TITLE> ) ; out . p r i n t l n ( t i t l e ) ; out . p r i n t l n ( </TITLE></HEAD >< BODY > ) ; out . p r i n t l n ( <H1>+ t i t l e +</H1> ) ; out . p r i n t l n ( <P>Cmmdc : +x ) ; out . p r i n t l n ( </BODY ></HTML > ) ; out . c l o s e ( ) ; } public void doPost ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { doGet ( req , r e s ) ; } }
9.5.9
Servlet cu JMS
208
CAPITOLUL 9. SERVLET
In prima faz a se apeleaz a un servlet care apeleaz a un server JMS. Solut ia este ret inut a de furnizorul serviciului de mesagerie pe o destinat ie cu un subiect furnizat de client. Pentru reg asirea rezultatului, servlet-ul creaz a clientului un abonament durabil, funct ie de numele subiectului. In faza a doua, clientul apeleaz a un alt servlet, a c arei funct ie este preluarea rezultatului. Clientul trebuie sa furnizeze subiectul destinat iei rezultatului. Exemplul 9.5.8 Codul serverului JMS
1 2 3 5 7 9 10 11 12 13 14 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
long cmmdc( long m, long n ) { . . . } public void s e r v i c e ( ) { try { // V a r i a n t a ApacheMessageQueue // o r g . apache . a c t i v e m q . ActiveMQConnectionFactory c f= // new o r g . apache . a c t i v e m q . ActiveMQConnectionFactory ( // tcp :// l o c a l h o s t :61616); // V a r i a n t a Oracle Sun MessageQueue com . sun . m e s s a g i n g . T o p i c C o n n e c t i o n F a c t o r y c f= new com . sun . m e s s a g i n g . T o p i c C o n n e c t i o n F a c t o r y ( ) ; // c f . s e t P r o p e r t y ( imqBrokerHostName , h o s t ) ; // c f . s e t P r o p e r t y ( imqBrokerHostPort , 7 6 7 6 ) ; T o p i c C o n n e c t i o n conn=c f . c r e a t e T o p i c C o n n e c t i o n ( ) ; T o p i c S e s s i o n s e s s i o n= conn . c r e a t e T o p i c S e s s i o n ( f a l s e , S e s s i o n .AUTO ACKNOWLEDGE) ; D e s t i n a t i o n tDate=s e s s i o n . c r e a t e T o p i c ( Cmmdc ) ; T o p i c S u b s c r i b e r consumer=s e s s i o n . c r e a t e S u b s c r i b e r ( ( Topic ) tDate ) ; conn . s t a r t ( ) ; TextMessage txtMsg=n u l l ; S t r i n g sm= , sn= , t o p i c= ; while ( true ) { txtMsg=(TextMessage ) consumer . r e c e i v e ( ) ; S t r i n g msg=txtMsg . g e t T e x t ( ) ; S t r i n g [ ] s t=msg . s p l i t ( ) ; sm=s t [ 0 ] ; sn=s t [ 1 ] ; t o p i c=s t [ 2 ] ; System . out . p r i n t l n ( sm+ : +sn+ : +t o p i c ) ; long a=Long . par se Lon g ( sm ) ; long b=Long . pa rs eL ong ( sn ) ; long c=cmmdc( a , b ) ; D e s t i n a t i o n t R e s u l t=s e s s i o n . c r e a t e T o p i c ( t o p i c ) ; MessageProducer p r o d u c e r=s e s s i o n . c r e a t e P r o d u c e r ( t R e s u l t ) ; txtMsg=s e s s i o n . c r e a t e T e x t M e s s a g e ( ( new Long ( c ) ) . t o S t r i n g ( ) ) ;
209
43 44 45 46 47 48 49 50 51 53 54 55 56 57
p r o d u c e r . send ( txtMsg ) ; System . out . p r i n t l n ( E x p e d i a t r a s p u n s ) ; } } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( E x c e p t i o n : +e . g e t M e s s a g e ( ) ) ; } System . out . p r i n t l n ( S e r v e r f i n i s h e d ) ; } public s t a t i c void main ( S t r i n g [ ] a r g s ) { MsgCmmdcServer s e r v e r=new MsgCmmdcServer ( ) ; server . service (); } }
package jms ; import j a v a x . jms . ; import j a v a . i o . ; import j a v a x . s e r v l e t . ; import j a v a x . s e r v l e t . h t t p . ; import j a v a x . s e r v l e t . a n n o t a t i o n . WebServlet ; @WebServlet ( u r l P a t t e r n s = / s e n d e r ) public c l a s s J M S S e n d e r S e r v l e t extends H t t p S e r v l e t { public void doGet ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { r e s . setContentType ( t e x t / html ) ; S e r v l e t O u t p u t S t r e a m out = r e s . getOutputStream ( ) ; String m =r e q . g e t P a r a m e t e r ( m ) ; S t r i n g n=r e q . g e t P a r a m e t e r ( n ) ; S t r i n g t o p i c=r e q . g e t P a r a m e t e r ( t o p i c ) ; S t r i n g c l i e n t I D=r e q . g e t P a r a m e t e r ( c l i e n t I D ) ; S t r i n g c l i e n t N a m e=r e q . g e t P a r a m e t e r ( c l i e n t N a m e ) ; try { // V a r i a n t a ApacheMessageQueue // o r g . apache . a c t i v e m q . ActiveMQConnectionFactory c f= // new o r g . apache . a c t i v e m q . ActiveMQConnectionFactory ( // tcp :// l o c a l h o s t :61616); // V a r i a n t a Oracle Sun MessageQueue com . sun . m e s s a g i n g . T o p i c C o n n e c t i o n F a c t o r y c f= new com . sun . m e s s a g i n g . T o p i c C o n n e c t i o n F a c t o r y ( ) ; // c f . s e t P r o p e r t y ( imqBrokerHostName , h o s t ) ; // c f . s e t P r o p e r t y ( imqBrokerHostPort , 7 6 7 6 ) ; T o p i c C o n n e c t i o n conn=c f . c r e a t e T o p i c C o n n e c t i o n ( ) ; conn . s e t C l i e n t I D ( c l i e n t I D ) ; T o p i c S e s s i o n s e s s i o n= conn . c r e a t e T o p i c S e s s i o n ( f a l s e , S e s s i o n .AUTO ACKNOWLEDGE) ; D e s t i n a t i o n t R e s u l t=s e s s i o n . c r e a t e T o p i c ( t o p i c ) ; T o p i c S u b s c r i b e r consumer= s e s s i o n . c r e a t e D u r a b l e S u b s c r i b e r ( ( Topic ) t R e s u l t , c l i e n t N a m e ) ; D e s t i n a t i o n t = s e s s i o n . c r e a t e T o p i c ( Cmmdc ) ; MessageProducer p r o d u c e r = s e s s i o n . c r e a t e P r o d u c e r ( t ) ; TextMessage txtMsg=s e s s i o n . c r e a t e T e x t M e s s a g e ( ) ; S t r i n g mesaj= m + +n+ +t o p i c ;
210
CAPITOLUL 9. SERVLET
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 59 60 61 62 63
txtMsg . s e t T e x t ( mesaj ) ; p r o d u c e r . send ( txtMsg ) ; session . close (); conn . c l o s e ( ) ; out . p r i n t l n ( <html><body b g c o l o r=\#c c b b c c \>< c e n t e r > ) ; out . p r i n t l n ( <h1> JSP Cmmdc </h1> ) ; out . p r i n t l n ( <p> ) ; out . p r i n t l n ( D a t e l e au f o s t e x p e d i a t e s e r v e r u l u i ) ; out . p r i n t l n ( </ c e n t e r ></body ></html> ) ; } catch ( E x c e p t i o n e ) { out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ; } out . c l o s e ( ) ; System . out . p r i n t l n ( P u b l i s h e r f i n i s h e d ) ; } public void doPost ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { doGet ( req , r e s ) ; } }
package jms ; import j a v a x . jms . ; import j a v a . i o . ; import j a v a x . s e r v l e t . ; import j a v a x . s e r v l e t . h t t p . ; import j a v a x . s e r v l e t . a n n o t a t i o n . WebServlet ; @WebServlet ( u r l P a t t e r n s = / r e c e i v e r ) public c l a s s J M S R e c e i v e r S e r v l e t extends H t t p S e r v l e t { public void doGet ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { r e s . setContentType ( t e x t / html ) ; S e r v l e t O u t p u t S t r e a m out = r e s . getOutputStream ( ) ; S t r i n g t o p i c=r e q . g e t P a r a m e t e r ( t o p i c ) ; S t r i n g c l i e n t I D=r e q . g e t P a r a m e t e r ( c l i e n t I D ) ; S t r i n g c l i e n t N a m e=r e q . g e t P a r a m e t e r ( c l i e n t N a m e ) ; try { // V a r i a n t a ApacheMessageQueue // o r g . apache . a c t i v e m q . ActiveMQConnectionFactory c f= // new o r g . apache . a c t i v e m q . ActiveMQConnectionFactory ( // tcp :// l o c a l h o s t :61616); // V a r i a n t a Oracle Sun MessageQueue com . sun . m e s s a g i n g . T o p i c C o n n e c t i o n F a c t o r y c f= new com . sun . m e s s a g i n g . T o p i c C o n n e c t i o n F a c t o r y ( ) ; // c f . s e t P r o p e r t y ( imqBrokerHostName , h o s t ) ; // c f . s e t P r o p e r t y ( imqBrokerHostPort , 7 6 7 6 ) ; T o p i c C o n n e c t i o n conn=c f . c r e a t e T o p i c C o n n e c t i o n ( ) ; conn . s e t C l i e n t I D ( c l i e n t I D ) ; T o p i c S e s s i o n s e s s i o n= conn . c r e a t e T o p i c S e s s i o n ( f a l s e , S e s s i o n .AUTO ACKNOWLEDGE) ; Destination tResult = session . createTopic ( topic ) ; T o p i c S u b s c r i b e r consumer=
211
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 54 55 56 57 58
s e s s i o n . c r e a t e D u r a b l e S u b s c r i b e r ( ( Topic ) t R e s u l t , c l i e n t N a m e ) ; conn . s t a r t ( ) ; TextMessage txtMsg=(TextMessage ) consumer . r e c e i v e ( ) ; S t r i n g cmmdc=txtMsg . g e t T e x t ( ) ; session . close (); conn . c l o s e ( ) ; out . p r i n t l n ( <html><body b g c o l o r=\#c c b b c c \>< c e n t e r > ) ; out . p r i n t l n ( <h1> JSP Cmmdc </h1> ) ; out . p r i n t l n ( <p> ) ; out . p r i n t l n ( R e z u l t a t u l o b t i n u t : +cmmdc ) ; out . p r i n t l n ( </ c e n t e r ></body ></html> ) ; } catch ( E x c e p t i o n e ) { out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ; } out . c l o s e ( ) ; System . out . p r i n t l n ( S u b s c r i b e r f i n i s h e d ) ; } public void doPost ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { doGet ( req , r e s ) ; } }
In catalogul lib al servlet-ului trebuie incluse sierele jar ale serviciului JMS folosit.
9.5.10
Servlet cu jurnalizare
Exemplul 9.5.9 Servlet cu jurnalizare. Fi sierul log se va aa n catalogul aplicat iei si va oferit clientului spre consultare.
1 2 3 4 5 6 7 8 9 10 11 13 15 17 18 20 21 22
package l o g t e s t ; import j a v a . i o . IOException ; import j a v a x . s e r v l e t . S e r v l e t E x c e p t i o n ; import j a v a x . s e r v l e t . S e r v l e t C o n t e x t ; import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t ; import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t R e q u e s t ; import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t R e s p o n s e ; import j a v a x . s e r v l e t . S e r v l e t O u t p u t S t r e a m ; import j a v a . u t i l . l o g g i n g . Logger ; import j a v a . u t i l . l o g g i n g . F i l e H a n d l e r ; import j a v a . u t i l . l o g g i n g . S i m p l e F o r m a t t e r ; import j a v a x . s e r v l e t . a n n o t a t i o n . WebServlet ; @WebServlet ( u r l P a t t e r n s = / l o g g i n g ) public c l a s s L o g g e r S e r v l e t extends H t t p S e r v l e t { private s t a t i c Logger l o g g e r=Logger . g e t L o g g e r ( l o g t e s t . L o g g e r S e r v l e t ) ; public void i n i t ( ) { try { F i l e H a n d l e r l o g g i n g F i l e = new F i l e H a n d l e r ( webapps / l o g g e r / r e s u l t s . l o g ) ;
212
CAPITOLUL 9. SERVLET
23 24 25 26 27 28 29 31 32 33 35 36 37 39 40 41 42 43 44 45 46 47 48 49 50 52 53 54 55 56
l o g g i n g F i l e . s e t F o r m a t t e r ( new S i m p l e F o r m a t t e r ( ) ) ; l o g g e r . addHandler ( l o g g i n g F i l e ) ; } catch ( IOException e ) { System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ; } } public void doGet ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , j a v a . i o . IOException { S t r i n g f i l e S e p = System . g e t P r o p e r t y ( f i l e . s e p a r a t o r ) ; l o g g e r . i n f o ( INFO : H e l l o ) ; l o g g e r . warning ( WARN : H e l l o ) ; l o g g e r . s e v e r e ( ERROR : H e l l o ) ; r e s . setContentType ( t e x t / html ) ; j a v a . i o . P r i n t W r i t e r out = r e s . g e t W r i t e r ( ) ; out . p r i n t l n ( <html><head>< t i t l e > S e r v l e t l o g g i n g </ t i t l e ></head><body> ) ; out . p r i n t l n ( <h2> H e l l o from L o g g e r S e r v l e t </h2> ) ; out . p r i n t l n ( <br/> ) ; out . p r i n t l n ( <a h r e f =\ h t t p : / / + r e q . getServerName ()+ : + r e q . g e t L o c a l P o r t ()+ f i l e S e p+ l o g g e r +f i l e S e p+ r e s u l t s . l o g \> V i z u a l i z a t i f i s i e r u l l o g </a> ) ; out . p r i n t l n ( </body ></html> ) ; out . c l o s e ( ) ; } public void doPost ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , j a v a . i o . IOException { doGet ( req , r e s ) ; } }
9.6
FileUpload
Deseori clientul trebuie s a furnizeze unui servlet un volum mare de date, depozitate ntr-un sier. Un produs care ne ajut a s a ndeplinim acest obiectiv este commons-leupload - dezvoltat de apache. Commons-FileUpload - dezvoltat n cadrul apache - este un produs care simplic a transferul unui sier de la un client la programul server (le upload). Interfat a de programare a produsului se refer a la partea de server - n cazul de fat a reprezentat prin servlet. Instalarea produsului const a din dezarhivarea sierului desc arcat din Internet. In plus este nevoie de commons-io
9.6. FILEUPLOAD
213
Fi sierele commons-leupload-*.*.jar commons-io-*.*.jar se depun n catalogul lib al servlet-ului. Transferarea unui sier, din partea clientului nu ridic a nici o problem a. In sierul html de apelare, se dene ste un formular <form action=. . . enctype="multipart/form-data" method="post"> iar un sier de nc arcat se xeaz a prin intermediul marcajului <input type="file" name=. . . size=. . .> Programul navigator a seaz a o fereastr a de c autare, prin care clientul selecteaz a sierul pe care dore ste s a-l ncarce. Dac a partea de client este un program, atunci se utilizeaz a commonshttpclient, 9.5.1 De partea de server punem n evident a dou a sabloane de programare: Fi sierele nc arcate sunt ret inute naintea utiliz arii. Datele sierelor se utilizeaz a n ux, n momentul parvenirii lor. In primul caz, programarea nc arc arii revine la 1. Crearea unei fabrici pentru manipularea sierelor pe disc FileItemFactory factory = new DiskFileItemFactory(); 2. Crearea unei unelte de nc arcare ServletFileUpload upload = new ServletFileUpload(factory);
214
CAPITOLUL 9. SERVLET
Fiecare element al listei implementeaz a interfat a FileItem. Se pot xa parametrii dimensiunea zonei de pe disc destinat a datelor de nc arcat DiskFileItemFactory factory = new DiskFileItemFactory(); factory.setSizeThreshold(maxMemorySize); catalogul temporar de ret inere a datelor de nc arcat factory.setRepositoryPath(tempDirectory); sau direct DiskFileItemFactory factory = new DiskFileItemFactory( maxMemorySize, tempDirectory); dimensiunea maxim a a unui sier upload.setSizeMax(maxRequestSize); 4. Prelucrarea elementelor nc arcate 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 sier putem obt ine numele si valoarea atributului furnizat de client String name = item.getFieldName(); String value = item.getString(); 6. In cazul unui sier putem aa numele c ampului input, numele sierului, dimensiunea sierului
9.6. FILEUPLOAD
215
String fieldName = item.getFieldName(); String fileName = item.getName(); long sizeInBytes = item.getSize(); 7. Dac a dorim s a salv am sierul pe calculatorul server atunci prelucrarea este File uploadedFile = new File(...); item.write(uploadedFile); 8. Dac a datele sierului se ncarc a n memoria calculatorului atunci prelucrarea este InputStream in = item.getInputStream(); //preluarea datelor din fluxul in . . . in.close(); Alternativ, datele se pot ret ine ca un sir de octet i prin byte[] data = item.get(); Exemplul 9.6.1 S a se obt in a n memoria serverului matricea cont inut a ntr un sier text. In sierul text, ecare linie cont ine o linie a matricei, iar elementele sunt separate prin spat ii. Metoda getMatrix utilizat a va reface matricea din datele sierului.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
package u pl oa d ; import j a v a . i o . IOException ; import j a v a . i o . InputStream ; import j a v a . i o . InputStreamReader ; import j a v a . i o . B u f f e r e d R e a d e r ; import j a v a x . s e r v l e t . S e r v l e t E x c e p t i o n ; import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t ; import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t R e q u e s t ; import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t R e s p o n s e ; import j a v a x . s e r v l e t . S e r v l e t O u t p u t S t r e a m ; import j a v a x . s e r v l e t . a n n o t a t i o n . WebServlet ; import j a v a . u t i l . L i s t ; import j a v a . u t i l . I t e r a t o r ; import j a v a . u t i l . V e c t o r ; import o r g . apache . commons . f i l e u p l o a d . d i s k . D i s k F i l e I t e m F a c t o r y ; import o r g . apache . commons . f i l e u p l o a d . s e r v l e t . S e r v l e t F i l e U p l o a d ; import o r g . apache . commons . f i l e u p l o a d . F i l e I t e m F a c t o r y ; import o r g . apache . commons . f i l e u p l o a d . F i l e I t e m ;
216
CAPITOLUL 9. SERVLET
20 21 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
@WebServlet ( u r l P a t t e r n s = / u pl o ad ) public c l a s s F i l e U p l o a d S e r v l e t extends H t t p S e r v l e t { public void doPost ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { r e s . setContentType ( t e x t / p l a i n ) ; S e r v l e t O u t p u t S t r e a m out = r e s . getOutputStream ( ) ; try { F i l e I t e m F a c t o r y f a c t o r y = new D i s k F i l e I t e m F a c t o r y ( ) ; ServletFileUpload up lo ad = new S e r v l e t F i l e U p l o a d ( f a c t o r y ) ; L i s t i t e m s = up l oad . p a r s e R e q u e s t ( r e q ) ; u pl oa d . s e t S i z e M a x ( 1 0 0 0 0 0 0 ) ; I t e r a t o r i t e r=i t e m s . i t e r a t o r ( ) ; while ( i t e r . hasNext ( ) ) { F i l e I t e m item = ( F i l e I t e m ) i t e r . n e x t ( ) ; i f ( ! item . i s F o r m F i e l d ( ) ) { S t r i n g f i l e N a m e = item . getName ( ) ; out . p r i n t l n ( f i l e N a m e ) ; long s i z e I n B y t e s = item . g e t S i z e ( ) ; out . p r i n t l n ( s i z e I n B y t e s ) ; InputStream i n=item . g e t I n p u t S t r e a m ( ) ; InputStreamReader i s r =new InputStreamReader ( i n ) ; B u f f e r e d R e a d e r br=new B u f f e r e d R e a d e r ( i s r ) ; double [ ] [ ] m a t r i x=g e t M a t r i x ( br ) ; int m =m a t r i x . l e n g t h ; i n t n=m a t r i x [ 0 ] . l e n g t h ; f o r ( i n t i =0; i < m; i ++){ f o r ( i n t j =0; j <n ; j ++) out . p r i n t ( m a t r i x [ i ] [ j ]+ ) ; out . p r i n t l n ( ) ; } br . c l o s e ( ) ; isr . close (); in . close ( ) ; out . c l o s e ( ) ; } } } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( E x c e p t i o n : +e . g e t M e s s a g e ( ) ) ; } } private double [ ] [ ] g e t M a t r i x ( B u f f e r e d R e a d e r br ) throws E x c e p t i o n { Vector <Double > v=new Vector <Double > ( 1 0 ) ; double [ ] [ ] m a t r i x=n u l l ; try { String line , s ; i n t m=0 ,n , mn ; do { l i n e=br . r e a d L i n e ( ) ; i f ( l i n e != n u l l ) { m++; S t r i n g [ ] s t=l i n e . s p l i t ( ) ; for ( S t r i n g s : s t ){ v . addElement ( new Double ( s ) ) ; } } }
9.6. FILEUPLOAD
217
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
while ( l i n e != n u l l ) ; i f ( v . s i z e () > 0) { mn=v . s i z e ( ) ; n=mn/m; m a t r i x=new double [m ] [ n ] ; f o r ( i n t i =0; i < m; i ++){ f o r ( i n t j =0; j <n ; j ++){ m a t r i x [ i ] [ j ] = ( ( Double ) v . elementAt ( i n+j ) ) . d o u b l e V a l u e ( ) ; System . out . p r i n t ( m a t r i x [ i ] [ j ]+ ) ; } System . out . p r i n t l n ( ) ; } } } catch ( E x c e p t i o n e ) { throw new E x c e p t i o n ( e . g e t M e s s a g e ( ) ) ; } return m a t r i x ; } }
Pentru compilare se completeaz a variabila de sistem classpath cu referint a c atre sierul commons-fileupload-*.*.jar. Formularul clientului este
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
<html> <head> < s c r i p t l a n g u a g e= j a v a s c r i p t > < ! function checkIt (){ var f i s =document . l i n e a r . m y f i l e . value ; i f ( f i s== ) { a l e r t ( S e l e c t a t i f i s i e r u l corespunzator matricei ); return f a l s e ; } return true ; } // > </ s c r i p t> </ head> <body> <h1> I n c ă r c a r e a unui f i ş i e r </ h1> <form method= p o s t action= u pl oa d e n c t y p e= m u l t i p a r t / form data name= l i n e a r onSubmit= r e t u r n c h e c k I t ( ) > <p> S e l e c t a ţ i f i ş i e r u l <p> <input type= f i l e name= m y f i l e s i z e =30> <p> <input type= submit value= Expediaza f i s i e r u l > </ form> </ body> </ html>
package u pl oa d ;
218
CAPITOLUL 9. SERVLET
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 19 21 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 60
import import import import import import import import import import import import import import import import
j a v a . i o . IOException ; j a v a . i o . InputStream ; j a v a . i o . InputStreamReader ; java . i o . BufferedReader ; javax . s e r v l e t . ServletException ; javax . s e r v l e t . http . HttpServlet ; javax . s e r v l e t . http . HttpServletRequest ; javax . s e r v l e t . http . HttpServletResponse ; javax . s e r v l e t . ServletOutputStream ; j a v a x . s e r v l e t . a n n o t a t i o n . WebServlet ; java . u t i l . List ; java . u t i l . I t e r a t o r ; java . u t i l . Vector ; o r g . apache . commons . f i l e u p l o a d . s e r v l e t . S e r v l e t F i l e U p l o a d ; o r g . apache . commons . f i l e u p l o a d . F i l e I t e m I t e r a t o r ; o r g . apache . commons . f i l e u p l o a d . F i l e I t e m S t r e a m ;
@WebServlet ( u r l P a t t e r n s = / u pl o ad ) public c l a s s F i l e U p l o a d S e r v l e t extends H t t p S e r v l e t { public void doPost ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { r e s . setContentType ( t e x t / p l a i n ) ; S e r v l e t O u t p u t S t r e a m out = r e s . getOutputStream ( ) ; try { S e r v l e t F i l e U p l o a d up lo ad = new S e r v l e t F i l e U p l o a d ( ) ; F i l e I t e m I t e r a t o r i t e r = up l oad . g e t I t e m I t e r a t o r ( r e q ) ; while ( i t e r . hasNext ( ) ) { F i l e I t e m S t r e a m item = i t e r . n e x t ( ) ; S t r i n g name = item . getFieldName ( ) ; out . p r i n t l n ( name ) ; i f ( ! item . i s F o r m F i e l d ( ) ) { S t r i n g f i l e N a m e = item . getName ( ) ; out . p r i n t l n ( f i l e N a m e ) ; InputStream i n=item . openStream ( ) ; InputStreamReader i s r =new InputStreamReader ( i n ) ; B u f f e r e d R e a d e r br=new B u f f e r e d R e a d e r ( i s r ) ; double [ ] [ ] m a t r i x=g e t M a t r i x ( br ) ; int m =m a t r i x . l e n g t h ; i n t n=m a t r i x [ 0 ] . l e n g t h ; f o r ( i n t i =0; i < m; i ++){ f o r ( i n t j =0; j <n ; j ++) out . p r i n t ( m a t r i x [ i ] [ j ]+ ) ; out . p r i n t l n ( ) ; } br . c l o s e ( ) ; isr . close (); in . close ( ) ; out . c l o s e ( ) ; } } } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( E x c e p t i o n : +e . g e t M e s s a g e ( ) ) ; } } private double [ ] [ ] g e t M a t r i x ( B u f f e r e d R e a d e r br ) throws E x c e p t i o n { . . . }
219
62
9.7
Consider am cazul: Exemplul 9.7.1 Fi sierul ales de client dintr-o lista disponibil a este desc arcat ind transmis navigatorului.
1 2 3 4 5 6 7 8 9 10 12 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 34 35 36 37 38
import import import import import import import import import import
j a v a . i o . IOException ; javax . s e r v l e t . ServletException ; javax . s e r v l e t . http . HttpServlet ; javax . s e r v l e t . http . HttpServletRequest ; javax . s e r v l e t . http . HttpServletResponse ; javax . s e r v l e t . ServletOutputStream ; j a v a x . s e r v l e t . a n n o t a t i o n . WebServlet ; j a v a . n i o . f i l e . Path ; j a v a . n i o . f i l e . Paths ; java . nio . f i l e . F i l e s ;
@WebServlet ( u r l P a t t e r n s = / download ) public c l a s s D o w n l o a d S e r v l e t extends H t t p S e r v l e t { public void doGet ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { S e r v l e t O u t p u t S t r e a m out=r e s . getOutputStream ( ) ; S t r i n g f i l e =r e q . g e t P a r a m e t e r ( f i l e ) ; System . out . p r i n t l n ( f i l e ) ; Path c a l e=Paths . g e t ( webapps / download / r e s o u r c e s / + f i l e ) ; try { System . out . p r i n t l n ( c a l e+ f i l e ) ; r e s . setContentType ( A p p l i c a t i o n / Octet stream ) ; r e s . addHeader ( Content D i s p o s i t i o n , attachment ; f i l e n a m e=+ f i l e ) ; F i l e s . copy ( c a l e , out ) ; } catch ( E x c e p t i o n e ) { r e s . setContentType ( t e x t / p l a i n ) ; out . p r i n t l n ( C e r e r e a d v o a s t r a nu p o a t e f i s a t i s f a c u t a ) ; } out . c l o s e ( ) ; } public void doPost ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { doGet ( req , r e s ) ; } }
R andul 18 are ca efect p astrarea numelui si a extensiei pentru sierul selectat a se desc arca.
220
CAPITOLUL 9. SERVLET
9.8
Filtru
Un ltru se asemean a unui servlet, dar activitatea ntreprins a vizeaz a uzual context ul, adic a ansamblul servlet ilor care fac parte din aplicat ia Web. Un ltru se declar a n sierul 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 ltrului implementeaz a interfat a Filter, adic a metodele public void init(FilterConfig lterCong ) throws ServletException public void destroy() public void doFilter(ServletRequest request, ServletResponse response, FilterChain lterChain ) throws IOException, ServletException Exemplul 9.8.1 Contextul myservlet cont ine doi servlet i HelloServlet si CmmdcServlet, apelabili respectiv din hello.html, cmmdc.html. S a se programeze un ltru care Redirecteaz a solicitarea /myservlet/hello c atre /cmmdc.html. Dac a se cere ca natura r aspunsului s a e text/xml atunci invalideaz a cererea. Servlet ii HelloServlet si CmmdcServlet sunt cei dezvoltat i la nceputul acestui capitol. Filtrul are codul
9.8. FILTRU
221
1 2 3 4 5 6 7 8 9 10 12 13 15 16 17 19 20 21 23 24 25 26 27 28 29 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
import import import import import import import import import import
j a v a . i o . IOException ; javax . s e r v l e t . ServletRequest ; javax . s e r v l e t . ServletResponse ; javax . s e r v l e t . RequestDispatcher ; javax . s e r v l e t . F i l t e r ; javax . s e r v l e t . F i l t e r C o n f i g ; javax . s e r v l e t . FilterChain ; javax . s e r v l e t . ServletException ; javax . s e r v l e t . http . HttpServletRequest ; javax . s e r v l e t . http . HttpServletResponse ;
public c l a s s M y F i l t e r D i s p a t c h e r implements F i l t e r { private F i l t e r C o n f i g f i l t e r C o n f i g ; public void i n i t ( F i l t e r C o n f i g f i l t e r C o n f i g ) throws S e r v l e t E x c e p t i o n { this . f i l t e r C o n f i g = f i l t e r C o n f i g ; } public void d e s t r o y ( ) { this . f i l t e r C o n f i g = null ; } public void d o F i l t e r ( S e r v l e t R e q u e s t r e q u e s t , S e r v l e t R e s p o n s e r e s p o n s e , F i l t e r C h a i n f i l t e r C h a i n ) throws IOException , S e r v l e t E x c e p t i o n { HttpServletRequest req = ( HttpServletRequest ) request ; HttpServletResponse res = ( HttpServletResponse ) response ; S t r i n g u r i = r e q . getRequestURI ( ) ; System . out . p r i n t l n ( F i l t e r URI= +u r i ) ; System . out . p r i n t l n ( u r i ) ; i f ( u r i . equals ( / myservlet ) | | u r i . equals ( / myservlet / ) ) f i l t e r C h a i n . doFilter ( request , response ) ; else { i f ( u r i . equals ( / myservlet / h e l l o )){ S t r i n g d i s p a t c h e r U r i= /cmmdc . html ; R e q u e s t D i s p a t c h e r rd=r e q u e s t . g e t R e q u e s t D i s p a t c h e r ( d i s p a t c h e r U r i ) ; rd . f o r w a r d ( r e q u e s t , r e s p o n s e ) ; } else { i f ( u r i . e q u a l s ( / m y s e r v l e t /cmmdc ) ) { S t r i n g t i p=r e q . g e t P a r a m e t e r ( t i p ) ; i f ( t i p . e q u a l s ( t e x t /xml ) ) { r e s . s e n d E r r o r ( H t t p S e r v l e t R e s p o n s e . SC FORBIDDEN ) ; } } f i l t e r C h a i n . doFilter ( request , response ) ; } } } }
<? xml version= 1 . 0 e n c o d i n g=ISO 8859 1 ?> < !D O C T Y P E webapp PUBLIC //Sun Microsystems , I n c . / /DTD Web A p p l i c a t i o n 2 . 3 / /EN h t t p : // j a v a . sun . com/ dtd /weba p p 2 3 . dtd > <webapp>
222
CAPITOLUL 9. SERVLET
7 8 9 10 12 13 14 15 16
< f i l t e r> < f i l t e r name> f i l t e r D i s p a t c h e r </ f i l t e r name> < f i l t e r c l a s s > M y F i l t e r D i s p a t c h e r</ f i l t e r c l a s s > </ f i l t e r > < f i l t e r mapping> < f i l t e r name> f i l t e r D i s p a t c h e r </ f i l t e r name> < u r l p a t t e r n>/ </ u r l p a t t e r n> </ f i l t e r mapping> </webapp>
<html> <head> < t i t l e> Cmmdc S e r v l e t </ t i t l e > </ head> <body bgcolor=#c c b b c c > <center> <h1> Cmmdc S e r v l e t </ h1> <form method= g e t action= h t t p : / / l o c a l h o s t : 8 0 8 0 / m y s e r v l e t /cmmdc> <table border= 1 > < tr> <td> Primul numar </ td> <td> <input type= t e x t name=m s i z e =10> </ td> </ tr> < tr> <td> Al d o i l e a numar </ td> <td> <input type= t e x t name=n s i z e =10> </ td> </ tr> < tr> <td> Natura r a s p u n s u l u i </ td> <td> < s e l e c t name= t i p > <option value= t e x t / html > t e x t / html <option value= t e x t / p l a i n > t e x t / p l a i n <option value= t e x t /xml> t e x t /xml </ s e l e c t> </ td> </ tr> < tr> <td> <input type= submit value= C a l c u l e a z a > </ td> <td></ td> </ tr> </ table> </ form> </ center> </ body> </ html>
223
9.9
n:
Eveniment si auditor
Tehnologia Servlet permite urm arirea si intervent ia de c atre serverul Web ciclul de viat a al unui servlet, prin interfat a javax.servlet.ServletContextListener evolut ia obiectului javax.servlet.http.HttpSession prin interfat a javax.servlet.http.HttpSessionListener Interfat a ServletContextListener declar a metodele void contextInitialized(ServletContextEvent sec ) void contextDestroyed(ServletContextEvent sec ) Interfat a HttpSessiontListener declar a metodele void sessionCreated(HttpSessionEvent hse ) void sessionDestroyed(HttpSessionEvent hse ) Clasa care implementeaz a una din aceste interfet e se declar a n sierul web.xml printr-un element <listener>> <listener> <listener-class> clasa_listener </listener-class> </listener> Exemplul 9.9.1 Auditor care sesizeaz a nc arcarea si disparit ia unui servlet a s and n fereastra DOS a serverului Web un mesaj.
1 2 3 5 6 7 8 9 10 11 12 13 14 15 16 17
import j a v a x . s e r v l e t . S e r v l e t C o n t e x t L i s t e n e r ; import j a v a x . s e r v l e t . S e r v l e t C o n t e x t E v e n t ; import j a v a x . s e r v l e t . S e r v l e t C o n t e x t ; public c l a s s F i r s t C o n t e x t L i s t e n e r implements S e r v l e t C o n t e x t L i s t e n e r { public void c o n t e x t D e s t r o y e d ( S e r v l e t C o n t e x t E v e n t e v e n t ) { System . out . p r i n t l n ( Web app was removed . ) ; } public void c o n t e x t I n i t i a l i z e d ( S e r v l e t C o n t e x t E v e n t e v e n t ) { System . out . p r i n t l n ( Web app i s r e a d y . ) ; S e r v l e t C o n t e x t s c=e v e n t . g e t S e r v l e t C o n t e x t ( ) ; System . out . p r i n t l n ( s c . g e t C o n t e x t P a t h ( ) ) ; System . out . p r i n t l n ( s c . g e t E f f e c t i v e M a j o r V e r s i o n ( ) ) ; System . out . p r i n t l n ( s c . g e t E f f e c t i v e M i n o r V e r s i o n ( ) ) ; } }
CAPITOLUL 9. SERVLET
import j a v a x . s e r v l e t . h t t p . H t t p S e s s i o n L i s t e n e r ; import j a v a x . s e r v l e t . h t t p . H t t p S e s s i o n E v e n t ; public c l a s s F i r s t S e s s i o n L i s t e n e r implements H t t p S e s s i o n L i s t e n e r { static int u s e r s = 0 ; public void s e s s i o n C r e a t e d ( H t t p S e s s i o n E v e n t e ) { u s e r s ++; } public void s e s s i o n D e s t r o y e d ( H t t p S e s s i o n E v e n t e ) { u s e r s ; } public s t a t i c i n t g e t C o n c u r r e n t U s e r s ( ) { return u s e r s ; } }
9.10
Intr-o clas a Java se poate ncorpora un server tomcat n care pot instalate una sau mai mult i servet i. Resursele necesare sunt cont inute n apache-tomcat*-embedded, iar sierele jar cont inute trebuie declarate n variabila de sistem classpath. S ablonul de programare este:
1 2 3 5 6 7 8 9 10 12 13 15 16 18 19 20 21 22 23 24 25
import o r g . apache . c a t a l i n a . s t a r t u p . Tomcat ; import o r g . apache . c a t a l i n a . Context ; import j a v a . i o . F i l e ; public c l a s s EmbeddedTomcat { public s t a t i c void main ( S t r i n g [ ] a r g s ) { try { Tomcat tomcat = new Tomcat ( ) ; tomcat . s e t B a s e D i r ( . ) ; tomcat . s e t P o r t ( 9 0 9 0 ) ; // p o r t u l s e r v e r u l u i F i l e docBase = new F i l e ( . ) ; Context c t x t = tomcat . addContext ( / , docBase . g e t A b s o l u t e P a t h ( ) ) ; Tomcat . a d d S e r v l e t ( c t x t , n u m e S e r v l e t , new C l a s a S e r v l e t ( ) ) ; c t x t . a d d S e r v l e t M a p p i n g ( /numeApel , n u m e S e r v l e t ) ; tomcat . s t a r t ( ) ; tomcat . g e t S e r v e r ( ) . a w a i t ( ) ; } catch ( E x c e p t i o n e ) { e . printStackTrace ( ) ; } } }
225
226
CAPITOLUL 9. SERVLET
Tipul tehnologiei JSP este denumit procesare de sabloane (template engine). JSP este o tehnologie similar a cu PHP, ASP.NET, apache-velocity, etc. JSP permite includerea de cod Java ntr-un document html. Un asemenea document se depoziteaz a ntr-un server Web, container de servlet, cu extensia jsp, eventual jspx. Apelarea documentului JSP se realizeaz a prin meniul File/Open a unui navigator, cu http://host:port/cale/doc.jsp referint a 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 nt elege calea de la catalogul webapps p an a la catalogul ce cont ine sierul jsp. Vom depozita sierele JSP ntr-un catalog jsp din arborele webapps |--> JSPApp | |--> WEB-INF | | |--> classes | | | web.xml 227
doc.jsp
n Hello.jsp si plas andu-l n catalogul jsp se obt ine acela si efect, dar prelucrarea paginilor / documentelor este diferit a. Fi sierul html este prelucrat doar de programul navigator si poate deschis ca sier, n timp ce sierul JSP este prelucrat de serverul Web cu a sarea prin intermediul navigatorului. Prelucrarea efectuat a de serverul Web const a din transformarea paginii / documentului JSP ntr-un servlet, care este compilat si lansat n execut ie. Din aceastr a cauz a prima invocare a paginii / documentului JSP dureaz a mai mult dec at apel arile ulterioare. Fi sierul JSP poate construit pe un document xhtml, av and 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 Exist a dou a moduri de a include elemente JSP ntr-un text html: prin elemente specice JSP. Fi sierul are extensia jsp si se nume ste pagin a JSP. prin elemente xml apart in and spat iului de nume http://java.sun.com/JSP/Page Fi sierul poate avea extensia jsp sau jspx si se nume ste document JSP. Comentariile JSP se scriu de forma <%-- Comentariu --%>
229
Consider am urm atorul exemplu introductiv: Exemplul 10.1.1 Putem a sa valoarea unei variabile Java (de exemplu data calendaristic a) prin Varianta paginii JSP
1 2 3 4 5 7 8 9 10 12 13 14 15 16 17
<html> <body> <p> Data c a l e n d a r i s t i c a 1 : < %= new j a v a . u t i l . Date ( ) % > <p> <% j a v a . u t i l . Date data1=new j a v a . u t i l . Date ( ) ; % > Data c a l e n d a r i s t i c a 2 : < %= data1 % > <p> <% j a v a . u t i l . Date data2=new j a v a . u t i l . Date ( ) ; % > Data c a l e n d a r i s t i c a 3 : <% out . p r i n t ( data2 ) ; % > </ body> </ html>
Dac a se utilizeaz a operatorul de a sare = atunci dup a expresia de a sat nu se pune ;. Variabila predenit a out este de tip javax.servlet.jsp.JspWriter. Varianta documentului JSP
1 2 3 4 5 6 7 8 9
<? xml v e r s i o n= 1 . 0 e n c o d i n g=UTF8 ?> <html xmlns : j s p= h t t p : / / j a v a . sun . com/JSP/ Page > <body> <j s p : s c r i p t l e t> j a v a . u t i l . Date d=new j a v a . u t i l . Date ( ) ; </ j s p : s c r i p t l e t > < j s p : e x p r e s s i o n> d </ j s p : e x p r e s s i o n> </ body> </ html>
Codul Java nglobat ntr-un text html se nume ste scriptlet. Sintaxa utilizat a este Varianta paginii JSP <% cod Java %>
<jsp:scriptlet> codJava </jsp:scriptlet> Domeniul de valabilitate. Domeniul de valabilitate dene ste intervalul de timp, de existent a al unui obiect, ind denit prin valorile: Valoare page request Domeniu de valabilitate pagina curent a n pagina curent a, n paginile incluse si n paginile c atre care se face o redirectare session n sesiunea curent a application pe durata rul arii aplicat iei In orice pagin a Variabila out request response session page pageContext application exception Astfel String request.getParameter(String numeParametru ) furnizeaz a valoarea parametrului numeParametru dintr-un formular html. Exemplul 10.1.2 Pagina JSP Hello: Clientul transmite numele paginii care i r aspunde cu mesajul de salut Hi + nume + !. Codul paginii JPS (hello.jsp ) este
1 2 3 4 5
/ document JSP sunt predenite obiectele: Tip/Clasa javax.servlet.jsp.JspWriter javax.servlet.ServletRequest javax.servlet.ServletResponse javax.servlet.http.HttpSession java.lang.Object, this javax.servlet.jsp.PageContext javax.servlet.ServletContext ServletContext.getServletCong().getContext() java.lang.Throwable
231
6 7 8 9 10 11 12 13 14
<center> <h1> Pagina de r ă spuns </ h1> <p> <% out . p r i n t l n ( Hi +r e q u e s t . g e t P a r a m e t e r ( name)+ ! ) ; % > </ center> </ body> </ html>
<html> <head> < t i t l e > JSP H e l l o </ t i t l e > </ head> <body bgcolor=#bbeebb > <center> <h1> Pagina de a p e l a r e JSP </ h1> <form method= p o s t action= j s p / h e l l o . j s p > <p> Numele : <input type= t e x t name=name s i z e =20> <p> <input type= submit > </ form> </ center> </ body> </ html>
Compilarea si arhivarea servlet-ului o vom realiza prin intermediul lui apache-ant. In acest scop se creaz a structura:
jsphello | |--> src | |--> web | | | |--> jsp | | | | hello.jsp | | |--> WEB-INF | | | |--> classes | | | |--> lib | | | | web.xml | | | index.html
< p r o j e c t b a s e d i r= . default= g e n e r a t e . war > < p r o p e r t y name= d i s t . name v a l u e=JSPApp /> < p r o p e r t y name= d i s t . d i r v a l u e= d i s t /> <path i d= m y c l a s s p a t h > < f i l e s e t d i r=web/WEB INF/ l i b > < i n c l u d e name= . j a r /> </ f i l e s e t > </ path> < t a r g e t name= i n i t > < d e l e t e d i r= $ { d i s t . d i r } />
232
< d e l e t e d i r=web/WEB INF/ c l a s s e s /> <mkdir d i r=web/WEB INF/ c l a s s e s /> <mkdir d i r= $ { d i s t . d i r } /> </ t a r g e t> < t a r g e t name= c o m p i l e depends= i n i t > < j a v a c c l a s s p a t h r e f= m y c l a s s p a t h s r c d i r= s r c d e s t d i r=web/WEB INF/ c l a s s e s i n c l u d e a n t r u n t i m e= f a l s e /> </ t a r g e t>
13 14 15 16 18 19 20 21 22 23 25 26 27 28
< t a r g e t name= g e n e r a t e . war depends= c o m p i l e > < j a r d e s t f i l e = $ { d i s t . d i r } /$ { d i s t . name } . war b a s e d i r=web /> </ t a r g e t> </ p r o j e c t>
10.1.1
Declarat ii JSP
Printr-o declarat ie JSP, putem deni c ampuri(variabile) si metode Java ce pot apoi folosite, respectiv apelate n documentul respectiv. O declarat ie JSP se dene ste printr-un marcaj <%! . . . %> sau, n format XML <jsp:declaration> . . . </jsp:declaration> Exemplul 10.1.3 Calculul celui mai mare divizor comun a dou a numere naturale cu metoda de calcul este denit a ntr-o declarat ie JSP. Pagina JSP a aplicat iei cmmdc.jsp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
<html> <body> <H1 > CMMDC </H1 > <%! l o n g cmmdc( l o n g m, l o n g n ) { . . . } % > Rezultatul este <% String sm=r e q u e s t . g e t P a r a m e t e r ( m ) ; String sn=r e q u e s t . g e t P a r a m e t e r ( n ) ; long m =Long . pa rse Lo ng ( sm ) , n=Long . pa rse Lo ng ( sn ) ; out . p r i n t l n (cmmdc(m, n ) ) ; % > </ body> </ html>
233
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
<html> <body> <h1> C a l c u l u l Cmmdc </ h1> <form method= p o s t action= j s p /cmmdc . j s p > <p> Primul numar e s t e <input type= t e x t name=m value= s i z e =5> <p> Al d o i l e a numar e s t e <input type= t e x t name=n value= s i z e =5> <p> <input type= submit value= C a l c u l e a z a > <input type= r e s e t value=Abandon> </ form> </ body> </ html>
Exist a dou a metode jspInit() si jspDestroy() care dac a sunt declarate de programator atunci sunt executate la nceputul si la sf ar situl ciclului de viat a a paginii / documentului JSP. Exemplul 10.1.4 Metoda jspInit init ializeaz a un num ar cu 0 iar metoda jspDestroy a seaz a num arul pe calculatorul serverului. Un client introduce un num ar care este adunat la cel ret inut de pagina JSP. Efectul metodei jspDestroy are loc n urma opririi aplicat iei JSP. Codul paginii JSP este
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
<html> <head> < t i t l e > I n i t </ t i t l e > </ head> <body> <%! i n t numar ; public void j s p I n i t (){ numar=0; } public void jspDestroy (){ System . out . p r i n t l n ( numar ) ; } % > <center> <h1> Pagina de r ă spuns </ h1> <p> <% String sn=r e q u e s t . g e t P a r a m e t e r ( numar ) ; i n t n=I n t e g e r . p a r s e I n t ( sn ) ; numar+=n ; out . p r i n t l n ( Numarul e s t e : +numar ) ; % > </ center> </ body> </ html>
234
10.1.2
Directive JSP
Directivele JSP xeaz a informat ii pentru tot documentul jsp. O directiv a jsp se indic a prin marcajul <%@ directiv a atribut1 atribut2 . . . %> sau n format XML <jsp:directive.directiva atribut1 atribut2 . . . /> unde ecare atribut are sintaxa nume=valoare. Directivele pot : page, include, taglib. Directiva page. Ment ion am atributele list a de pachete separate prin , text Informat ia se poate reg asi apel and metoda getServletInfo() errorPage= adresa url a paginii ce trateaz a except ia isErrorPage= "true | false" import= info= Directiva include permite includerea unor siere .html sau .jsp n document <%@ include file= sier html, jsp %> Includerea are loc n locul n care apare directiva. Referint a la sierul html sau jsp se face relativ la catalogul paginii JSP init iale (adic a cea n care apare directiva). Directiva taglib indic a bibliotecile de marcaje utilizate n documentul jsp, av and atributele uri= uri - Universal Resource Identier - a bibliotecii de marcaje prefix= prexul marcajului
10.1.3
Un marcaj JSP dene ste o act iune care se execut a n timpul proces arii paginii jsp. Sintaxa marcajelor JSP seam an a cu cea a marcajelor html sau xml <prefix : marcaj atribute />
235
Dintre marcajele JSP predenite adic a cu prexul JSP amintim: <jsp : <jsp : include page=numeFi sier jsp sau html /> forward page=numeFi sier jsp sau html />
Prelucrarea care urmeaz a va cea din sierul ment ional. Diferent a dintre cele dou a elemente const a n faptul c a include prevede revenirea n pagina JSP init ial a iar forward nu. Referint a la sierul html sau jsp se face relativ la catalogul paginii JSP init iale. In cazul marcajelor <jsp: include>, <jsp: forward> se pot transmite parametri prin marcajele incluse <jsp:param name="nume " value=valoare "/> sau <jsp:params> <jsp:param name="nume " value=valoare "/> . . . . . . </jsp:params> <jsp : useBean id=numeComponent aJava class=numeClasa scope=domeniu />
unde domeniu precizeaz a domeniul de valabilitate al componentei Java, adic a page, request, session, application. Creaz a un obiect numeComponent aJava de tip numeClasa av and domeniul de valabilitate dat a de domeniu. <jsp : setProperty name=numeComponent aJava property=numeProp value=valoare />
Acest marcaj este echivalent cu codul Java numeComponent aJava .setNumeProp(valoare). <jsp : setProperty name=numeComponent aJava property="*" /> vizeaz a toate propriet a tile componentei Java, xarea valorilor f ac anduse cu datele unui formular. Numele parametrilor din formularele de introducere a datelor trebuie s a coincid a cu identicatorii c ampurilor din componenta Java corespunz atoare.
236 <jsp :
10.1.4
Clasa componentei Java care se va utiliza ntr-o pagin a JSP trebuie inclus a ntr-un pachet. Relu am exemplul 10.1.2 cu o component a Java corespunz atoare numelui din formularul index.html. Exemplul 10.1.5
1 2 3 4 5 6 7 8 9 10
package j s p ; public c l a s s H e l l o B e a n { private S t r i n g name= ; public S t r i n g getName ( ) { return name ; } public void setName ( S t r i n g name ) { t h i s . name=name ; } }
< j s p : useBean id= o b j c l a s s= j s p . H e l l o B e a n scope= r e q u e s t /> < j s p : s e t P r o p e r t y name= o b j p r o p e r t y= /> <html> <head> < t i t l e > j s p h e l l o </ t i t l e > </ head> <body> <h1> Pagina de r ă spuns </ h1> <center> <% out . p r i n t l n ( Hi +o b j . getName ()+ ! ) ; % > </ center> </ body> </ html>
Mai mult, se poate include formularul n pagina JSP, bine nt eles sterg andu-l din sierul html:
1 2 3 4 5 6
< j s p : useBean id= o b j c l a s s= j s p . H e l l o B e a n scope= r e q u e s t /> < j s p : s e t P r o p e r t y name= o b j p r o p e r t y= /> <html> <head> < t i t l e > j s p h e l l o </ t i t l e > </ head>
237
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
<body> <center> <h1> Pagina JSP a p l i c a ţ i a H e l l o </ h1> <form method= p o s t > <p> <h3> I n t r o d u c e t i numele : </ h3> <input type= t e x t name=name s i z e =20> <p> <input type= submit > </ form> <p> <% out . p r i n t l n ( Hi +o b j . getName ()+ ! ) ; % > </ center> </ body> </ html>
Exemplul 10.1.6 Pagin a JSP pentru calculul celui mai mare divizor comun cu metoda de calcul denit a ntr-o component a Java. Utiliz and documentului html din Exemplul 10.1.3 se dene ste componenta Java
1 2 3 4 5 7 8 9 10 11 12 13 14 15 16 17 18 20 21 22 23 24 26 28
package cmmdc ; public c l a s s CmmdcBean { private S t r i n g m = ; private S t r i n g n= ; private S t r i n g cmmdc ; public void setM ( S t r i n g m) { t h i s .m = m; } public void setN ( S t r i n g n ) { t h i s . n=n ; } public S t r i n g getM ( ) { return m; } public S t r i n g getN ( ) { return n ; } public S t r i n g getCmmdc ( ) { long a=Long . par se Lon g (m) ; long b=Long . p ars eL ong ( n ) ; return ( new Long (cmmdc( a , b ) ) ) . t o S t r i n g ( ) ; } long cmmdc( long m, long n ) { . . . } }
Instant iem o componenta Java si i x am propriet a tile (adic a i transmitem parametri problemei) dup a care apel am metoda ce calculeaz a rezultatul dorit n pagina JSP:
238
1 2 3 4 5 6 7 8 9 10
< j s p : useBean id= o b j c l a s s=cmmdc . CmmdcBean scope= a p p l i c a t i o n /> < j s p : s e t P r o p e r t y name= o b j p r o p e r t y= /> <html> <body> Cel mai mare d i v i z o r comun a l n u m e r e l o r <p> < %=o b j . getM ( ) % > si < %=o b j . getN ( ) % > este < %=o b j . getCmmdc ( ) % > </ body> </ html>
1 2 3 4 5 6 7 8 9 10 11 12 13 14
<% @ page e r r o r P a g e= e r r o r p a g e . j s p % > <html> <body> <% String m a t e r i a=r e q u e s t . g e t P a r a m e t e r ( m a t e r i a ) . t r i m ( ) ; i f ( m a t e r i a . e q u a l s ( AN ) ) { out . p r i n t l n ( <hr >< f o n t c o l o r=red > A l e g e r e c o r e c t a ! < / f o n t > ) ; } else{ throw new E x c e p t i o n ( N a t i f a c u t a l e g e r e a c o r e c t a ) ; } % > </ body> </ html>
< ! Aceste comentarii sunt f o a r t e importante in c a z u l u t i l i z a r i i n a v i g a t o r u l u i IE s i a l u i apache tomcat 5 . . . / 6 . . . In l i p s a l o r nu s e g e n e r e a z a s a l t u l l a e x c e p t i e p r i n p a g i n a j s p . R o l u l c o m e n t a r i i l o r e s t e marirea l u n g i m i i f i s i e r u l u i de f a t a . O a l t e r n a t i v a e s t e ca d i n IE6 . . . O p t i o n s sa s e d e z a c t i v e z e o p t i u n e a Show f r i e n d l y HTTP e r r o r message Cu n a v i g a t o r u l F i r e f o x nu e x i s t a a c e a s t a problema . > <% @ page i s E r r o r P a g e= t r u e % > <html> <body> <div a l i g n= c e n t e r > < %= e x c e p t i o n . g e t M e s s a g e ( ) % > </ div> </ body> </ html>
239
apelate prin
<html> <body> <form method=p o s t action= j s p / e r r h a n d l e r . j s p > Care e s t e m a t e r i a p r e f e r a t a d i n a n i i de s t u d i u u n i v e r s i t a r ? <p> A l g o r i t m i c a s i programare <input type= r a d i o name= m a t e r i a value=AP checked> <p> A n a l i z a numerica <input type= r a d i o name= m a t e r i a value=AN> <p> Inteligenta artificiala <input type= r a d i o name= m a t e r i a value=IA> <p> <input type=submit> </ form> </ body> </ html>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
10.2
JSTL este o familie de biblioteci de marcaje ce ofer a o serie de facilit a ti activit a tii de realizare a paginilor Web. JSTL ajut a la separarea activit a tii de programare de aceea a proiectare (design) a paginii Web. JSTL este alc atuit a din 5 biblioteci: URI Descriere http://java.sun.com/jsp/jstl/core Biblioteca de baz a http://java.sun.com/jsp/jstl/xml Biblioteca de prelucrare a documentelor xml http://java.sun.com/jsp/jstl/fmt Biblioteca de formatare a datelor http://java.sun.com/jsp/jstl/sql Biblioteca de lucru cu baze de date http://java.sun.com/jsp/jstl/functions Biblioteca de funct ii ajut atoare Instalarea bibliotecilor. Bibliotecile sunt livrate mpreun a cu apachetomcat-* n catalogul apache-tomcat-*\webapps\examples\WEB-INF\lib prin sierele jstl.jar si standard.jar. Utilizarea bibliotecilor. In vederea utiliz arii, cele dou a siere trebuie copiate n catalogul lib al aplicat iei care utilizeaz a bibliotecile. In pagina / documentul JSP, o bibliotec a utilizat a trebuie declarat a printro directiv a taglib.
240
10.2.1
Biblioteca de baz a
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> Marcaje din biblioteca de baz a: c:set Fixeaz a o valoare ntr-o variabil a. Atribute ale marcajului: Atribut Fel Descriere var obligatoriu Numele variabilei ce va stoca valoarea expresiei. value opt ional Expresia care va evaluat a si atribuit a variabilei scope opt ional Domeniul de valabilitate al variabilei. Unul din valorile: page, request, session, application. Referirea la o variabil a se face prin sintaxa ${numeVariabil a} Referirea la valoarea unui c amp dintr-un formular se face prin ${param.numeC amp } Al aturi de obiectul param, alte obiecte predenite sunt cookie, header, initParam, pageContext. Se pot deni variabile cu acela si nume dar av and domenii de valabilitate diferit a. Referirea se face prin ${pageScope.numeVariabil a }, ${requestScope.numeVariabil a }, ${sessionScope.numeVariabil a }, ${applicationScope.numeVariabil a }. Plas and clauza empty naintea unei variabile, ${empty numeVariabil a }, se obt ine false sau true dup a cum variabila are sau nu atribuit a o valoare. c:remove S terge o variabil a. Atribute ale marcajului: Atribut Fel Descriere var obligatoriu Numele variabilei ce se sterge. scope opt ional Domeniul de valabilitate al variabilei. Unul din valorile: page, request, session, application.
241
c:out A seaz a o valoare. Atribute ale marcajului: Atribut value default Fel Descriere obligatoriu Valoarea ce se evalueaz a si se a seaz a. opt ional Cea ce se a seaz a n cazul n care expresia nu poate evaluat a. escapeXml opt ional true / false. Valoarea implicit a este true. Pe false interpreteaz a caracterele din value ca si cod html. c:if Test, vericarea unei condit ii. Atribute ale marcajului: Atribut Fel Descriere test obligatoriu Condit ia de test. var opt ional Numele variabilei ce va stoca valoarea testului. scope opt ional Domeniul de valabilitate al variabilei denit a anterior. In cazul n care condit ia are valoarea true se prelucreaz a corpul marcajului, n caz contrar, acesta este ignorat. Exemplul 10.2.1 Preluarea datelor unui formular cu c ampurile de intrare nume, prenume si email se face prin pagina JSP
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
< H T M L > <% @ t a g l i b u r i= h t t p : / / j a v a . sun . com/ j s p / j s t l / c o r e p r e f i x= c % > < B O D Y > <p> <c : i f t e s t= $ { empty param . nume } var= testNume > <c : out value=Numele l i p s e s t e ! /> </ c : i f > <c : i f t e s t= $ { not testNume } > Nume : <c : out value= $ { param . nume } /> </ c : i f > <p> <c : i f t e s t= $ { empty param . prenume } var= testPrenume > <c : out value= Prenumele l i p s e s t e ! /> </ c : i f > <c : i f t e s t= $ { not testPrenume } > Prenume : <c : out value= $ { param . prenume } /> </ c : i f > <p> <c : i f t e s t= $ { empty param . e m a i l } var= t e s t E m a i l >
242
20 21 22 23 24 25 26
<c : out value= Adresa EMail l i p s e s t e ! /> </ c : i f > <c : i f t e s t= $ { not t e s t E m a i l } > Em a i l : <c : out value= $ { param . e m a i l } /> </ c : i f > </B O D Y > </H T M L >
c:choose Marcajul de select ie poate cont ine oric ate marcaje c:when si cel mult un marcaj c:otherwise. Fiecare marcaj c:when cont ine obligatoriu atributul test. Dac a ntr-un marcaj c:when condit ia are valoarea true, atunci se prelucreaz a corpul acelui marcaj. In cazul n care toate marcajele c:when au fost evaluate cu false atunci se va prelucra marcajul c:otherwise (marcaj f ar a atribute). c:forEach Ciclu. Atribute ale marcajului: Atribut items var Fel Descriere opt ional Colect ia care se parcurge. opt ional Numele variabilei n care se stocheaz a valoarea elementului curent. begin opt ional Valoarea init ial a a variabilei var. end opt ional Valoarea nal a a variabilei var. step opt ional Valoarea pasului de iterare. Implicit este 1. varStatus opt ional Informat ii despre elementul curent. Variabila varStatus are c ampurile: index valoarea curent a a elementului dup a care se realizeaz a ciclarea; count num arul iterat iei curente; first are valoarea true dac a este primul element al ciclului; last are valoarea true dac a este ultimul element al ciclului; Exemplul 10.2.2 Lista parametrilor formularului de apelare a exemplului anterior se a seaz a 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}" />
243
<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 Evident ierea fontului cu care se scriu titlurile ntr-un document html:
<c:forEach begin="1" end="6" var="i" > <c:out value="<h${i}> Heading ${i} </h${i}>" escapeXml="false" /> </c:forEach>
c:forTokens Asigur a acea si funct ionalitate ca si clasei java.util.String Tokenizer. Atribute ale marcajului: Atribut value Fel Descriere obligatoriu Valoarea ce se evalueaz a si se a seaz a. expresiei. default opt ional Cea ce se a seaz a n cazul n care expresia nu poate evaluat a. escapeXml opt ional true / false. Valoarea implicit a este true. Pe false interpreteaz a caracterele din value ca si cod html. c:import Permite includerea altor pagini JSP n pagina curent a. Atribute ale marcajului:
244
Atribut Fel Descriere url obligatoriu Adresa documentului importat. context opt ional Context-ul paginii / documentului importat. Simbolul /, urmat de numele unei aplicat ii de pe acela si server. var opt ional Numele variabilei n care va stocat documentul importat. scope opt ional Domeniul de valabilitate al variabilei var. Unul din valorile: page, request, session, application. Cu marcajul c:param se pot xa parametri pentru pagina importat a. Acest marcaj are dou a atribute name si value. Acesti parametri se transmit cu metoda get. c:redirect Redirectarea activitatea c atre o alt a pagin a. Atribute ale marcajului: Atribut Fel Descriere url obligatoriu Adresa paginii c atre care se face redirectarea. context opt ional Context-ul paginii c atre care se face redirectarea. Simbolul /, urmat de numele unei aplicat ii de pe acela si server. Prin redirectare, parametrii nu sunt retransmi si automat mai departe. c:url Ret ine adrese URL. Atribute ale marcajului: Atribut Fel Descriere value obligatoriu Adresa documentului de ret inut. context opt ional Context-ul documentului. Simbolul /, urmat de numele unei aplicat ii de pe acela si server. var opt ional Numele variabilei n care va stocat a adresa documentului. scope opt ional Domeniul de valabilitate al variabilei var. Unul din valorile: page, request, session, application.
245
10.2.2
<%@taglib uri="http://java.sun.com/jsp/jstl/sql" prefix="sql" %> Marcaje din biblioteca de baz a: sql:setDataSource Fixeaz a referint a la baza de date. Atribute ale marcajului: Atribut dataSource driver url username password var scope Fel opt ional opt ional opt ional opt ional opt ional opt ional opt ional Descriere Referint a la baza de date Driver-ul bazei de date url-ul bazei de date nume utilizatorului bazei de date parola de acces la baza de date variabila cu referint a la baza de date Domeniul de valabilitate al variabilei var.
sql:query O interogare a bazei de date. Atribute ale marcajului: Atribut sql dataSource startRow maxRows var scope Fel obligatoriu opt ional opt ional opt ional obligatoriu opt ional Descriere Fraza sql Referint a la baza de date Linia de la care se ncepe interogarea Num arul maxim de rezultate acceptate Variabila cu rezultatele interog arii bazei de date Domeniul de valabilitate al variabilei var.
sql:update Actualizarea bazei de date. Atribute ale marcajului: Atribut Fel Descriere sql obligatoriu Fraza sql dataSource opt ional Referint a la baza de date Exemplul 10.2.5 S a se a seze lista din agenda de adrese e-mail creat a n exemplul din Cap. Servlet.
246
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
< H T M L > <% @ t a g l i b u r i= h t t p : / / j a v a . sun . com/ j s p / j s t l / c o r e p r e f i x= c % > <% @ t a g l i b u r i= h t t p : / / j a v a . sun . com/ j s p / j s t l / s q l p r e f i x= s q l % > < B O D Y > <p> <s q l : setDataSource d r i v e r= o r g . apache . derby . j d b c . C l i e n t D r i v e r u r l= j d b c : derby : / / l o c a l h o s t : 1 5 2 7 / AgendaEMail var=db /> < s q l : query d a t a S o u r c e= $ { db } var= r e z u l t s q l= s e l e c t from a d r e s e /> <c : i f t e s t= $ { r e z u l t . rowCount g t 0 } > <table> < tr> <c : f o r E a c h i t e m s= $ { r e z u l t . columnNames } var= c o l > <th> <c : out value= $ { c o l } /> </ th> </ c : f o r E a c h> </ tr> <c : f o r E a c h i t e m s= $ { r e z u l t . rowsByIndex } var= l i n e > < tr> <c : f o r E a c h i t e m s= $ { l i n e } var= elem > <td> <c : out value= $ { elem } /> </ td> </ c : f o r E a c h> </ tr> </ c : f o r E a c h> </ table> </ c : i f > </B O D Y > </H T M L >
10.3
Programatorul poate crea marcaje JSP proprii care se grupeaz a n colect ii numite biblioteci de marcaje. O bibliotec a de marcaje este reprezentat a de o identicator dat sub forma unui URI (Universal Resource Identier ).
10.3.1
Pentru a crea unui asemenea marcaj JSP propriu este necesar a denirea a patru componente: 1. O clas a de denit ie a comportamentului marcajului JSP (tag handler class).
247
2. Descriptorul de bibliotec a de marcaje JSP, care leag a clasa de denit ie a marcajului cu identicatorul bibliotecii de marcaje. 3. Marcajul taglib a sierului web.xml, care permite serverului Web s a g aseasc a descriptorul bibliotecii de marcaje. 4. Fi sierul JSP ce utilizeaz a marcajul JSP (clientul). Exemplic am acest a tehnologie prin Exemplul 10.3.1 S a se realizeze un marcaj dateTag, a c arui efect s a e a sarea datei calendaristice. 1. Clasa de denit ie a comportamentului marcajului. Programul const a din: (a) Importul pachetelor import javax.servlet.jsp.*; import javax.servlet.jsp.tagext.*; Aceste pachete se g asesc n sierul jsp-api.jar. (b) Un marcaj f ar a atribute si f ar a corp trebuie s a extind a clasa TagSupport si s a suprascrie metoda doStartTag, care dene ste activitatea intreprins a c and este nt alnit marcajul ntr-un document jsp. Metoda trebuie s a returneze constanta SKIP BODY. public class NumeClasa extends TagSupport{ public int doStartTag(){ . . . return SKIP_BODY; } } (c) Scrierea n uxul de ie sire se face cu un obiect JspWriter, care se obt ine cu pageContext.getOut(). Metoda print a clasei JspWriter poate genera o except ie IOException. Textul surs a al clasei de denit ie a comportamentului marcajului dateTag este:
248
1 2 3 4 5 7 8 9 10 11 12 13 14 15 16 17 18
package j s p ; import j a v a x . s e r v l e t . j s p . J s p W r i t e r ; import j a v a x . s e r v l e t . j s p . t a g e x t . TagSupport ; import j a v a . i o . IOException ; import j a v a . u t i l . Date ; public c l a s s DateTag extends TagSupport { public i n t doStartTag ( ) { try { J s p W r i t e r out=pageContext . getOut ( ) ; out . p r i n t l n ( new Date ( ) ) ; } catch ( IOException e ) { System . out . p r i n t l n ( DateTagException +e . g e t M e s s a g e ( ) ) ; } return SKIP BODY ; } }
2. Descriptorul de bibliotec a de marcaje JSP este dependent de versiunea tomcat folosit a. Acest sier trebuie s a aib a extensia tld (Taglib Language Denition). Localizarea acestui sier este denit a n elementul taglib din web.xml. In cazul unei distribut ii apache-tomcat-5.*, acest sier este (mylibtag.tld) :
<? xml version= 1 . 0 e n c o d i n g=ISO 8859 1 ?> < !D O C T Y P E taglib PUBLIC //Sun Microsystems , I n c . / /DTD JSP Tag L i b r a r y 1 . 2 / /EN h t t p : // j a v a . sun . com/ j 2 e e / dtd /web j s p t a g l i b r a r y 1 2 . dtd > < ! a t a g l i b r a r y d e s c r i p t o r > < t a g l i b> < t l i b version> 1 . 0 </ t l i b version> < j s p version> 1 . 2 </ j s p version> < s h o r t name> mytags </ s h o r t name> < u r i> h t t p : // c s . u n i t b v . r o / m y t a g l i b</ u r i> < d e s c r i p t i o n > L i b r a r i e de m a r c a j e </ d e s c r i p t i o n > < t a g> <name> dateTag </name> <tag c l a s s > j s p . DateTag </ tag c l a s s > <bodyc o n t e n t> EMPTY </bodyc o n t e n t> < d e s c r i p t i o n > f u r n i z e a z a data c u r e n t a </ d e s c r i p t i o n > </ t a g> </ t a g l i b >
1 2 3 4 6 7 8 9 10 11 12 14 15 16 17 18 19 20
Elementul uri cont ine identicatorul bibliotecii de marcaje, cs.unitbv.ro/mytaglib. Pentru ecare marcaj propriu se completeaz a un marcaj tag. Pentru un marcaj propriu f ar a atribute elementele acestui marcaj sunt (a) name Numele simbolic al marcajului.
249
(b) tag-class Referint a la sierul class al clasei de denit ie a comportamentului marcajului propriu. Referint a se face relativ la catalogul ...\WEB-INF\classes (c) description Descrierea marcajului propriu. (d) body-content In cazul nostru are valoarea EMPTY. In cazul unui marcaj cu corp se d a valoarea JSP. 3. Marcajul taglib din sierul 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 Identicatorul bibliotecii de marcaje. (b) taglib-location Locat ia sierului descriptor de bibliotec a de marcaje (numele calicat al sierului, adic a alc atuit din cale plus numele sierului). Astfel elementele constitutive se vor g asi n: webapps |--> mytag | |--> WEB-INF | | |--> classes | | | |--> jsp | | | | |--> DateTag.class | | | web.xml | | | mylibtag.tld | |--> jsp | | | dateTag.jsp 4. Marcajele proprii se utilizeaz a cu sintaxa <prex : NumeMarcaj />
250
Referint a la catalogul cu toate componentele necesare marcajului si prexul se xeaz a n directiva taglib. Un sier jsp care utilizeaz a marcajul realizat este (dateTag.jsp) :
1 2 3 4 5 6 7 8 9 10 11 12 13 14
<html> <head> < t i t l e> Tag p e n t r u data c a l e n d a r i s t i c a c u r e n t a </ t i t l e > </ head> <body> <% @ t a g l i b u r i= h t t p : / / c s . u n i t b v . r o / m y t a g l i b p r e f i x=mk % > <p> Data c u r e n t a e s t e : <mk : dateTag /> </ body> </ html>
apelat din
1 2 3 4 6 7 8 9 10
<html> <body> <form method= g e t action= j s p / dateTag . j s p > Data c a l e n d a r i s t i c ă: <p><input type= submit value= A f i s e a z a > </ form> </ body> </ html>
10.3.2
Realiz am un marcaj ziuaTag cu un atribut ziua care va a sat n momentul prelucr arii marcajului. 1. Pentru ecare atribut clasa ce dene ste act iunea marcajului trebuie s a cont in a o metod a public void setNumeAtribut (String value){...} care preia valoarea atributului dat a de parametrul value. Exemplul 10.3.2
251
1 2 3 4 6 7 9 10 11 13 14 15 16 17 18 19 20 21 22 23
package j s p ; import j a v a x . s e r v l e t . j s p . J s p W r i t e r ; import j a v a x . s e r v l e t . j s p . t a g e x t . TagSupport ; import j a v a . i o . IOException ; public c l a s s ZiuaTag extends TagSupport { String ziua ; public void s e t Z i u a ( S t r i n g v a l u e ) { z i u a=v a l u e ; } public i n t doStartTag ( ) { try { J s p W r i t e r out=pageContext . getOut ( ) ; out . p r i n t l n ( z i u a ) ; } catch ( IOException e ) { System . out . p r i n t l n ( ZiuaTagException +e . g e t M e s s a g e ( ) ) ; } return SKIP BODY ; } }
2. In descriptorul bibliotecii de marcaje pentru ecare atribut se dene ste un marcaj <attribute>...< /attribute> av and incluse marcajele Nume marcaj Semnicat ie name numele atributului required true | false dup a cum atributul e obligatoriu sau nu rtexprvalue true | false dup a cum atributul se poate utiliza ntr-o expresie < %= numeAtribut % > Fel obligatoriu obligatoriu opt ional
252
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
<html> <body> <form method= g e t action= j s p / ziuaTag . j s p > <p> A s t a z i , e s t e < s e l e c t name= z i u a > <option value= l u n i > Luni <option value= m a r t i > Marti <option value= m i e r c u r i > M i e r c u r i <option value= j o i > J o i <option value= v i n e r i > V i n e r i <option value= s i mb a ta > Simbata <option value= duminica > Duminica </ s e l e c t> <p><input type= submit value= A f i s e a z a > </ form> </ body> </ html>
<html> <head> < t i t l e > Tag cu marcaj </ t i t l e > </ head> <body> <% @ t a g l i b u r i= h t t p : / / c s . u n i t b v . r o / m y t a g l i b p r e f i x=mk % > <p> <% String z i=r e q u e s t . g e t P a r a m e t e r ( z i u a ) ; % > Ziua e s t e : <mk : ziuaTag z i u a=<%= z i % > /> </ body> </ html>
10.3.3
Marcaje cu corp.
In metoda doStartTag valoarea returnat a trebuie s a e EVAL BODY INCLUDE, n loc de SKIP BODY. In descriptorul bibliotecii de marcaje apare <body-content> JSP </body-content> n loc de EMPTY. Dac a se dore ste ca marcajul s a execute act iuni dup a interpretarea corpului, atunci acele activit a ti sunt denite n metoda doEndTag. Aceast a metod a
253
returneaz a valoarea EVAL PAGE sau SKIP PAGE dup a cum se dore ste sau nu continuarea proces arii paginii jsp. Exemplul 10.3.3 Fie marcajul modTag care modic a un text n caractere mari sau mici dup a valoarea atributului trans. Acest marcaj poate include ale elemente. Codul clasei ce prelucreaz a marcajul este
1 2 3 4 6 7 8 10 11 12 14 15 16 18 19 20 21 22 23 24 25 26 27 28 29 30 31
package j s p ; import j a v a x . s e r v l e t . j s p . J s p W r i t e r ; import j a v a x . s e r v l e t . j s p . t a g e x t . TagSupport ; import j a v a . i o . IOException ; public c l a s s ModTag extends TagSupport { String text ; boolean toUpperCase ; public void s e t T e x t ( S t r i n g v a l u e ) { t e x t=v a l u e ; } public void s e t T r a n s ( S t r i n g v a l u e ) { toUpperCase=(new Boolean ( v a l u e ) ) . b o o l e a n V a l u e ( ) ; } public i n t doStartTag ( ) { try { J s p W r i t e r out=pageContext . getOut ( ) ; i f ( toUpperCase ) out . p r i n t l n ( t e x t . toUpperCase ( ) ) ; else out . p r i n t l n ( t e x t . toLowerCase ( ) ) ; } catch ( IOException e ) { System . out . p r i n t l n ( ModTagException +e . g e t M e s s a g e ( ) ) ; } return EVAL BODY INCLUDE ; } }
254
<name> trans </name> <required> true </required> <rtexprvalue> true </rtexprvalue> </attribute> </tag>
<html> <body> <form method= g e t action= j s p / modtextTag . j s p > I n t r o d u c e o f r a z ă <input type= t e x t name= t e x t s i z e= 40 > <p> Se t r a n s f o r m ă în l i t e r e < s e l e c t name= t r a n s > <option value= upperCase > mari <option value= l o w e r C a s e > m i c i </ s e l e c t> <p><input type= submit value= A f i s e a z a > </ form> </ body> </ html>
mpreun a cu modtextTag.jsp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
<html> <body> <% @ t a g l i b u r i= h t t p : / / c s . u n i t b v . r o / m y t a g l i b p r e f i x=mk % > <% String text=r e q u e s t . g e t P a r a m e t e r ( t e x t ) ; String t r a n s=r e q u e s t . g e t P a r a m e t e r ( t r a n s ) ; String t ; i f ( t r a n s . e q u a l s ( upperCase ) ) t= t r u e ; else t= f a l s e ; % > <p> <mk : modTag text=<%= t e x t % > t r a n s=<%=t% >> <mk : dateTag /> </mk : modTag> </ body> </ html>
10.4
Prezent am desf a surarea unui servlet ntr-un produs sau platform a de cloud computing. Dintre produsele de cloud computing disponibile n prezent amintim: Amazons Elastic Compute Cloud -(EC2) produs de referint a, dar comercial;
255
Google App Engine (GAE); Microsoft Azure; In cele urmeaz a se va utiliza Google App Engine.1 GAE permite: nc arcarea unei aplicat ii Web pe un simulator local al platformei de Cloud Computing; nc arcarea unei aplicat ii Web pe platforma Google de Cloud Computing. In prezent, pe platforma GAE se pot nc arca aplicat ii realizate n Java, Python si Go, al aturi de care care pot ap area siere http, css, js. Exist a c ate o distribut ie distinct a pentru ecare din aceste limbaje de programare. Prezent am numai nc arcarea pe simulatorul local al platformei GAE, n versiunea Java construit peste serverul Web jetty. Instalarea produsului const a din dezarhivarea sierului appengine-javasdk-*. Utilizarea. In vederea nc arc arii unui servlet pe simulatorul local se creaz a structura de cataloage si siere
www |--> | | | | | | | WEB-INF |--> classes | | *.class |--> lib | | *.jar | web.xml | appengine-web.xml index.html
Singurul sier specic GAE este appengine-web.xml. Codul acestui ser este
1 2 3 4 6 8
< appengine webapp xmlns= h t t p : // a p p e n g i n e . g o o g l e . com/ ns / 1 . 0 > < ! R e p l a c e t h i s w i t h your a p p l i c a t i o n i d from h t t p : // a p p e n g i n e . g o o g l e . com > < a p p l i c a t i o n ></ a p p l i c a t i o n > <version>1</ version> </ appengine webapp>
Datele sierului web.xml corespund servlet-ului, iar prin sierul index.html se apeleaz a aplicat ia Web. Parametrul action al elementului form are forma simplicat a action=/numeApel, unde numeApel coincide cu valoarea atributului urlPattern.
1
256
Dac a aplicat ia se ncarc a pe platforma Google de Cloud Computing atunci trebuie completat elementul <application>. Lansarea simulatorului si nc arcarea se poate face prin comenzile
set GAE\_HOME=. . .\appengine-java-sdk-* %GAE\_HOME%\bin\dev_appserver www
lansate ntr-o fereast a DOS, n catalogul care-l cont ine pe www. Aplicat ia se apeleaz a prin http://localhost:8080. Dac a n loc de index.html se utilizeaz a alt nume, atunci apelarea aplicat iei este http://localhost:8080/fi sier.html. O aplicat ie JSP se trateaz a asem an ator. Distribut ia GAE pentru Java cont ine sablonul unei aplicat ii mpreun a cu un sier build.xml (appengine-java-sdk-*\demos\new project template) prin intermediul c aruia, cu ajutorul lui ant, se construie ste catalogul www descris anterior. Exemplul 10.4.1 Servlet-ul CmmdcServlet instalat n platforma Google App Engine de Cloud Computing. S ablonul se copiaz a n zona de lucru sub numele appcmmdc si se completeaz a cu sierele servlet-ului (CmmdcServlet.java, cmmdc.html ) rezult and:
appcmmdc |--> html | | cmmdc.html |--> src | |--> WEB-INF | | | appengine-web.xml | | | web.xml | | CmmdcServlet.java | build.xml
Se execut a cu ant obiectivul implicit din build.xml, urmat de lansarea simulatorului din interiorul catalogului appcmmdc. Deoarece numele sierului html difer a de index, aplicat ia se apeleaz a prin http://localhost:8080/cmmdc.html. Alternativ, aplicat ia se poate construi cu Eclipse folosind o component a (plug-in ) specic a. GAE cont ine n plus un serviciu de autenticare si autorizare UserService, un sistem de persistent a a datelor Datastore, Task-Queue.
257
2. Precizat i diferent a dintre o pagin a JSP si un document JSP. 3. Unde se instaleaz a o pagina JSP? 4. Care este rolul unei declarat ii JSP ? 5. Care este rolul unei directive JSP ? 6. Cum apeleaz a o pagin a JSP ? 7. Cum prelucreaz a un server Web o pagina / document JSP ? 8. Care sunt tr as aturile unei componente Java (bean) ? 9. Care este rolul unui element <jsp:useBean> ?
258
260
geronimo - apache, sprijinit de I.B.M. JOnAS. Glasssh, geronimo sunt implement ari ale extensiei Java Enterprise Edition - JEE. In acela si timp, aceste servere Web sunt containere EJB, de servlet si JSP. In cele ce urmeaz a vom utiliza glasssh. 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 dat a de valorile c ampurilor sale. Din punctul de vedere al ret inerii st arii, exist a urm atoarele tipuri de componente sesiune EJB: stateless - f ar a ret inerea st arii; stateful - cu ret inerea st arii pe parcursul sesiunii serverului; singleton - exist a o singur a instant a a componentei EJB. Durata de viat a a componentei coincide cu intervalul de timp n care componenta EJB este activ a n serverul de aplicat ii. Aplicat iile cu component a EJB constau din: componenta EJB - desf a surat a n serverul de aplicat ii. Aceast a component a poate totodat a si un serviciu Web de tip JAX-WS; aplicat ie client care poate client Web - servlet sau client al serviciului Web de tip JAX-WS; client RMI-IIOP (Internet Inter ORB Protocol).
261
In terminologia JEE componenta EJB, clientul Web si clientul RMI-IIOP formeaz a c ate un modul. Componenta EJB si clientul Web formeaz a o aplicat ie JEE care se instaleaz a n serverul de aplicat ii JEE. Modulele EJB si RMI-IIOP se arhiveaz a cu extensia jar iar modulul Web se arhiveaz a cu extensia war. Aplicat ia JEE se arhiveaz a cu extensia ear -Enterprise ARchive - sau war. Un client RMI-IIOP apeleaz a modulul EJB prin intermediul programului glassfish\bin\appclient.exe
appclient -client modul-iiop.jar [-targetserver host:port] arg1 . . .
11.1.1
S ablonul 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 dou a numere naturale. Componentei EJB are codul
1 2 4 5 6 7
package cmmdc . e j b ; import j a v a x . e j b . S t a t e l e s s ; @Stateless public c l a s s CmmdcBean { public long cmmdc( long m, long n ) { . . . } }
Aplicat ia client va un servlet g azduit de acela si server de aplicat ie. Accesul la componenta EJB se poate programa: prin injectare, utiliz and adnot ari; prin JNDI. In ambele cazuri serverul Web este responsabil de instant ierea componentei EJB.
Serverul de aplicat ie injecteaz a n servlet o instant a a componentei EJB sau altfel explicat
@EJB Type var; @EJB(name="xyz") Type var;
injecteaz a (realizeaz a o referint a ) pentru var c atre un obiect de tipul Type specicat. Actiunea este declan sat a de adnotarea EJB. Codul servlet-ului este
1 2 3 4 5 6 7 9 10 11 12 14 15 16 17 18 19 21 22 23 24 25 26 27 28 30 31 33 34 35 36 37
package cmmdc . web ; import j a v a . i o . ; import j a v a x . s e r v l e t . ; import j a v a x . s e r v l e t . h t t p . ; import cmmdc . e j b . CmmdcBean ; import j a v a x . e j b . EJB ; import j a v a x . s e r v l e t . a n n o t a t i o n . WebServlet ; @WebServlet ( u r l P a t t e r n s = /cmmdc ) public c l a s s CmmdcServlet extends H t t p S e r v l e t { @EJB CmmdcBean cb ; public void doGet ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { S t r i n g sm=r e q . g e t P a r a m e t e r ( m ) , sn=r e q . g e t P a r a m e t e r ( n ) ; long m =Long . par se Lo ng ( sm ) , n=Long . par se Lo ng ( sn ) ; long x=cb . cmmdc(m, n ) ; P r i n t W r i t e r out=r e s . g e t W r i t e r ( ) ; S t r i n g t i t l e =Cmmdc S e r v l e t ; r e s . setContentType ( t e x t / html ) ; out . p r i n t l n ( <HTML ><HEAD ><TITLE> ) ; out . p r i n t l n ( t i t l e ) ; out . p r i n t l n ( </TITLE></HEAD >< BODY > ) ; out . p r i n t l n ( <H1>+ t i t l e +</H1> ) ; out . p r i n t l n ( <P>Cmmdc : +x ) ; out . p r i n t l n ( </BODY ></HTML > ) ; out . c l o s e ( ) ; } public void doPost ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { doGet ( req , r e s ) ; } }
263
| |
| | | index.html
CmmdcServlet.class
Aceast a structur a se arhiveaz a cu jar, dar cu extensia war. Acces la componenta EJB prin JNDI Referint a JNDI are structura prex /[nume app ][/nume modul ]/nume EJB unde prex poate Prex Vizibilitatea rezultatului java:global Componenta se poate utiliza de oriunde. Coincide cu numele arhivei ear. java:app Componenta se poate utiliza n aplicat ie Coincide cu numele arhivei jar sau war. java:module Componental se poate utiliza n modul In cazul exemplului codul servlet-ului va
1 2 3 4 5 6 7 8 10 11 12 14 15 16 17 18 19 20 21 22 23 24 26 27 29 30 31 32
package cmmdc . web ; import j a v a . i o . ; import j a v a x . s e r v l e t . ; import j a v a x . s e r v l e t . h t t p . ; import cmmdc . e j b . CmmdcBean ; import j a v a x . naming . Context ; import j a v a x . naming . I n i t i a l C o n t e x t ; import j a v a x . s e r v l e t . a n n o t a t i o n . WebServlet ; @WebServlet ( u r l P a t t e r n s = /cmmdc ) public c l a s s CmmdcServlet extends H t t p S e r v l e t { CmmdcBean cb ; public void i n i t ( S e r v l e t C o n f i g c o n f i g ) throws S e r v l e t E x c e p t i o n { super . i n i t ( c o n f i g ) ; Context c t x=n u l l ; try { c t x=new I n i t i a l C o n t e x t ( ) ; cb=(CmmdcBean) c t x . l o o k u p ( j a v a : module /CmmdcBean ) ; } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( E r o a r e : +e . g e t M e s s a g e ( ) ) ; } } public void doGet ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { . . . } public void doPost ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { . . . } } }
264
11.1.2
Modic am arhitectura aplicat iei anterioare denind un modul EJB pentru componta EJB.
modul-ejb |--> numePachet | | *.class
Instalarea aplicat ie, adic a a ansamblului alc atuit din cele 2 module se face prin intermediul administratorului. Fi sierul application.xml precizeaz a structura aplicat iei
<?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>
Aceast a organizare necesit a modicarea componentei EJB din sect iunea 11.1.1 n sensul denirii unei interfet e cu adnotarea Remote. Componenta EJB implementeaz a interfat a si n plus, dac a interfat a are numele Xyz atunci componenta EJB va avea numele XyzBean. Pentru exemplul discutat codurile sunt:
265
1 2 4 5 6 7
package cmmdc . e j b ; import j a v a x . e j b . Remote ; @Remote public i n t e r f a c e Cmmdc{ public long cmmdc( long m, long n ) ; }
si
1 2 4 5 6 7
package cmmdc . e j b ; import j a v a x . e j b . S t a t e l e s s ; @Stateless public c l a s s CmmdcBean implements Cmmdc{ public long cmmdc( long m, long n ) { . . . } }
Modulul / clientul Web este cel prezentat anterior n sect iunea 11.1.1, cu diferent a c a referint a la componenta EJB se face prin interfat a . In cazul exemplului tratat, desf a surarea clientului RMI-IIOP va
cmmdc-iiop |--> cmmdc | |--> client | | | | |--> ejb | | |
CmmdcClient.class Cmmdc.class
package cmmdc . c l i e n t ; import j a v a x . e j b . EJB ; import cmmdc . e j b . Cmmdc ; import j a v a . u t i l . S c a n n e r ; public c l a s s CmmdcClient { @EJB private s t a t i c Cmmdc cb ; public s t a t i c void main ( S t r i n g [ ] a r g s ) throws E x c e p t i o n { S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ; System . out . p r i n t l n ( m = ) ; long m =s c a n n e r . nextLong ( ) ; System . out . p r i n t l n ( n= ) ; long n=s c a n n e r . nextLong ( ) ; long x=cb . cmmdc(m, n ) ; System . out . p r i n t l n ( Cmmdc : +x ) ; } }
Dac a se utilizeaz a referint a prin JNDI atunci adresarea componentei EJB va : java:global/cmmdc-ear/cmmdc-ejb/CmmdcBean Dac a dist este catalogul cu arhiva clientului atunci apelarea acestuia este
266
Apelarea modulului Web se face n mod obi snuit, prin: http://host:8080/context unde context a fost denit n sierul application.xml.
11.1.3
Serverul de aplicat ie creaz a o singur a instant iaz a a componentei EJB care este utilizat a de tot i client ii. Diferent a const a n utilizarea adnot arii @Singleton n loc de @Stateless. Utiliz am modelul din sect iunea 11.1.2. Consider am doar varianta bazat a pe adnot ari. Exemplul 11.1.2 Num ararea solicit arilor de utilizare a componentei EJB. Codul componentei EJB singleton
1 2 4 5 6 7
package s i n g l e . e j b ; import j a v a x . e j b . Remote ; @Remote public i n t e r f a c e S i n g l e { public i n t g e t I n d e x ( ) ; } package s i n g l e . e j b ; import j a v a x . e j b . S i n g l e t o n ; @Singleton public c l a s s S i n g l e B e a n implements S i n g l e { private i n t i n d e x =0; public i n t g e t I n d e x ( ) { return ++i n d e x ; } }
1 2 4 5 6 7 8 9 10
package s i n g l e . web ; import j a v a . i o . ; import j a v a x . s e r v l e t . ; import j a v a x . s e r v l e t . h t t p . ; import s i n g l e . e j b . S i n g l e ; import j a v a x . e j b . EJB ; import j a v a x . s e r v l e t . a n n o t a t i o n . WebServlet ; @WebServlet ( u r l P a t t e r n s = / s i n g l e ) public c l a s s S i n g l e S e r v l e t extends H t t p S e r v l e t { @EJB
267
12 14 15 16 17 18 19 20 21 22 23 24 25 26 27 29 30 31 32 33
S i n g l e sb ; public void doGet ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { i n t x=sb . g e t I n d e x ( ) ; P r i n t W r i t e r out=r e s . g e t W r i t e r ( ) ; r e s . setContentType ( t e x t / html ) ; S t r i n g t i t l e = S i n g l e S e r v l e t ; out . p r i n t l n ( <HTML ><HEAD ><TITLE> ) ; out . p r i n t l n ( t i t l e ) ; out . p r i n t l n ( </TITLE></HEAD >< BODY > ) ; out . p r i n t l n ( <H1>+ t i t l e +</H1> ) ; out . p r i n t l n ( <p>V a l o a r e a i n d e x : +x ) ; out . p r i n t l n ( </BODY ></HTML > ) ; out . c l o s e ( ) ; } public void doPost ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { doGet ( req , r e s ) ; } }
<html> <body bgcolor=#c c b b c c > <center> <h1> EJB S i n g l e S e r v l e t </ h1> <form method= g e t action= h t t p : / / l o c a l h o s t : 8 0 8 0 / e j b s i n g l e / s i n g l e > <p><input type= submit value= A p e l e a z a > </ form> </ center> </ body> </ html
package s i n g l e . c l i e n t ; import j a v a x . e j b . EJB ; import s i n g l e . e j b . S i n g l e ; import j a v a . u t i l . S c a n n e r ; public c l a s s S i n g l e C l i e n t { @EJB private s t a t i c S i n g l e nb ; public s t a t i c void main ( S t r i n g [ ] a r g s ) throws E x c e p t i o n { S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ; S t r i n g ch=Y ; i n t i n d e x =0; while ( ch . e q u a l s ( Y ) ) { i n d e x=nb . g e t I n d e x ( ) ; System . out . p r i n t l n ( Numarul de a p e l a r i : +i n d e x ) ; System . out . p r i n t l n ( C o n t i n u a t i ? (Y/N) ) ; do { ch=s c a n n e r . n e x t ( ) . t r i m ( ) . toUpperCase ( ) ;
268
21 22 23 24 25
} while ( ( ! ch . s t a r t s W i t h ( Y ))&&(! ch . s t a r t s W i t h ( N ) ) ) ; } } }
11.1.4
Diferent a formal a fat a de modelele Stateless si Singleton const a n utilizarea adnot arii @Stateful. Consider am un exemplu ce deriv a din cel precedent. Exemplul 11.1.3 Num ararea solicit arilor de utilizare a componentei EJB. Componenta EJB are interfat a
1 2 4 5 6 7 8
package numara . e j b ; import j a v a x . e j b . Remote ; @Remote public i n t e r f a c e Numara { public i n t g e t I n d e x ( ) ; public void remove ( ) ; }
si implementarea
1 2 3 5 6 7 8 9 10 12 13 14
package numara . e j b ; import j a v a x . e j b . S t a t e f u l ; import j a v a x . e j b . Remove ; @Stateful public c l a s s NumaraBean implements Numara { private i n t i n d e x =0; public i n t g e t I n d e x ( ) { return ++i n d e x ; } @Remove public void remove ( ) {} }
Metoda cu adnotarea Remove are ca efect stergerea instant ei componentei EJB din serverul de aplicat ii. Din acest motiv, apelarea acestei metode ntr-un modul Web, are ca efect compromiterea servlet-ului. Injectarea componentei EJB are loc n momentul activ arii servlet-ului. Astfel ecare client Web va utiliza acea si component a EJB. Modulul IIOP este mult mai util. La ecare apelare a modulului IIOP are loc injectarea unei componente EJB. Serverul de aplicat ii p astreaz a starea componentei pe durata de utilizare a modulului IIOP. Codul modulului Web
269
1 2 3 4 5 6 8 9 10 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 36 37 38 39 40
package numara . web ; import j a v a . i o . ; import j a v a x . s e r v l e t . ; import j a v a x . s e r v l e t . h t t p . ; import numara . e j b . Numara ; import j a v a x . e j b . EJB ; public c l a s s NumaraServlet extends H t t p S e r v l e t { @EJB Numara nb ; public void doGet ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { S t r i n g o p e r=r e q . g e t P a r a m e t e r ( o p e r ) ; P r i n t W r i t e r out=r e s . g e t W r i t e r ( ) ; r e s . setContentType ( t e x t / html ) ; S t r i n g t i t l e =Numara S e r v l e t ; out . p r i n t l n ( <HTML ><HEAD ><TITLE> ) ; out . p r i n t l n ( t i t l e ) ; out . p r i n t l n ( </TITLE></HEAD >< BODY > ) ; out . p r i n t l n ( <H1>+ t i t l e +</H1> ) ; switch ( o p e r ) { case i n d e x : i n t x=nb . g e t I n d e x ( ) ; out . p r i n t l n ( <p>V a l o a r e a i n d e x : +x ) ; break ; case e x i t : out . p r i n t l n ( <p> OK: Pe r a s p u n d e r e a d v o a s t r a ) ; nb . remove ( ) ; break ; } out . p r i n t l n ( </BODY ></HTML > ) ; out . c l o s e ( ) ; } public void doPost ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { doGet ( req , r e s ) ; } }
apelat din
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
<html> <body bgcolor=#c c b b c c > <center> <h1> EJB Numară S e r v l e t </ h1> <form method= g e t action= h t t p : / / l o c a l h o s t : 8 0 8 0 / ejbnumara /numara> <table> < tr> <td> S e l e c t a ţ i o p e r a ţ i a</ td> <td> < s e l e c t name= o p e r > <option value= i n d e x > Numă r de a p e l ă r i <option value= e x i t > S t e r g e componenta EJB </ s e l e c t> </ td> </ tr>
270
17 18 19 20 21 22 23 24 25
< tr> <td> <input type= submit value= A p e l e a z a ></ td> <td /> </ tr> </ table> </ form> </ center> </ body> </ html>
package numara . c l i e n t ; import j a v a x . e j b . EJB ; import numara . e j b . Numara ; import j a v a . u t i l . S c a n n e r ; public c l a s s NumaraClient { @EJB private s t a t i c Numara nb ; public s t a t i c void main ( S t r i n g [ ] a r g s ) throws E x c e p t i o n { S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ; S t r i n g ch=Y , msg= ; i n t op , i n d e x =0; while ( ch . e q u a l s ( Y ) ) { System . out . p r i n t l n ( O p e r a t i i : 1 . Numara 2 . S t e r g e componenta EJB ) ; System . out . p r i n t l n ( O p e r a t i a : ) ; op=s c a n n e r . n e x t I n t ( ) ; switch ( op ) { case 1 : i n d e x=nb . g e t I n d e x ( ) ; msg=Numarul de a p e l a r i : +(new I n t e g e r ( i n d e x ) ) . t o S t r i n g ( ) ; break ; case 2 : nb . remove ( ) ; msg=Sa s t e r s componenta EJB ; break ; default : msg=Cod o p e r a t i e e r o n a t ; break ; } System . out . p r i n t l n ( msg ) ; System . out . p r i n t l n ( C o n t i n u a t i ? (Y/N) ) ; do { ch=s c a n n e r . n e x t ( ) . t r i m ( ) . toUpperCase ( ) ; } while ( ( ! ch . s t a r t s W i t h ( Y ))&&(! ch . s t a r t s W i t h ( N ) ) ) ; } } }
Rul and modulele IIOP ale aplicat iilor corespunz atoare adnot arilor Stateful si Singleton observat i diferent a rezultatelor furnizate.
271
11.1.5
O component a EJB MessageDriven (MDB) preia mesaje care sunt trimise c atre un obiect destinat ie predenit de tip Queue sau Topic. Componenta EJB este adnotat a cu @MessageDriven(mappedName=nume Destinat ie ) Prelucrarea mesajelor primite se programeaz a n metoda onMessage a interfet ei MessageListener. A sarea unor mesaje se obt ine prin intermediul unei jurnaliz ari java.util. logging.Logger. Textele apar n sierul server.log aat n catalogul log al domeniului. Obiectele administrator - fabrica de conexiuni, obiectul destinat ie - se creaz a naintea desf a sur arii componentei EJB.
Exemplul 11.1.4 O aplicat ie client trimite un num ar de mesaje c atre o component a MDB. Codul componentei EJB
272
1 2 3 4 5 6 8 9 10 11 13 14 15 16 17 18 19 20 21 22 23 24 25 26
package mdb ; import j a v a x . e j b . MessageDriven ; import j a v a x . jms . Message ; import j a v a x . jms . TextMessage ; import j a v a x . jms . M e s s a g e L i s t e n e r ; import j a v a . u t i l . l o g g i n g . Logger ; @MessageDriven ( mappedName=myQueue ) public c l a s s MessageBean implements M e s s a g e L i s t e n e r { private s t a t i c f i n a l Logger l o g g e r = Logger . g e t L o g g e r ( MessageBean . c l a s s . getName ( ) ) ; public void onMessage ( Message msg ) { TextMessage txtMsg = n u l l ; try { i f ( msg instanceof TextMessage ) { txtMsg = ( TextMessage ) msg ; l o g g e r . i n f o ( MESSAGE BEAN: + txtMsg . g e t T e x t ( ) ) ; System . out . p r i n t l n ( txtMsg . g e t T e x t ( ) ) ; } } catch ( Throwable th ) { th . p r i n t S t a c k T r a c e ( ) ; } } }
Fi sierul simple-mdb.jar nu cont ine dec at clasa mdb.MessageBean, reprodus a mai sus. Codul clientului cu reg asirea obiectilor prin adnotare
1 2 3 4 5 6 7 8 9 11 12 13 14 15 17 18 19 20
package mdb ; import j a v a x . jms . QueueConnection ; import j a v a x . jms . QueueConnectionFactory ; import j a v a x . jms . D e s t i n a t i o n ; import j a v a x . jms . Q u e u e S e s s i o n ; import j a v a x . jms . MessageProducer ; import j a v a x . jms . Message ; import j a v a x . jms . TextMessage ; import j a v a x . a n n o t a t i o n . R e s o u r c e ; public c l a s s MessageClient { @Resource ( l o o k u p= myQueueConnectionFactory ) private s t a t i c QueueConnectionFactory c f ; @Resource ( l o o k u p=myQueue ) private s t a t i c D e s t i n a t i o n q ; public s t a t i c void main ( S t r i n g [ ] a r g s ) { try { QueueConnection conn = c f . c r e a t e Q u e u e C o n n e c t i o n ( ) ; QueueSession s e s s i o n =
273
21 22 23 24 25 26 27 29 30 31 32 33 34 35 36 37
conn . c r e a t e Q u e u e S e s s i o n ( f a l s e , Q u e u e S e s s i o n .AUTO ACKNOWLEDGE) ; MessageProducer s e n d e r = s e s s i o n . c r e a t e P r o d u c e r ( q ) ; TextMessage msg = s e s s i o n . c r e a t e T e x t M e s s a g e ( ) ; f o r ( i n t i = 0 ; i < 5 ; i ++) { msg . s e t T e x t ( Mesaj t r i m i s + ( i + 1 ) ) ; s e n d e r . send ( msg ) ; } System . out . p r i n t l n ( Sen de r has f i n i s h e d ) ; session . close (); System . e x i t ( 0 ) ; } catch ( E x c e p t i o n e ) { e . printStackTrace ( ) ; } } }
si prin JNDI
1 2 3 4 5 6 7 8 9 10 12 13 14 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 38 39 40
package mdb ; import j a v a x . jms . QueueConnection ; import j a v a x . jms . QueueConnectionFactory ; import j a v a x . jms . D e s t i n a t i o n ; import j a v a x . jms . Q u e u e S e s s i o n ; import j a v a x . jms . MessageProducer ; import j a v a x . jms . Message ; import j a v a x . jms . TextMessage ; import j a v a x . naming . Context ; import j a v a x . naming . I n i t i a l C o n t e x t ; public c l a s s MessageClient { private s t a t i c QueueConnectionFactory c f ; private s t a t i c D e s t i n a t i o n q ; public s t a t i c void main ( S t r i n g [ ] a r g s ) { Context c t x=n u l l ; try { c t x=new I n i t i a l C o n t e x t ( ) ; c f =( QueueConnectionFactory ) c t x . l o o k u p ( myQueueConnectionFactory ) ; q=( D e s t i n a t i o n ) c t x . l o o k u p ( myQueue ) ; } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( E r o a r e : +e . g e t M e s s a g e ( ) ) ; System . e x i t ( 1 ) ; } try { QueueConnection conn = c f . c r e a t e Q u e u e C o n n e c t i o n ( ) ; Q u e u e S e s s i o n s e s s i o n = conn . c r e a t e Q u e u e S e s s i o n ( f a l s e , Q u e u e S e s s i o n .AUTO ACKNOWLEDGE) ; MessageProducer s e n d e r = s e s s i o n . c r e a t e P r o d u c e r ( q ) ; TextMessage msg = s e s s i o n . c r e a t e T e x t M e s s a g e ( ) ; f o r ( i n t i = 0 ; i < 5 ; i ++) { msg . s e t T e x t ( Mesaj t r i m i s + ( i + 1 ) ) ; s e n d e r . send ( msg ) ; } System . out . p r i n t l n ( Sen de r has f i n i s h e d ) ; session . close (); System . e x i t ( 0 ) ;
274
} catch ( E x c e p t i o n e ) { e . printStackTrace ( ) ; } } }
41 42 43 44 45 46
11.1.6
O componenta de tip entity simplic a accesul la o baz a de date ntr-o aplicat ie JEE. Crearea bazei de date
Glasssh cont ine SGBD JavaDB (derby ). Vom lansa serverul glasssh si prin intermediul utilitarului ij vom crea baza de date AgendaEMail. Crearea se face n modul descris n anexa dedicat a utiliz arii unei SGBD ntr-un program Java.
275
Aplicat ie cu component a Entity O componenta Entity va adnotat a @Entity si corespunde unui tabel al bazei de date relat ionale. Exemplul 11.1.5 Aplicat ie de consultarea a bazei de date AgendaEMail. Desf a surarea aplicat iei este
agendae-ear |--> META-INF | | persistence.xml | agenda-ejb.jar
package e n t i t y ; import j a v a . i o . S e r i a l i z a b l e ; import j a v a x . p e r s i s t e n c e . E n t i t y ; import j a v a x . p e r s i s t e n c e . I d ; import j a v a x . p e r s i s t e n c e . GeneratedValue ; import j a v a x . p e r s i s t e n c e . GenerationType ; import j a v a . i o . S e r i a l i z a b l e ; @Entity public c l a s s Adrese implements S e r i a l i z a b l e { @Id @GeneratedValue ( s t r a t e g y=GenerationType . IDENTITY) private i n t i d ; private S t r i n g nume ; private S t r i n g e m a i l ; public S t r i n g getNume ( ) { return nume ; } public void setNume ( S t r i n g nume ) { t h i s . nume = nume ; } public S t r i n g g e t E m a i l ( ) { return e m a i l ; } public void s e t E m a i l ( S t r i n g e m a i l ) { this . email = email ; } public i n t g e t I d ( ) { return i d ; }
276
public void s e t I d ( i n t i d ) { this . id = id ; } }
32 33 34 35
Accesul la baza de date se realizeaz a printr-o component a EJB Session stateless Codul interfet ei AgendaEMail.java este
1 2 3 4 6 7 8 9 10
package e j b ; import j a v a x . e j b . Remote ; import e n t i t y . Adrese ; import j a v a . u t i l . L i s t ; @Remote public i n t e r f a c e AgendaEMail { public L i s t <Adrese > g e t E m a i l ( S t r i n g nume ) ; public L i s t <Adrese > getNume ( S t r i n g e m a i l ) ; }
package e j b ; import j a v a x . e j b . S t a t e l e s s ; import j a v a x . p e r s i s t e n c e . P e r s i s t e n c e C o n t e x t ; import j a v a x . p e r s i s t e n c e . EntityManager ; import j a v a x . p e r s i s t e n c e . Query ; import e n t i t y . Adrese ; import j a v a . u t i l . L i s t ; @Stateless public c l a s s AgendaEMailBean implements AgendaEMail { @ P e r s i s t e n c e C o n t e x t ( unitName= a g e n d a e p e r s i s t e n c e c t x ) EntityManager em ; public L i s t <Adrese > g e t E m a i l ( S t r i n g nume ) { S t r i n g nm= \ +nume+ \ ; S t r i n g s q l=SELECT e n t i t y FROM Adrese e n t i t y WHERE e n t i t y . nume=+nm ; System . out . p r i n t l n ( s q l ) ; Query query=em . c r e a t e Q u e r y ( s q l ) ; L i s t <Adrese > l i s t =( L i s t <Adrese >) query . g e t R e s u l t L i s t ( ) ; return l i s t ; } public L i s t <Adrese > getNume ( S t r i n g e m a i l ) { S t r i n g eml= \ +e m a i l+ \ ; S t r i n g s q l=SELECT e n t i t y FROM Adrese e n t i t y WHERE e n t i t y . e m a i l=+eml ; System . out . p r i n t l n ( s q l ) ; Query query=em . c r e a t e Q u e r y ( s q l ) ; L i s t <Adrese > l i s t =( L i s t <Adrese >) query . g e t R e s u l t L i s t ( ) ; return l i s t ; } }
< p e r s i s t e n c e xmlns= h t t p : // j a v a . sun . com/xml/ ns / p e r s i s t e n c e version= 1 . 0 > < p e r s i s t e n c e u n i t name= a g e n d a e p e r s i s t e n c e c t x > < j t a data s o u r c e> j d b c / Adrese</ j t a data s o u r c e> < p r o p e r t i e s>
277
5 6 7 8 9 10 11 12
< !Use t h e j a v a 2 d b f e a t u r e > < p r o p e r t y name= t o p l i n k . ddl g e n e r a t i o n v a l u e= none /> < ! Generate t h e s q l s p e c i f i c t o Derby d a t a b a s e > < p r o p e r t y name= t o p l i n k . j d b c . d r i v e r v a l u e= o r g . apache . derby . j d b c . C l i e n t D r i v e r /> </ p r o p e r t i e s > </ p e r s i s t e n c e u n i t> </ p e r s i s t e n c e >
Se observ a urm atoarele corelat ii Valoarea agendae persistence ctx atributului name a elementului persis tence-unit este utilizat n clasa AgendaEMailBean n adnotarea @PersistenceContext Elementul jta-data-surse cont ine numele JNDI a bazei de date denit n glasssh. Aplicat ia client Desf a surarea aplicat iei client este
agendae-client |--> ejb | | AgendaEMail.class |--> entity | | Adrese.class |--> META-INF | | MANIFEST.MF | Client.class
public c l a s s C l i e n t { @EJB private s t a t i c AgendaEMail bean ; private s t a t i c L i s t <Adrese > l i s t =n u l l ; public s t a t i c void main ( S t r i n g [ ] a r g s ) { i n t p r e l , no ; S t r i n g ch=Y , nume= , e m a i l= ; S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ;
278
18 19 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
I t e r a t o r <Adrese > i t e r=n u l l ; Adrese i n r e g=n u l l ; try { while ( ch . s t a r t s W i t h ( Y ) ) { do { System . out . p r i n t l n ( Continue ? (Y/N) ) ; ch=s c a n n e r . n e x t ( ) . toUpperCase ( ) ; } while ( ( ! ch . s t a r t s W i t h ( Y ))&&(! ch . s t a r t s W i t h ( N ) ) ) ; i f ( ch . s t a r t s W i t h ( Y ) ) { System . out . p r i n t l n ( Natura i n t e r o g a r i i ? ) ; System . out . p r i n t l n ( ( Dupa nume : 1 , Dupa e m a i l : 2 ) ) ; do { p r e l =0; try { p r e l=s c a n n e r . n e x t I n t ( ) ; } catch ( InputMismatchException e ) { } } while ( ( p r e l <1)&&( p r e l > 2 ) ) ; switch ( p r e l ) { case 1 : System . out . p r i n t l n ( Numele ) ; nume=s c a n n e r . n e x t ( ) . t r i m ( ) ; l i s t =bean . g e t E m a i l ( nume ) ; i t e r= l i s t . i t e r a t o r ( ) ; System . out . p r i n t l n ( A d r e s e l e de e m a i l p e n t r u : +nume ) ; while ( i t e r . hasNext ( ) ) { i n r e g =( Adrese ) i t e r . n e x t ( ) ; System . out . p r i n t l n ( i n r e g . g e t E m a i l ( ) ) ; } break ; case 2 : System . out . p r i n t l n ( Email ) ; e m a i l=s c a n n e r . n e x t ( ) . t r i m ( ) ; l i s t =bean . getNume ( e m a i l ) ; i t e r= l i s t . i t e r a t o r ( ) ; System . out . p r i n t l n ( I n r e g i s t r a r i l e p e n t r u a d r e s a : +e m a i l ) ; while ( i t e r . hasNext ( ) ) { i n r e g =( Adrese ) i t e r . n e x t ( ) ; System . out . p r i n t l n ( i n r e g . getNume ( ) ) ; } break ; default : System . out . p r i n t l n ( Comanda e r o n a t a ) ; } } } } catch ( E x c e p t i o n e ) { e . printStackTrace ( ) ; } } }
O aplicat ie Java destinat a a utilizat a pe un calculator poate valoricat a si ntr-o ret ea, pe baza protocolului Java Network Launching Protocol - JNLP. Tehnologia poart a numele de Java Web Start. Aplicat ia Java trebuie s a satisfac a o serie de restrict ii: Aplicat ia trebuie arhivat a cu jar; Arhiva jar trebuie certicat a. Certicarea se realizeaz a cu utilitarele keytool.exe si jarsigner.exe din distribut ia jdk; Eventualele date necesare aplicat iei se introduc prin intermediul unei interfet e grace (JavaFX, swing, SWT, apache-pivot ); Acces limitat la propriet a tile si resursele sistemului client. Aplicat iei i se ata seaz a un sier xml, dar cu extensia jnlp, care se va apela dintr-un navigator. Pentru acest sier folosim terminologia de sier jnlp. Fi sierul jnlp xeaz a: referint a URL a aplicat ie (prin atributul codebase); arhivele jar utilizate (prin atributul href); clasa cu metoda main (prin atributul main-class). Ansamblul de resurse formeaz a o aplicat ie Web care poate desf a surat a ntr-un server Web (container de servlet) sau poate incorporat ntr-un servlet. Ar at am activit a tile care trebuie ntreprinse n cazul unui exemplu simplu dat de clasa VisualCmmdc.java. 279
280
1 2 3 4 6 8 9 10 12 13 14 15 16 17 18 19 20 21 22 23 24 25 27 28 29 31 32 33 35 36 37 38 39 40 41
public c l a s s VisualCmmdc extends j a v a x . swing . JFrame { public VisualCmmdc ( ) { initComponents ( ) ; } private long cmmdc( long m, long n ) { . . . } private void i n i t C o m p o n e n t s ( ) { // cod g e n e r a t de Netbeans } private void cmmdcButtonMouseClicked ( j a v a . awt . e v e n t . MouseEvent e v t ) { try { S t r i n g sm=mTextField . g e t T e x t ( ) ; S t r i n g sn=n T e x t F i e l d . g e t T e x t ( ) ; long m =Long . par se Lo ng ( sm ) ; long n=Long . pa rs eL ong ( sn ) ; long c=cmmdc(m, n ) ; S t r i n g s =(new Long ( c ) ) . t o S t r i n g ( ) ; cmmdcTextField . s e t T e x t ( s ) ; } catch ( E x c e p t i o n e ) { System . e r r . p r i n t l n ( E x c e p t i o n : +e . g e t M e s s a g e ( ) ) ; } } private void exitForm ( j a v a . awt . e v e n t . WindowEvent e v t ) { System . e x i t ( 0 ) ; } public s t a t i c void main ( S t r i n g a r g s [ ] ) { new VisualCmmdc ( ) . s e t V i s i b l e ( true ) ; } private private private private private private } j a v a x . swing . JButton cmmdcButton ; j a v a x . swing . J L a b e l mLabel ; j a v a x . swing . J L a b e l nLabel ; j a v a x . swing . J T e x t F i e l d mTextField ; j a v a x . swing . J T e x t F i e l d n T e x t F i e l d ; j a v a x . swing . J T e x t F i e l d cmmdcTextField ;
281
Primele dou a act iuni au ca rezultat obt inerea certicatului myKeystore iar ultima act iune reprezint a nglobarea certic arii n arhiva resursa.jar - n cazul exemplului cmmdc.jar. 3. Se editeaz a sierul launch .jnlp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
<? xml version= 1 . 0 e n c o d i n g=UTF8 ?> < j n l p c o d e b a s e= h t t p : // h o s t : 8 0 8 0 /cmmdc> < i n f o r m a t i o n> < t i t l e > . . . </ t i t l e > < vendor> . . . </ vendor> < d e s c r i p t i o n > . . . </ d e s c r i p t i o n > </ i n f o r m a t i o n> < r e s o u r c e s> < j 2 s e version= 1.2+ /> < j a r h r e f=cmmdc . j a r /> </ r e s o u r c e s> < s e c u r i t y> < a l l p e r m i s s i o n s /> </ s e c u r i t y > < a p p l i c a t i o n d e s c main c l a s s=VisualCmmdc /> </ j n l p>
host se nlocuie ste cu numele calculatorului care g azduie ste serverul Web. 4. Se creaz a sier de apelare a aplicat iei (cmmdc.html )
1 2 3 4
282
5 6 7 8 9
<a href= h t t p : / / h o s t : 8 0 8 0 / cmmdc/ l a u n c h . j n l p > Launch t h e a p p l i c a t i o n </ a> </ center> </ body> </ html>
5. Ansamblul
cmmdc | cmmdc.jar | cmmdc.html | launch.jnlp
se copiaz a n serverul Web. Dintr-un navigator, apelarea aplicat iei este http://host:port/cmmdc/ cmmdc. html. Fi sierul jnlp se descarc a pe calculatorul clientului si se proceseaz a cu bin\javaws.exe din Java.
Fi sierul jnlp-servlet.jar se preia din distribut ia JDK, din catalogul sample/jnlp/servlet. Fi sierul web.xml este
1 2 3 4 5 6
? xml v e r s i o n= 1 . 0 e n c o d i n g= i s o 8859 1?> < !D O C T Y P E webapp PUBLIC //Sun Microsystems , I n c . / /DTD Web A p p l i c a t i o n 2 . 3 / /EN h t t p : // j a v a . sun . com/ dtd /weba p p 2 3 . dtd > <webapp> < ! Standard Ac ti o n S e r v l e t C o n f i g u r a t i o n ( w i t h d e b u g g i n g ) >
283
7 8 9 10 11 12 13 14 15 16 17 18 19
<webapp> < s e r v l e t> < s e r v l e t name> J n l p D o w n l o a d S e r v l e t</ s e r v l e t name> < s e r v l e t c l a s s> j n l p . sample . s e r v l e t . J n l p D o w n l o a d S e r v l e t </ s e r v l e t c l a s s > </ s e r v l e t > < s e r v l e t mapping> < s e r v l e t name> J n l p D o w n l o a d S e r v l e t</ s e r v l e t name> < u r l p a t t e r n> . j n l p</ u r l p a t t e r n> </ s e r v l e t mapping> </webapp> </webapp>
5. Cont inutul catalogului de lucru se arhiveaz a ntr-un sier war. jar cfv cmmdc.war app/* WEB-INF/* cmmdc.html 6. Utiliz and apache-tomcat sau jetty, de exemplu, sierul war se copiaz a n catalogul webapps al serverului web. Dintr-un navigator, apelarea aplicat iei se obt ine prin http://host:8080/cmmdc/cmmdc.html. Dac a aplicat ia Java utilizeaz a imagini grace acestea trebuie arhivate mpreun a cu aplicat ia, de exemplu ntr-un catalog images. Inc arcarea si a sarea unei imagini program andu-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. Dac a aplicat ia Java utilizeaz a alte resurse date prin siere jar atunci toate sierele jar trebuie s a poarte acea si certicare. 2. Fi sierele jar certicate se depun n catalogul app\lib. 3. In sierul jnlp, n elementul resources, pentru ecare sier jar utilizat se introduce declarat ia <jar href=lib/resource.jar/> Dac a arhiva jar a aplicat iei Java este executabil a atunci, n sierul jnlp, elementul application-desc poate lipsi. Intr-o arhiv a jar executabil a, sierul MANIFEST.MF indic a clasa cu metoda main si eventualele resurse externe utilizate ( siere jar) prin propriet a tile
284
Pentru a obt ine sierul MANIFEST.MF cu aceste propriet a ti se editeaz a un sier text cu cont inutul de mai sus, denumit de exemplu myManifest.mf, si se arhiveaz a prin
jar cfvm numeArhiva.jar myManifest.mf *.class lib
286
Terminologia server MBean se justic a prin faptul c a poate invocat de un program client. In aceast a ipostaz a, serverul MBean are rolul unui container de MBean-uri si de gestionare si execut ie a apelurilor client ilor. Structura unei aplicat ii JMX cont ine dou a nivele: componentele MBean; agentul (serverul MBean).
13.1
13.1.1
Standard MBean
Crearea unui Standard MBean
O component a MBean este alc atuit a dintr-o interfat a si o clas a care implementeaz a interfat a satisf ac and urm atoarele restrict ii: 1. interfat a are numele clasei care o implementeaz a av and n plus suxul MBean; 2. Interfat a si clasa care o implementeaz a apart in aceluia si pachet; 3. constructorii si metodele expuse trebuie s a e publice. In continuare c ampurile si metodele destinate expunerii se vor denumi atribute, respectiv operat ii. Fiec arui atribut xxx i se ata seaz a cel put in una din metodele public void setXxx(tip xxx){ this.xxx=xxx; } si / sau public tip getXxx(){ return xxx; } Un atribut se precizeaz a doar prin aceste metode, f ar a denirea / declararea c ampului corespunz ator. C ampul se dene ste n clasa ce implementeaz a interfat a MBean-ului. Astfel, un MBean este caracterizat de
287
atribute care pot consultate (citite), modicate (scrise) sau cu ambele opt iuni. operat ii notic ari cu evident a modic arilor suferite de atribute. Exemplul 13.1.1 Construim un MBean cu atributele label ce poate numai citit; cursEuro care poate consultat si modicat; operat iile public String sayHello() a seaz a un mesaj; public long cmmdc(long m, long n); de calcul a celui mai mare divizor comun a dou a numere naturale. Interfat a IntroMBean este
1 3 4 5 6 8 9 10 11 12 13 14
package b a s i c ; public i n t e r f a c e IntroMBean { // O p e r a t i i public S t r i n g s a y H e l l o ( ) ; public long cmmdc( long m, long n ) ; // A t r i b u t e // read o n l y public S t r i n g g e t L a b e l ( ) ; // read w r i t e public double getCursEuro ( ) ; public void s e t C u r s E u r o ( double c u r s E u r o ) ; }
288
1 3 5 6 7 9 10 11 13 14 15 17 18 19 21 22 23 24 25 26 28 29
package b a s i c ; public c l a s s I n t r o implements IntroMBean { // A t r i b u t e private f i n a l S t r i n g l a b e l = Fac . Matematica s i I n f o r m a t i c a ; private double c u r s E u r o = 4 . 5 0 ; public S t r i n g g e t L a b e l ( ) { return l a b e l ; } public double getCursEuro ( ) { return c u r s E u r o ; } public synchronized void s e t C u r s E u r o ( double c u r s E u r o ) { this . cursEuro = cursEuro ; } // O p e r a t i i public S t r i n g s a y H e l l o ( ) { S t r i n g message= H e l l o World ! ; System . out . p r i n t l n ( message ) ; return message ; } public long cmmdc( long m, long n ) { . . . } }
13.1.2
Un agent sau MBean server implementeaz a interfat a MBeanServer. Un asemenea obiect se obt ine printr-una din metodele statice static MBeanServer ManagementFactory.getPlatformMBeanServer() Utilitarul jconsole permite conectarea la serverul MBean. static MBeanServer MBeanServerFactory.createMBeanServer() In agent se nregistreaz a componente MBean. Un obiect MBean este caracterizat de un nume, un obiect de tip ObjectName. Inregistrarea si / sau crearea unei componente MBean necesit a denirea n prealabil a acestui nume. Structura unei nume este domeniu : numeAtribut=valAtribut ,numeAtribut=valAtribut . . . unde
289
domeniu este un nume simbolic (String). Dac a domeniul este stringul vid atunci se consider a valoarea implicit a DefaultDomain. atribute uzuale: type=numele MBean-ului index=num ar de identicare a MBean-ului Cel put in un atribut este obligatoriu. Clasa ObjectName Constructori ObjectName(String nume ) Parametrul nume are structura descris a 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 interfet ei MBeanServer. ObjectInstance Un obiect de tip ObjectInstance este folosit pentru reprezentarea ansamblului alc atuit de un obiect ObjectName asociat unui MBean si numele clasei corespunz atoare. Interfat a MBeanServer Metode ObjectInstance registerMBean(Object obj , ObjectName nume ) Inregistreaz a pe platform a, instant a obj a unui MBean av and numele nume.
290
void unregister(ObjectName nume ) ObjectInstance createMBean(String numeClas a , ObjectName nume ) Creaz a si nregistreaz a un MBean de clas a numeClas a si de nume nume. ObjectInstance createMBean(String numeClas a , ObjectName nume , Object[] param , String[] sign ) In plus, sirul param cont ine parametri constructorului, de tip, respectiv sign. String getDefaultDomain() Object invoke(ObjectName mbeanName , String operationName , Object[] param , String[] paramTip ) Se invoc a operat ia operationName a MBean-ului mbeanName. Parametri necesari operat iei mpreun a cu tipurile corespunz atoare sunt dat i n variabilele param si respectiv paramTip. Object getAttribute(ObjectName mbeanName ,String atribut ) Returneaz a valoarea atributului atribut a mbean-ului mbeanName. void setAttribute(ObjectName mbeanName ,Attribute atribut ) Fixeaz a valoarea atributului atribut a MBean-ului mbeanName. Ret inem doar constructorul clasei Attribute prin Attribute(String nume , Object valoare ) MBeanInfo getMBeanInfo(ObjectName mbeanName ) Returneaz a un obiect de tip MBeanInfo util inspect arii resurselor unui MBean. Exist a mai multe sabloane de programare a nregistr arii unei componente MBean. Exemplul 13.1.2 Se creaz a dou a componente MBean de tip Intro care vor inspectate prin intermediul utilitarului jconsole1 - distribut ia jdk . Utilitarul jconsole permite apelarea operat iilor, modicarea atributelor si semnaleaz a notic arile.
In acest caz, este nevoie ca variabilele de tip clas a acoperitoare Double, Long s a e nlocuite prin tipuri predenite.
1
291
1 2 3 4 6 7 8 9 10 11 12 14 15 16 17 19 20 22 23 25 26 27 29 30 31 32 33 34 35 36 37
package b a s i c ; import j a v a . l a n g . management . ManagementFactory ; import j a v a x . management . ObjectName ; import j a v a x . management . MBeanServer ; public c l a s s Main { public s t a t i c void main ( S t r i n g [ ] a r g s ) { S t r i n g domeniu= ; i f ( a r g s . l e n g t h > 0) domeniu=a r g s [ 0 ] ; try { // S e r v e r u l p l a t f o r m e i MBeanServer mbs = ManagementFactory . getPlatformMBeanServer ( ) ; // V a r i a n t a 1 // C o n s t r u i r e a ObjectName c o r e s p u n z a t o r MBean u l u i ObjectName mbeanObjectName = new ObjectName ( domeniu+ : t y p e=I n t r o , i n d e x=1 ) ; // Crearea MBean u l u i I n t r o mbean = new I n t r o ( ) ; // I n r e g i s t r a r e a MBean u l u i mbs . r e g i s t e r M B e a n ( mbean , mbeanObjectName ) ; // V a r i a n t a 2 mbeanObjectName=new ObjectName ( domeniu+ : t y p e=I n t r o , i n d e x=2 ) ; mbs . createMBean ( b a s i c . I n t r o , mbeanObjectName ) ; // A s t e p t a r e n e d e f i n i t a System . out . p r i n t l n ( Waiting f o r e v e r . . . ) ; while ( true ) ; } catch ( E x c e p t i o n e ) { System . e r r . p r i n t l n ( E x c e p t i o n : +e . g e t M e s s a g e ( ) ) ; } } }
Executarea aplicat iei revine la 1. Intr-o fereastr a DOS se lanseaz a agentul Main prin java -Dcom.sun.manager.jmxremote basic.Main 2. Intr-o alt a fereastr a DOS se lanseaz a jconsole pornind utilitarul jconsole. 3. In fereastra de dialog jconsole:Connect to Agent se d a clic pe Connect. 4. In panoul Tree g asim domeniul dat. Prin clic pe domeniu apar MBeanurile de indice 1 si 2. 5. Prin clic pe unul din aceste MBean-uri, n panoul central avem acces la atributele si la operat iile lor.
292
13.1.3
Notic ari
Pentru implementarea ret inerii de c atre un agent MBean a notic arilor, clasa ce implementeaz a interfat a MBean-ului trebuie s a extind a clasa NotificationBroadcasterSupport. Modic arile unui atribut se ret in ntr-un obiect de tip Notification si este transmis prin metoda sendNotification(Notification notication )
293
a clasei NotificationBroadcasterSupport. Suplimentar se dene ste metoda public MBeanNotificationInfo[] getNotificationInfo() n care se precizeaz a tipul notic arii - (constant a denit a de clasa AttributeChangeNotification); clasa n care s-a generat noticarea String name = AttributeChangeNotification.class.getName(); o descriere a modic arii. Astfel, introducerea notic arilor presupune familiarizarea cu clasele NoticationBroadcasterSupport Constructori NotificationBroadcasterSupport() Metode void sendNotification(Notification noticare ) Notication Constructori Notification(String type , Object source , long sequenceNumber ) Notification(String type , Object source , long sequenceNumber , long timeStamp ) Notification(String type , Object source , long sequenceNumber , long timeStamp , String mesaj ) Notification(String type , Object source , long sequenceNumber , String mesaj ) Metode public void setUserData(Object userData ) public Object getUserData()
294
AttributeChangeNotication extends Notication Constructori AttributeChangeNotification(Object source , long sequenceNumber , long timeStamp , String msg , String attributeName , String attributeType , Object oldValue , Object newValuE ) C ampuri static String ATTRIBUTE CHANGE Semnaleaz a schimbarea atributului Exemplul 13.1.3 Extinderea MBean-ului Intro cu noticarea modic arilor atributelor n jconsole. Implementarea notic arilor n clasa Intro presupune modicarea metodei setCursEuro. Totodat a se adaug a metoda getNoticationInfo, ce furnizeaz a informat ii referitoare la modicarea ap arut a. Codul clasei care implementeaz a interfat a devine
1 2 3 4 5 7 8 9 11 12 13 15 17 19 20 21 22 23 24 25 26 27 28 29 30 31
package ag e nt n ; import j a v a x . management . N o t i f i c a t i o n ; import j a v a x . management . A t t r i b u t e C h a n g e N o t i f i c a t i o n ; import j a v a x . management . N o t i f i c a t i o n B r o a d c a s t e r S u p p o r t ; import j a v a x . management . M B e a n N o t i f i c a t i o n I n f o ; public c l a s s I nt r oN extends N o t i f i c a t i o n B r o a d c a s t e r S u p p o r t implements IntroNMBean { private long sequenceNumber =1; // A t r i b u t e private f i n a l S t r i n g l a b e l = Fac . Matematica s i I n f o r m a t i c a ; private double c u r s E u r o = 4 . 5 0 ; public S t r i n g g e t L a b e l ( ) { . . . } public double getCursEuro ( ) { . . . } public synchronized void s e t C u r s E u r o ( double c u r s E u r o ) { double oldCursEuro=t h i s . c u r s E u r o ; this . cursEuro = cursEuro ; // System . o u t . p r i n t l n ( Curs de schimb euro : + euro+ ron . ) ; N o t i f i c a t i o n n=new A t t r i b u t e C h a n g e N o t i f i c a t i o n ( this , sequenceNumber++, System . c u r r e n t T i m e M i l l i s ( ) , Schimbarea c u r s u l u i Euro , cursEuro , double , oldCursEuro , cursEuro ) ;
295
32 33 35 36 37 38 39 40 41 42 43 44 46 47 49 50
sendNotification (n ) ; } public M B e a n N o t i f i c a t i o n I n f o [ ] g e t N o t i f i c a t i o n I n f o ( ) { S t r i n g [ ] t y p e s = new S t r i n g [ ] { A t t r i b u t e C h a n g e N o t i f i c a t i o n .ATTRIBUTE CHANGE }; S t r i n g name = A t t r i b u t e C h a n g e N o t i f i c a t i o n . c l a s s . getName ( ) ; S t r i n g d e s c r i p t i o n = An a t t r i b u t e o f t h i s MBean has changed ; MBeanNotificationInfo info = new M B e a n N o t i f i c a t i o n I n f o ( t y p e s , name , d e s c r i p t i o n ) ; return new M B e a n N o t i f i c a t i o n I n f o [ ] { i n f o } ; } // O p e r a t i i public S t r i n g s a y H e l l o ( ) { . . . } public long cmmdc( long m, long n ) { . . . } }
13.1.4
Agent MBean
In exemplelele anterioare resursele unui MBean au fost utilizate prin jconsole. Valoricarea resurselor unui MBean Intro, dintr-un MBeanServer (agent) se programeaz a prin Exemplul 13.1.4
1 2 3 4 5 6 7 9 10 11 12 13 15 16 17 18 19 20 22 23 24
package a g e n t ; import j a v a . i o . IOException ; import j a v a x . management . ObjectName ; import j a v a x . management . MBeanServer ; import j a v a x . management . MBeanServerFactory ; import j a v a x . management . A t t r i b u t e ; import j a v a . u t i l . S c a n n e r ; public c l a s s Agent { public s t a t i c void main ( S t r i n g [ ] a r g s ) { try { // Crearea A g e n t u l u i MBeanServer MBeanServer mbs = MBeanServerFactory . c r e a t e M B e a n S e r v e r ( ) ; // Crearea unui MBean S t r i n g domain = mbs . g e t D e f a u l t D o m a i n ( ) ; S t r i n g className= a g e n t . I n t r o ; S t r i n g sObjectName=domain+ : t y p e=+className ; ObjectName mbeanObjectName = new ObjectName ( sObjectName ) ; mbs . createMBean ( className , mbeanObjectName ) ; // U t i l i z a r e a MBean u l u i // A p e l a r e a o p e r a t i i l o r S t r i n g o p e r a t i a= s a y H e l l o ;
296
25 27 28 29 30 31 32 33 34 35 36 37 39 40 41 43 44 45 46 47 48 49 50 51 52 53 54
mbs . i n v o k e ( mbeanObjectName , o p e r a t i a , null , n u l l ) ; o p e r a t i a=cmmdc ; System . out . p r i n t l n ( Cmmdc a l n u m e r e l o r : ) ; S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ; System . out . p r i n t l n ( Primul numar : ) ; long m =s c a n n e r . nextLong ( ) ; System . out . p r i n t l n ( Al d o i l e a numar : ) ; long n=s c a n n e r . nextLong ( ) ; O b j e c t [ ] param={m, n } ; S t r i n g [ ] s i g n ={ l o n g , l o n g } ; Long r =(Long ) mbs . i n v o k e ( mbeanObjectName , o p e r a t i a , param , s i g n ) ; System . out . p r i n t l n ( cmmdc=+r . t o S t r i n g ( ) ) ; // U t i l i z a r e a A t r i b u t e l o r S t r i n g l a b e l =( S t r i n g ) mbs . g e t A t t r i b u t e ( mbeanObjectName , L a b e l ) ; System . out . p r i n t l n ( V a l o a r e a a t r i b u t u l u i l a b e l : +l a b e l ) ; System . out . p r i n t l n ( I n t r o d u c e t i c u r s u l e u r o ) ; double c u r s E u r o=s c a n n e r . nextDouble ( ) ; A t t r i b u t e c u r s=new A t t r i b u t e ( CursEuro , c u r s E u r o ) ; mbs . s e t A t t r i b u t e ( mbeanObjectName , c u r s ) ; Double e u r o =(Double ) mbs . g e t A t t r i b u t e ( mbeanObjectName , CursEuro ) ; System . out . p r i n t l n ( V a l o a r e a a t r i b u t u l u i c u r s E u r o : +e u r o ) ; } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ; } } }
13.1.5
Invocarea la distant a
Din punct de vedere al program arii distribuite, cazul interesant este cel n care clasa ce implementeaz a MBean-ul si clientul (agentul MBean) care o utilizeaz a se a a pe calculatoare diferite. In acest caz: Este nevoie de o clasa server (agent) al c arui rol este Instant ierea unui MBeanServer Instant iarea unui server de conexiune, obiect de tip MBeanServerConnection. Bazat pe tehnologia RMI sau RMI-IIOP, acest obiect gestioneaz a comunicat ia dintre un client si serverul MBeanServer. Serverul de conexiune si serverul MBeanServer apart in aceleia si clase. In cazul utiliz arii tehnologiei RMI rmiregistry si serverul MBeanServer trebuie s a ruleze pe acela si calculator. Utiliz and tehnologia RMI-IIOP, orbd si serverul MBeanServer pot rula pe calculatoare distincte.
297
Lansarea n execut ie a serverului de conexiune. Clientul dispune de interfat a MBean-ului. Interfat a MBeanServerConnection este implementat a de clasa MBeanServer S ablonul de programare pentru instant ierea obiectului de tip MBeanServerConnection si lansarea sa n execut ie poate :
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 c atre client. Lansarea n execut ie a serverului este precedat a de pornirea registrului rmiregistry, respectiv orbd. Exemplul 13.1.5
1 2 3 4 5 6 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
package s e r v e r ; import j a v a x . management . MBeanServer ; import j a v a x . management . MBeanServerFactory ; import j a v a x . management . remote . JMXServiceURL ; import j a v a x . management . remote . JMXConnectorServer ; import j a v a x . management . remote . JMXConnectorServerFactory ; public c l a s s MBServer { public s t a t i c void main ( S t r i n g [ ] a r g s ) { S t r i n g h o s t= l o c a l h o s t ; S t r i n g p o r t= 1099 ; // S t r i n g p o r t =1050; i f ( a r g s . l e n g t h ==0){ System . out . p r i n t l n ( The name o f t h e s e r v e r i s r e q u i r e d ) ; System . e x i t ( 0 ) ; } i f ( a r g s . l e n g t h >=2) h o s t=a r g s [ 1 ] ; i f ( a r g s . l e n g t h >=3) p o r t=a r g s [ 2 ] ; try { // Crearea MBeanServer MBeanServer mbs = MBeanServerFactory . c r e a t e M B e a n S e r v e r ( ) ;
298
25 26 27 28 29 30 31 32 34 35 36 37 38 39 40 41 42 43 44 45
// Crearea unui s e r v e r c o n e c t o r S t r i n g s u r l= s e r v i c e : jmx : rmi : / / / j n d i / rmi : / / + h o s t+ : +p o r t+ / +a r g s [ 0 ] ; // S t r i n g s u r l = s e r v i c e : jmx : i i o p : / / / j n d i / i i o p ://+ // h o s t +:+ p o r t +/+ a r g s [ 0 ] ; JMXServiceURL u r l=new JMXServiceURL ( s u r l ) ; JMXConnectorServer c s= JMXConnectorServerFactory . newJMXConnectorServer ( u r l , null , mbs ) ; // P o r n i r e a s e r v e r c o n e c t o r u l u i cs . s tart ( ) ; System . out . p r i n t l n ( P r e s s Enter t o f i n i s h ! ) ; System . i n . r e a d ( ) ; cs . stop ( ) ; } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ; e . printStackTrace ( ) ; } } }
Primul argument care trebuie furnizat programului anterior (args[0] ) este numele serverului. Clientul, la r andul lui, este nevoit s a creeze un conector c atre server (agent), prin intermediul c aruia obt ine un obiect ce implementeaz a interfat a MBeanServerConnection. Prin acest obiect, clientul va putea crea MBean-uri - n agent - si le va putea utiliza resursele. S ablonul de programare pentru crearea obiectului MBeanServerConnection poate
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 interfet ei MBeanServerConnection. crearea unui reprezentant local al MBean-ului prin metoda static a mbeanClass proxy = (mbeanClass) MBeanServerInvocationHandler.newProxyInstance( mbeanServerConnection,mbeanObjectName,mbeanClass.class,true); In nal, MBean-ul se sterge din serverul de conexiune, prin cs.unregisterMBean(mbeanObjectName).
299
package c l i e n t ; import j a v a . u t i l . S c a n n e r ; import j a v a x . management . MBeanServerConnection ; import j a v a x . management . ObjectName ; import j a v a x . management . A t t r i b u t e ; import j a v a x . management . M B e a n S e r v e r I n v o c a t i o n H a n d l e r ; import j a v a x . management . remote . JMXServiceURL ; import j a v a x . management . remote . JMXConnector ; import j a v a x . management . remote . JMXConnectorFactory ; public c l a s s C l i e n t { public s t a t i c void main ( S t r i n g [ ] a r g s ) { S t r i n g h o s t= l o c a l h o s t ; S t r i n g p o r t= 1099 ; i f ( a r g s . l e n g t h <=1){ System . out . p r i n t l n ( The s e r v e r and domain names a r e r e q u i r e d ) ; System . e x i t ( 0 ) ; } S t r i n g serverName=a r g s [ 0 ] ; S t r i n g domain=a r g s [ 1 ] ; i f ( a r g s . l e n g t h >=3) h o s t=a r g s [ 2 ] ; i f ( a r g s . l e n g t h >=4) p o r t=a r g s [ 4 ] ; S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ; try { // Crearea unui c o n e c t o r s i a o b i e c t u l u i de t i p M B e a n S e r v e r c s e c t i o n S t r i n g s u r l= s e r v i c e : jmx : rmi : / / / j n d i / rmi : / / + h o s t+ : +p o r t+ / +a r g s [ 0 ] ; // S t r i n g s u r l = s e r v i c e : jmx : i i o p : / / / j n d i / i i o p ://+ // h o s t +:+ p o r t +/+ a r g s [ 0 ] ; JMXServiceURL u r l = new JMXServiceURL ( s u r l ) ; JMXConnector jmxc = JMXConnectorFactory . c o n n e c t ( u r l , n u l l ) ; MBeanServerConnection c s = jmxc . getMBeanServerConnection ( ) ; // Domeniile a g e n t u l u i s u n t System . out . p r i n t l n ( Domains : ) ; S t r i n g domains [ ] = c s . getDomains ( ) ; f o r ( i n t i = 0 ; i < domains . l e n g t h ; i ++) { System . out . p r i n t l n ( \ tDomain [ + i + ] = + domains [ i ] ) ; } // i a r domeniul i m p l i c i t System . out . p r i n t l n ( DefaultDomain : +c s . g e t D e f a u l t D o m a i n ( ) ) ; System . out . p r i n t l n ( Domain : +domain ) ; // Crearea unui MBean I n t r o S t r i n g className= b a s i c . I n t r o ; S t r i n g sObjectName=domain+ : t y p e=+className ; ObjectName mbeanObjectName = new ObjectName ( sObjectName ) ; c s . createMBean ( className , mbeanObjectName , null , n u l l ) ; double c u r s E u r o ; long m, n ; // U t i l i z a r e a MBean u l u i // V a r i a n t a 1 de i n v o c a r e p r i n p r o x y
300
56 57 58 59 60 61 62 64 65 66 68 69 70 71 72 73 74 76 77 78 79 80 81 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 99 100 101 103 104 105 106 107 108 109 110 111 112 113 114
System . out . p r i n t l n ( V a r i a n t a de i n v o c a r e p r i n p r o x i ) ; IntroMBean proxy= ( IntroMBean ) M B e a n S e r v e r I n v o c a t i o n H a n d l e r . n e w P r o x y I n s t a n c e ( cs , mbeanObjectName , c l i e n t . IntroMBean . c l a s s , true ) ; // U t i l i z a r e a o p e r a t i i l o r // o p e r a t i a s a y H e l l o proxy . s a y H e l l o ( ) ; // o p e r a t i a cmmdc System . out . p r i n t l n ( Cmmdc a l n u m e r e l o r : ) ; System . out . p r i n t l n ( Primul numar : ) ; m =s c a n n e r . nextLong ( ) ; System . out . p r i n t l n ( Al d o i l e a numar : ) ; n=s c a n n e r . nextLong ( ) ; System . out . p r i n t l n ( Cmmdc=+proxy . cmmdc(m, n ) ) ; // U t i l i z a r e a a t r i b u t e l o r System . out . p r i n t l n ( Numele : +proxy . g e t L a b e l ( ) ) ; System . out . p r i n t l n ( I n t r o d u c e t i c u r s u l e u r o ) ; c u r s E u r o=s c a n n e r . nextDouble ( ) ; proxy . s e t C u r s E u r o ( c u r s E u r o ) ; System . out . p r i n t l n ( Euro : +proxy . getCursEuro ( ) ) ; // V a r i a n t a 2 de i n v o c a r e p r i n c o n e x i u n e System . out . p r i n t l n ( V a r i a n t a de i n v o c a r e p r i n c o n e x i u n e ) ; // A p e l a r e a o p e r a t i i l o r S t r i n g o p e r a t i a= s a y H e l l o ; c s . i n v o k e ( mbeanObjectName , o p e r a t i a , null , n u l l ) ; o p e r a t i a=cmmdc ; System . out . p r i n t l n ( Cmmdc a l n u m e r e l o r : ) ; System . out . p r i n t l n ( Primul numar : ) ; m =s c a n n e r . nextLong ( ) ; System . out . p r i n t l n ( Al d o i l e a numar : ) ; n=s c a n n e r . nextLong ( ) ; O b j e c t [ ] param={m, n } ; S t r i n g [ ] s i g n ={ l o n g , l o n g } ; Long r =(Long ) c s . i n v o k e ( mbeanObjectName , o p e r a t i a , param , s i g n ) ; System . out . p r i n t l n ( Cmmdc=+r . t o S t r i n g ( ) ) ; // U t i l i z a r e a A t r i b u t e l o r S t r i n g l a b e l =( S t r i n g ) c s . g e t A t t r i b u t e ( mbeanObjectName , L a b e l ) ; System . out . p r i n t l n ( V a l o a r e a a t r i b u t u l u i l a b e l : +l a b e l ) ; System . out . p r i n t l n ( I n t r o d u c e t i c u r s u l e u r o ) ; c u r s E u r o=s c a n n e r . nextDouble ( ) ; A t t r i b u t e c u r s=new A t t r i b u t e ( CursEuro , c u r s E u r o ) ; c s . s e t A t t r i b u t e ( mbeanObjectName , c u r s ) ; Double newEuro=(Double ) c s . g e t A t t r i b u t e ( mbeanObjectName , CursEuro ) ; System . out . p r i n t l n ( V a l o a r e a a t r i b u t u l u i e u r o : +newEuro ) ; c s . u n r e g i s t e r M B e a n ( mbeanObjectName ) ; } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ; } }
301
115
Inspectarea si valoricarea resurselor unei componente MBean se poate face si prin intermediul metodei
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
private s t a t i c void getMBeanResources ( MBeanInfo i n f o ) { System . out . p r i n t l n ( CLASA : \ t + i n f o . getClassName ( ) ) ; System . out . p r i n t l n ( DESCR: \ t + i n f o . g e t D e s c r i p t i o n ( ) ) ; System . out . p r i n t l n ( ATTRIBUTE ) ; MBeanAttributeInfo [ ] a t t r I n f o = i n f o . g e t A t t r i b u t e s ( ) ; i f ( a t t r I n f o . length > 0) { f o r ( i n t i = 0 ; i < a t t r I n f o . l e n g t h ; i ++) { System . out . p r i n t l n ( \tNUME: \ t + a t t r I n f o [ i ] . getName ( ) ) ; System . out . p r i n t l n ( \ tDESC : \ t + a t t r I n f o [ i ] . g e t D e s c r i p t i o n ( ) ) ; System . out . p r i n t l n ( \ tTIP : \ t + a t t r I n f o [ i ] . getType ( ) + READ: + a t t r I n f o [ i ] . i s R e a d a b l e ( ) + WRITE: + a t t r I n f o [ i ] . i s W r i t a b l e ( ) ) ; } } else System . out . p r i n t l n ( \ t F a r a a t r i b u t e ! ) ; System . out . p r i n t l n ( CONSTRUCTORI ) ; MBeanConstructorInfo [ ] c o n s t r I n f o = i n f o . g e t C o n s t r u c t o r s ( ) ; f o r ( i n t i =0; i < c o n s t r I n f o . l e n g t h ; i ++) { System . out . p r i n t l n ( \tNUME: \ t + c o n s t r I n f o [ i ] . getName ( ) ) ; System . out . p r i n t l n ( \tDESCR : \ t + c o n s t r I n f o [ i ] . g e t D e s c r i p t i o n ( ) ) ; System . out . p r i n t l n ( \tPARAM: \ t + c o n s t r I n f o [ i ] . g e t S i g n a t u r e ( ) . l e n g t h + p a r a m e t r i ) ; } System . out . p r i n t l n ( OPERATII ) ; MBeanOperationInfo [ ] o p I n f o = i n f o . g e t O p e r a t i o n s ( ) ; i f ( opInfo . length > 0) { f o r ( i n t i = 0 ; i < o p I n f o . l e n g t h ; i ++) { System . out . p r i n t l n ( \tNUME: \ t + o p I n f o [ i ] . getName ( ) ) ; System . out . p r i n t l n ( \tDESCR : \ t + o p I n f o [ i ] . g e t D e s c r i p t i o n ( ) ) ; System . out . p r i n t l n ( \tPARAM: \ t + o p I n f o [ i ] . g e t S i g n a t u r e ( ) . l e n g t h + p a r a m e t r i ) ; } } else System . out . p r i n t l n ( \ t F a r a o p e r a t i i ) ; System . out . p r i n t l n ( NOTIFICARI ) ; MBeanNotificationInfo [ ] n o t i f I n f o = info . g e t N o t i f i c a t i o n s ( ) ; i f ( n o t i f I n f o . length > 0) { f o r ( i n t i = 0 ; i < n o t i f I n f o . l e n g t h ; i ++) { System . out . p r i n t l n ( \tNUME: + n o t i f I n f o [ i ] . getName ( ) ) ; System . out . p r i n t l n ( \tDESCR : + n o t i f I n f o [ i ] . g e t D e s c r i p t i o n ( ) ) ; String notifTypes [ ] = n o t i f I n f o [ i ] . getNotifTypes ( ) ; f o r ( i n t j = 0 ; j < n o t i f T y p e s . l e n g t h ; j ++) { System . out . p r i n t l n ( \ tTIP : + n o t i f T y p e s [ j ] ) ; } } } else System . out . p r i n t l n ( \ t F a r a n o t i f i c a r i ) ; }
Aceast a metod a poate inserat a n oricare din programele agent sau client.
302
Noticarea la distant a
Noticarea la distant a presupune utilizarea unui MBean posed and aceast a facilitate. Pe partea de client trebuie implementat interfat a NotificationListener care declar a metoda public void handleNotification(Notification notication , Object handback ) Ata sarea si disponibilizarea clasei ce implementeaz a interfat a Notification Listener se obt in prin metodele interfet ei MBeanServerConnection: void addNotificationListener(ObjectName name , NotificationListener listener , NotificationFilter lter , Object handback )throws InstanceNotFoundException, IOException void removeNotificationListener(ObjectName name , ObjectName listener )throws InstanceNotFoundException, ListenerNotFoundException, IOException Exemplul 13.1.7 Folosind exemplul 13.1.6 - dar cu MBean-ul creat pentru 13.1.3 se creaz a un client cu noticare, care sesiseaz a modicarea valoarii atributului cursEuro a MBean-ului IntroN. Implementarea interfet ei NotificationListener este
1 2 3 4 6 7 8 9 10 11 12 13 14 15 16 17
package c l i e n t ; import j a v a x . management . N o t i f i c a t i o n ; import j a v a x . management . N o t i f i c a t i o n L i s t e n e r ; import j a v a x . management . A t t r i b u t e C h a n g e N o t i f i c a t i o n ; public c l a s s C l i e n t L i s t e n e r implements N o t i f i c a t i o n L i s t e n e r { public void h a n d l e N o t i f i c a t i o n ( N o t i f i c a t i o n n o t i f i c a t i o n , O b j e c t handback ) { System . out . p r i n t l n ( \ n R e c e i v e d n o t i f i c a t i o n : + n o t i f i c a t i o n ) ; A t t r i b u t e C h a n g e N o t i f i c a t i o n myNotif= ( AttributeChangeNotification ) n o t i f i c a t i o n ; System . out . p r i n t l n ( Curs i n i t i a l : + myNotif . g e tO l d V a l u e ( ) . t o S t r i n g ( ) ) ; System . out . p r i n t l n ( Curs c u r e n t : + myNotif . getNewValue ( ) . t o S t r i n g ( ) ) ; } }
package c l i e n t ; import j a v a x . management . ObjectName ; import j a v a x . management . MBeanInfo ; import j a v a x . management . M B e a n A t t r i b u t e I n f o ; import j a v a x . management . MBeanConstructorInfo ;
303
6 7 8 9 10 11 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 35 36 37 38 40 41 43 44 45 46 47 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
j a v a x . management . MBeanOperationInfo ; j a v a x . management . M B e a n N o t i f i c a t i o n I n f o ; j a v a x . management . MBeanServerConnection ; j a v a x . management . remote . JMXServiceURL ; j a v a x . management . remote . JMXConnector ; j a v a x . management . remote . JMXConnectorFactory ;
public c l a s s C l i e n t N o t i f { public s t a t i c void main ( S t r i n g [ ] a r g s ) { S t r i n g h o s t= l o c a l h o s t ; S t r i n g p o r t= 1099 ; i f ( a r g s . l e n g t h <=1){ System . out . p r i n t l n ( The s e r v e r and domain names a r e r e q u i r e d ) ; System . e x i t ( 0 ) ; } S t r i n g serverName=a r g s [ 0 ] ; S t r i n g domain=a r g s [ 1 ] ; i f ( a r g s . l e n g t h >=3) h o s t=a r g s [ 2 ] ; i f ( a r g s . l e n g t h >=4) p o r t=a r g s [ 3 ] ; C l i e n t N o t i f o b j=new C l i e n t N o t i f ( ) ; try { // Crearea unui c o n e c t o r s i a o b i e c t u l u i // de t i p MBeanServerConnection S t r i n g s u r l= s e r v i c e : jmx : rmi : / / / j n d i / rmi : / / + h o s t+ : +p o r t+ / +a r g s [ 0 ] ; JMXServiceURL u r l = new JMXServiceURL ( s u r l ) ; JMXConnector jmxc = JMXConnectorFactory . c o n n e c t ( u r l , n u l l ) ; MBeanServerConnection c s = jmxc . getMBeanServerConnection ( ) ; // Crearea o b i e c t u l u i OBjectName a t a s a t MBean u l u i IntroN S t r i n g className= b a s i c n . I nt r oN ; S t r i n g sObjectName=domain+ : t y p e=+className ; ObjectName mbeanObjectName = new ObjectName ( sObjectName ) ; MBeanInfo i n f o=c s . getMBeanInfo ( mbeanObjectName ) ; getMBeanResources ( i n f o ) ; // U t i l i z a r e a n o t i f i c a r i i // Crearea unui a s c u l t a t o r C l i e n t L i s t e n e r l i s t e n e r = new C l i e n t L i s t e n e r ( ) ; // A c t i v a r e a n o t i f i c a t o r u l u i c s . a d d N o t i f i c a t i o n L i s t e n e r ( mbeanObjectName , l i s t e n e r , null , o b j ) ; Thread . s l e e p ( 5 0 0 ) ; // D i s p o n i b i l i z a r e a a s c u l t a t o r u l u i de n o t i f i c a r i System . out . p r i n t l n ( P r e s s Enter t o f i n i s h ! ) ; try { System . i n . r e a d ( ) ; } catch ( j a v a . i o . IOException e ) { } c s . r e m o v e N o t i f i c a t i o n L i s t e n e r ( mbeanObjectName , l i s t e n e r ) ; // D i s p o n i b i l i z a r e a o b i e c t u l u i MBeanObjectName c s . u n r e g i s t e r M B e a n ( mbeanObjectName ) ; } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ; e . printStackTrace ( ) ; } }
304
66 68
Clasa Client care creaz a MBean-ul trebuie lansat a naintea clasei ClientNotif. Aceste dou a clase pot rula pe calculatoare distincte. Exemplul 13.1.8 O aplicat ie servlet ntret ine un cont. Act iunile ce pot ntreprinse sunt: depunerea unei sume, extragerea unei sume n limita soldului si consultarea contului. Contul este implementat ca un MBean standard. Se cere urm arirea la distant a a modic arilor suferite de cont. Interfat a contului (a MBean-ului) este
1 2 3 4 5 6
implementat prin
1 2 3 4 6 7 8 9 11 12 13 15 16 17 18 19 20 21 22 23 24 25 26 27 28 30 31 32
public c l a s s Cont extends N o t i f i c a t i o n B r o a d c a s t e r S u p p o r t implements ContMBean { private long sequenceNumber =1; private double c o n t ; public synchronized double getCont ( ) { return c o n t ; } public synchronized void s e t C o n t ( double c o n t ) { double oldCont=t h i s . c o n t ; t h i s . c o n t=c o n t ; N o t i f i c a t i o n n=new A t t r i b u t e C h a n g e N o t i f i c a t i o n ( this , sequenceNumber++, System . c u r r e n t T i m e M i l l i s ( ) , Schimbarea Cont , cont , double , oldCont , cont ) ; sendNotification (n ) ; } public M B e a n N o t i f i c a t i o n I n f o [ ] g e t N o t i f i c a t i o n I n f o ( ) { S t r i n g [ ] t y p e s = new S t r i n g [ ] { A t t r i b u t e C h a n g e N o t i f i c a t i o n .ATTRIBUTE CHANGE
305
33 34 35 36 37 38 39 40
}; S t r i n g name = A t t r i b u t e C h a n g e N o t i f i c a t i o n . c l a s s . getName ( ) ; S t r i n g d e s c r i p t i o n = An a t t r i b u t e o f t h i s MBean has changed ; MBeanNotificationInfo info = new M B e a n N o t i f i c a t i o n I n f o ( t y p e s , name , d e s c r i p t i o n ) ; return new M B e a n N o t i f i c a t i o n I n f o [ ] { i n f o } ; } }
import import import import import import import import import import import import import import import
j a v a . i o . IOException ; javax . s e r v l e t . ServletException ; javax . s e r v l e t . http . HttpServlet ; javax . s e r v l e t . http . HttpServletRequest ; javax . s e r v l e t . http . HttpServletResponse ; javax . s e r v l e t . ServletOutputStream ; javax . s e r v l e t . ServletConfig ; j a v a x . s e r v l e t . a n n o t a t i o n . WebServlet ; j a v a x . s e r v l e t . a n n o t a t i o n . WebInitParam ; j a v a x . management . ObjectName ; j a v a x . management . A t t r i b u t e ; j a v a x . management . MBeanServerConnection ; j a v a x . management . remote . JMXServiceURL ; j a v a x . management . remote . JMXConnector ; j a v a x . management . remote . JMXConnectorFactory ;
@WebServlet ( u r l P a t t e r n s = / a p p d e p o z i t , initParams = { @WebInitParam ( name = j m x S e r v e r H o s t , v a l u e = l o c a l h o s t ) } ) public c l a s s D e p o z i t S e r v l e t extends H t t p S e r v l e t { MBeanServerConnection c s=n u l l ; ObjectName mbeanObjectName=n u l l ; String host ; S t r i n g p o r t= 1099 ; S t r i n g s e r v e r= s e r v e r ; public void i n i t ( S e r v l e t C o n f i g c o n f i g ) { try { super . i n i t ( c o n f i g ) ; h o s t=c o n f i g . g e t I n i t P a r a m e t e r ( j m x S e r v e r H o s t ) ; S t r i n g s u r l= s e r v i c e : jmx : rmi : / / / j n d i / rmi : / / +h o s t+ : +p o r t+ / +s e r v e r ; // S t r i n g s u r l = s e r v i c e : jmx : i i o p : / / / j n d i / i i o p ://+ h o s t +:+ p o r t +/+ s e r v e r ; JMXServiceURL u r l = new JMXServiceURL ( s u r l ) ; JMXConnector jmxc = JMXConnectorFactory . c o n n e c t ( u r l , n u l l ) ; c s = jmxc . getMBeanServerConnection ( ) ; S t r i n g domain = c s . g e t D e f a u l t D o m a i n ( ) ; S t r i n g className= Cont ; S t r i n g sObjectName=domain+ : t y p e=+className ; mbeanObjectName = new ObjectName ( sObjectName ) ; c s . createMBean ( className , mbeanObjectName , null , n u l l ) ; } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ; System . e x i t ( 0 ) ; } }
306
public void doGet ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { S e r v l e t O u t p u t S t r e a m out=r e s . getOutputStream ( ) ; S t r i n g o p e r=r e q . g e t P a r a m e t e r ( o p e r ) ; S t r i n g message= ; double suma=0; i f ( ! o p e r . e q u a l s ( con ) ) { S t r i n g s=r e q . g e t P a r a m e t e r ( suma ) ; suma=Double . p a r s e D o u b l e ( s ) ; } Double o b j V a l u e=n u l l ; try { o b j V a l u e =(Double ) c s . g e t A t t r i b u t e ( mbeanObjectName , Cont ) ; } catch ( E x c e p t i o n e ) { message=JMX E r r o r : +e . g e t M e s s a g e ( ) ; } double v a l u e=o b j V a l u e . d o u b l e V a l u e ( ) ; double x ; A t t r i b u t e c u r s=n u l l ; switch ( o p e r ) { case dep : x=v a l u e+suma ; c u r s=new A t t r i b u t e ( Cont , x ) ; try { c s . s e t A t t r i b u t e ( mbeanObjectName , c u r s ) ; message=Sa depus suma ; } catch ( E x c e p t i o n e ) { message=JMX E r r o r : +e . g e t M e s s a g e ( ) ; } break ; case e x t : i f ( v a l u e >=suma ) { x=v a l u e suma ; c u r s=new A t t r i b u t e ( Cont , x ) ; try { c s . s e t A t t r i b u t e ( mbeanObjectName , c u r s ) ; message=Sa e x t r a s suma ; } catch ( E x c e p t i o n e ) { message=JMX E r r o r : +e . g e t M e s s a g e ( ) ; } } else { message= C e r e r e a nu p o a t e f i i n d e p l i n i t a ; } break ; case con : message=Suma d i n c o n t e s t e +v a l u e+ u n i t . ; break ; } r e s . setContentType ( t e x t / html ) ; out . p r i n t l n ( <html> ) ; out . p r i n t l n ( <head>< t i t l e >Depozit </ t i t l e ></head> ) ; out . p r i n t l n ( <body> ) ; out . p r i n t l n ( <h1>O p e r a t i u n i Cont </h1> ) ; out . p r i n t l n ( <p> ) ;
307
108 109 110 111 112 114 115 116 117 118
<html> <head> < t i t l e > S e r v l e t u l H e l l o </ t i t l e > </ head> <body bgcolor=#a a e e a a > <center> <h1> Pagina de î n t r e ţ i n e r e a d e p o z i t u l u i </ h1> <form method= p o s t action= h t t p : / / l o c a l h o s t : 8 0 8 0 / appcont / a p p d e p o z i t > <p> I n t r o d u c e ţ i : <p>Operaţ i a : < s e l e c t name= o p e r > <option value= dep >Depunere <option value= e x t > E x t r a g e r e <option value= con > C o n s u l t a r e </ s e l e c t> <p> <input type= t e x t name=suma value= 0 > <p> <input type= submit value= Executa > </ form> </ center> </ body> </ html>
import import import import import import import import import import import import import
j a v a x . management . ObjectName ; j a v a x . management . MBeanInfo ; j a v a x . management . M B e a n A t t r i b u t e I n f o ; j a v a x . management . MBeanConstructorInfo ; j a v a x . management . MBeanOperationInfo ; j a v a x . management . M B e a n N o t i f i c a t i o n I n f o ; j a v a x . management . MBeanServerConnection ; j a v a x . management . N o t i f i c a t i o n ; j a v a x . management . N o t i f i c a t i o n L i s t e n e r ; j a v a x . management . A t t r i b u t e C h a n g e N o t i f i c a t i o n ; j a v a x . management . remote . JMXServiceURL ; j a v a x . management . remote . JMXConnector ; j a v a x . management . remote . JMXConnectorFactory ;
308
20 21 22 23 24 25 26 27 28 29 30 31 32 33 35 36 37 38 39 40 42 43 45 46 47 48 49 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 68 69 71 72 73 74 75 76 77 78
System . out . p r i n t l n ( The S e r v e r name i s r e q u i r e d ) ; System . e x i t ( 0 ) ; } i f ( a r g s . l e n g t h >=2) h o s t=a r g s [ 1 ] ; i f ( a r g s . l e n g t h >=3) p o r t=a r g s [ 2 ] ; C l i e n t N o t i f o b j=new C l i e n t N o t i f ( ) ; try { // Crearea unui c o n e c t o r s i a o b i e c t u l u i de // t i p MBeanServerConnection S t r i n g s u r l= s e r v i c e : jmx : rmi : / / / j n d i / rmi : / / + h o s t+ : +p o r t+ / +a r g s [ 0 ] ; JMXServiceURL u r l = new JMXServiceURL ( s u r l ) ; JMXConnector jmxc = JMXConnectorFactory . c o n n e c t ( u r l , n u l l ) ; MBeanServerConnection c s = jmxc . getMBeanServerConnection ( ) ; S t r i n g domain = c s . ge t D e f a u l t D o m a i n ( ) ; System . out . p r i n t l n ( DefaultDomain : +domain ) ; // Crearea o b i e c t u l u i OBjectName a t a s a t MBean u l u i Cont S t r i n g className= Cont ; S t r i n g sObjectName=domain+ : t y p e=+className ; ObjectName mbeanObjectName = new ObjectName ( sObjectName ) ; MBeanInfo i n f o=c s . getMBeanInfo ( mbeanObjectName ) ; getMBeanResources ( i n f o ) ; // U t i l i z a r e a n o t i f i c a r i i // Crearea unui a s c u l t a t o r C l i e n t L i s t e n e r l i s t e n e r = new C l i e n t L i s t e n e r ( ) ; // A c t i v a r e a n o t i f i c a t o r u l u i c s . a d d N o t i f i c a t i o n L i s t e n e r ( mbeanObjectName , l i s t e n e r , null , o b j ) ; Thread . s l e e p ( 5 0 0 ) ; // D i s p o n i b i l i z a r e a a s c u l t a t o r u l u i de n o t i f i c a r i System . out . p r i n t l n ( P r e s s Enter t o f i n i s h ! ) ; try { System . i n . r e a d ( ) ; } catch ( j a v a . i o . IOException e ) { } c s . r e m o v e N o t i f i c a t i o n L i s t e n e r ( mbeanObjectName , l i s t e n e r ) ; // D i s p o n i b i l i z a r e a o b i e c t u l u i MBeanObjectName c s . u n r e g i s t e r M B e a n ( mbeanObjectName ) ; } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ; e . printStackTrace ( ) ; } } private s t a t i c void getMBeanResources ( MBeanInfo i n f o ) { . . . } } c l a s s C l i e n t L i s t e n e r implements N o t i f i c a t i o n L i s t e n e r { public void h a n d l e N o t i f i c a t i o n ( N o t i f i c a t i o n n o t i f i c a t i o n , O b j e c t handback ) { System . out . p r i n t l n ( \ n R e c e i v e d n o t i f i c a t i o n : + n o t i f i c a t i o n ) ; A t t r i b u t e C h a n g e N o t i f i c a t i o n myNotif= ( AttributeChangeNotification ) n o t i f i c a t i o n ; System . out . p r i n t l n ( S o l d i n i t i a l : + myNotif . g et O l d V a l u e ( ) . t o S t r i n g ( ) ) ;
309
79 80 81 82
Serverul MBean este cel prezentat n Exemplul 13.1.5. Serverul MBean este plasat n servlet ( n catalogul WEB-INF/classes al aplicat iei) iar clientul care urm are ste de la distant a se poate aa oriunde. Dup a instalarea servlet-ului se lanseaz a pe ma sina acestuia server-ul MBean. Deoarece noticarea presupune existent a MBean-ului, iar acesta se instant eaz a prin metoda init a servlet-ului este nevoie de apelarea servlet-ului, depun and 0 unit a ti. Dup a aceast a operat ie se lanseaz a n execut ie programul ClientNotif.
310
311
A.1
XML
EXtensible Markup Language (XML) reprezint a un limbaj pentru denirea marcajelor de semantic a, care mpart un document n p art i identicabile n document. Din 1998, XML este un standard World Wide Web Consortium (W3C). Totodat a XML este un meta-limbaj pentru denirea sintaxei de utilizat n alte domenii. XML descrie structura si semantica si nu formatarea. Structura unui document XML este <?xml version="1.0" encoding="tip_codare" [standalone="yes"]?> corpul documentului alcatuit din elemente Prima linie - preambulul - reprezint a declarat ia de document XML. Tipul cod arii poate utf-8, iso-8859-1. Corpul documentului este alc atuit din elemente. Inceputul unui element este indicat printr-un marcaj. Textul marcajului constituie denumirea elementului. Elementele pot cu corp, alc atuit din alte elemente, av and sintaxa <marcaj> corpul elementului </marcaj> 313
Un marcaj poate avea atribute date prin sintaxa numeAtribut="valoareAtribut" Valoarea unui atribut este cuprins a ntre ghilimele (). <marcaj numeAtribut="valoareAtribut" . . .> corpul elementului </marcaj> Exist a un singur element r ad acin a. Elementele unui document XML formeaz a un arbore. Fiec arui marcaj de nceput al unui element trebuie s a-i corespund a un marcaj de sf ar sit. Caracterele mari si mici din denumirea unui element sunt distincte (case sensitive ). Elementele ncuib arite (nested )- incluse ntr-un alt element - nu se pot amesteca, adic a un marcaj de sf ar sit corespunde ultimului marcaj de nceput. Un comentariu se indic a prin <!-Text comentariu --> Exemplul A.1.1 Fi sier XML - denumirile elementelor si cont inutul lor permit nt elegerea simpl a a semanticii introduse n document.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
<? xml version= 1 . 0 e n c o d i n g= u t f 8 ?> < c u r s u r i> < d i s c i p l i n a f e l = o b l i g a t o r i u > <nume> A n a l i z a numerica </nume> <fond detimp> < c u r s> 2 </ c u r s> < s e m i n a r> 1 </ s e m i n a r> < l a b o r a t o r> 1 </ l a b o r a t o r> </ fond detimp> </ d i s c i p l i n a > < d i s c i p l i n a f e l = o b l i g a t o r i u > <nume> Programare d i s t r i b u i t a </nume> <fond detimp> < c u r s> 2 </ c u r s> < s e m i n a r> 0 </ s e m i n a r> < l a b o r a t o r> 2 </ l a b o r a t o r> </ fond detimp> </ d i s c i p l i n a > < d i s c i p l i n a f e l = o b l i g a t o r i u >
A.1. XML
315
20 21 22 23 24 25 26 27
<nume> S o f t matematic </nume> <fond detimp> < c u r s> 2 </ c u r s> < s e m i n a r> 0 </ s e m i n a r> < l a b o r a t o r> 1 </ l a b o r a t o r> </ fond detimp> </ d i s c i p l i n a > </ c u r s u r i >
Un document XML este bine formatat dac a: exist a preambul; ecare element este nchis sau i corespunde un marcaj de inchidere; marcajele ncuib arite nu se amestec a. Un document XML este valid dac a este bine formatat; n cazul c a exist a o referint a c atre XML Schema atunci documentul XML este conform schemei. Un produs informatic accesibil gratuit, care permite vericarea bine format arii si a validit a tii unui document xml, este XML Copy Editor. Pentru validare, dac a sierul XML Schema se a a n alt catalog dec at cel al serului xml atunci acestuia i se asociaz a XML Schema prin XML Associate XML Schema. . . Prelucrarea unui document XML n Java se poate face pe baza interfet elor de programare: Document Object Model - DOM; Simple API for XML - SAX; Stream API for XML - StAX; Java Architecture for XML Binding - JAXB. Amintim faptul c a reprezentarea obiectelor matematice prin elemente XML constituie subiectul a dou a proiecte MathML si OpenMath. Obiectivul limbajului MathML este reprezentarea unui text matematic ntr-un document HTML, n timp ce obiectivul proiectului OpenMath este reprezentarea semantic a a datelor matematice pentru realizarea de aplicat ii cooperante ntre sisteme de calcul simbolic - CAS (Computer Algebra System ).
316
A.2
apache-ant
Utilitarul apache-ant asigur a executarea unui sir de comenzi de operare. Aceste comenzi se nregistreaz a ntr-un sier de tip xml, cu denumirea build.xml. Astfel, apache-ant se substituie unui sier de comenzi bat n Windows sau unui script shell din Linux/Unix. Avantajul obt inut const a n independent a fat a de platforma de calcul (Windows, Linux). Instalarea const a n dezarhivarea sierului desc arcat din Internet. Lansarea n execut ie necesit a xarea variabilei de mediu JAVA HOME, ce cont ine calea la distribut ia Java. Lansarea se poate face prin urm atorul sier de comenzi set JAVA_HOME=. . . set ANT_HOME=. . . %ANT_HOME%\bin\ant.bat %1 Parametrul %1 acestui sier de comenzi reprezint a obiectivul care se dore ste a atins. Dac a se modic a denumirea sau locat ia sierului build.xml atunci sierul de comenzi se invoc a cu opt iunea -buildfile. Un sier build.xml corespunde unui proiect (project), alc atuit din unul sau mai multe obiective (target). Atingerea ecar arui obiectiv const a din ndeplinirea uneia sau mai multor sarcini (task). Apache-ant cont ine o familie predenit a de sarcini. Programatorul are datoria x arii atributelor sarcinilor. Manualul din documentat ia produsului cont ine descrierea atributelor c at si exemple. In general, o sarcin a reprezint a o operat ie executat a uzual n linia de comand a. Atributele se dau, respect and sintaxa XML numeAtribut = valoareAtribut Astfel, un proiect apare sub forma <project name="numeProiect" default="obiectiv" basedir="catalogDeReferinta"> <target name="numeObiectiv"> sarcini </target> . . . . . . . </project>
A.2. APACHE-ANT
317
Dac a la apelarea lui Apache-ant lipse ste parametrul opt ional atunci se va executa obiectivul default. Intr-un proiect se pot deni variabile prin marcajul <property name=numeVariabila value=valoareVariabila /> O variabil a denit a se va utiliza cu sintaxa ${numeVariabila}. Exemplul A.2.1 Fi sierul build pentru execut ia programelor din 1.2.
1 2 4 5 6 8 9 10 11 12 13 14 16 17 18 20 21 22 24 25 26 27
< p r o j e c t name= S o c k e t default= S e r v e r b a s e d i r= . > < d e s c r i p t i o n > S o c l u r i TCP </ d e s c r i p t i o n > < ! s e t g l o b a l p r o p e r t i e s f o r t h i s b u i l d > < p r o p e r t y name= b u i l d l o c a t i o n= work /> < p r o p e r t y name= s r c l o c a t i o n= . /> < t a r g e t name= i n i t > < ! C r e a t e t h e time stamp > <tstamp /> < ! C r e a t e t h e b u i l d d i r e c t o r y s t r u c t u r e used by c o m p i l e > < d e l e t e d i r= $ { b u i l d } /> <mkdir d i r= $ { b u i l d } /> </ t a r g e t> < t a r g e t name= Compile depends= i n i t d e s c r i p t i o n= c o m p i l e t h e s o u r c e > < j a v a c s r c d i r= $ { s r c } d e s t d i r= $ { b u i l d } i n c l u d e a n t r u n t i m e= f a l s e /> </ t a r g e t> < t a r g e t name= S e r v e r depends= Compile > < j a v a c l a s s n a m e=MyMServer c l a s s p a t h= $ { b u i l d } f o r k= t r u e /> </ t a r g e t> < t a r g e t name= C l i e n t > < j a v a c l a s s n a m e= VisualCmmdcClient c l a s s p a t h= $ { b u i l d } f o r k= t r u e /> </ t a r g e t> </ p r o j e c t>
Utilizarea lui apache-ant presupune c a toate resursele utilizate, cuprinse uzual n siere cu extensia jar (j ava ar hive) sunt disponibile pe calculatorul local. Dac a calculatorul este conectat la Internet, atunci resursele publice pot desc arcate mpreun a cu toate dependint ele si utilizate prin apache-ant, folosind suplimentar apache-ivy 1 . In vederea utiliz arii lui apache-ivy se copiaz a sierul ivy-*.jar din distribut ia apache-ivy n ANT HOME\lib. Fi sierul build.xml cont ine n plus
1
318
<project name="Proiect" basedir="." default="obiectiv_final" xmlns:ivy="antlib:org.apache.ivy.ant"> . . . <!-- ================================= target: resolve ================================= --> <target name="resolve" depends="init" description="--> retreive dependencies with ivy"> <ivy:retrieve/> </target> <!-- ================================= target: report ================================= --> <target name="report" depends="resolve" description="--> generates a report of dependencies"> <ivy:report todir="${report.dir}"/> </target> . . . </project> la care se adaug a un sier ivy.xml, cu dependint ele necesare aplicat iei care urmeaz a a preluate dintr-unul din depozitele ivy - local, shared, public
<ivy-module version="2.0"> <info organisation="cs.unitbv.ro" module="Biblioteca-Ivy"/> <dependencies> <dependency org="commons-fileupload" name="commons-fileupload" rev="1.2"/> . . . </dependencies> </ivy-module>
A.3
apache-maven
Apache-maven 2 este un alt cadru de dezvoltare si gestiune a proiectelor (Project management framework). Calculatorul pe care se dezvolt a proiectul / aplicat ia trebuie s a e conectat la internet. Resursele necesare ndeplinitii diferitelor sarcini (maven artifacts ) sunt preluate din internet si depuse ntr un depozit local maven (local repository ). In prezent sunt ntret inute depozite
2
A.3. APACHE-MAVEN
319
publice de resurse soft necesare dezvolt arii de aplicat ii cu maven 3 iar dezvoltatorii de instrumente soft au posibilitatea de a- si promova produsele prin depunerea ntr-un depozit maven. Dintr-un asemenea depozit public resursele necesare sunt desc arcate n depozitul local.
De exemplu repo1.maven.org/maven2.
320
S ablonul se specic a n parametrul -DarchetypeArtifactId al comenzii mvn archetype:create. Indeplinirea diferitelor obiective (generarea unui proiect, compilare, arhivare, testare, etc) se obt in prin comenzi maven. Comenzile maven sunt de dou a tipuri:
Semnicat ia a seaz a versiunea maven (util a pentru vericarea funct ion arii lui maven ) mvn clean sterge sierele maven generate mvn compile compilarea sursele Java mvn test-compile compileaz a sursele Java care realizeaz a testele junit mvn test execut a testul junit mvn package creaz a o arhiv a jar sau war mvn install depune arhiva jar sau war n depozitul local
A.3. APACHE-MAVEN
genereaz a structura de cataloage a proiectului sablonul se alege dintr-o list a clean:clean sterge sierele generate n urma compil arii compiler:compile compilarea sursele Java surefire:test execut a testul junit jar:jar creaz a o arhiv a jar install:install-file depune o arhiv a jar n depozitul local
mvn install:install-file \ -Dfile=numeFi sier \ -DgroupId=numePachet \ -DartifactId=numeProiect \ -Dversion=versiunea \ -Dpackaging=tipArhiv a
mvn exec:java
Astfel comanda
mvn archetype:create -DgroupId=unitbv.cs.calcul -DartifactId=hello -DarchetypeArtifactId=maven-archetype-quickstart
genereaz a arborescent a
hello |--> src | |--> main | | |--> | | | | | | | | | | | | | |--> test | | |--> | | | | | | | | | | | | | pom.xml
322
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
< p r o j e c t xmlns= h t t p : //maven . apache . o r g /POM/ 4 . 0 . 0 x m l n s : x s i= h t t p : //www. w3 . o r g /2001/XMLSchema i n s t a n c e x s i : s c h e m a L o c a t i o n= h t t p : //maven . apache . o r g /POM/ 4 . 0 . 0 h t t p : //maven . apache . o r g /maven v 4 0 0 . xsd > < m o d e l V e r s i o n> 4 . 0 . 0 </ m o d e l V e r s i o n> < g r o u p I d> u n i t b v . c s . c a l c u l </ g r o u p I d> < a r t i f a c t I d > h e l l o </ a r t i f a c t I d > < p a c k a g i n g> j a r </ p a c k a g i n g> <version>1.0 SNAPSHOT </ version> <name> h e l l o </name> < u r l> h t t p : //maven . apache . o r g</ u r l> < d e p e n d e n c i e s> <dependency> < g r o u p I d> j u n i t </ g r o u p I d> < a r t i f a c t I d > j u n i t </ a r t i f a c t I d > <version> 3 . 8 . 1 </ version> < s c o p e> t e s t </ s c o p e> </ dependency> </ d e p e n d e n c i e s> </ p r o j e c t>
App.java este programul Java HelloWorld iar AppTest.java este un program de vericare bazat pe junit. Pentru testarea aplicat iei, din catalogul hello se execut a comenzile
mvn compile mvn test
Sarcina programatorul este acela de a nlocui aceste programe cu cele care rezolv a sarcinile proiectului. Pentru orice prelucrare toate dependint ele trebuie s a se g aseasc a n depozitul local maven. Exemplul A.3.1 Dezvoltarea aplicat iei de calcul al celui mai mare divizor comun a dou a numere naturale utiliz and maven. Gener am proiectul maven
mvn archetype:create -DgroupId=simple.app.cmmdc -DartifactId=cmmdc -DarchetypeArtifactId=maven-archetype-quickstart
package s i m p l e . app . cmmdc ; public c l a s s MyCmmdc{ private long m, n ; MyCmmdc( long m, long n ) { t h i s .m = m; t h i s . n=n ; } public long cmmdc ( ) { . . . } }
si
A.3. APACHE-MAVEN
323
1 2 4 5 6 7 8 9 10 11 12 13 14
package s i m p l e . app . cmmdc ; import j a v a . u t i l . S c a n n e r ; public c l a s s App { public s t a t i c void main ( S t r i n g [ ] a r g s ) { S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ; System . out . p r i n t l n ( m = ) ; long m =s c a n n e r . nextLong ( ) ; System . out . p r i n t l n ( n= ) ; long n=s c a n n e r . nextLong ( ) ; MyCmmdc o b j=new MyCmmdc(m, n ) ; System . out . p r i n t l n ( cmmdc = +o b j . cmmdc ( ) ) ; } }
package s i m p l e . app . cmmdc ; import o r g . j u n i t . ; import s t a t i c o r g . j u n i t . A s s e r t . ; public c l a s s T e s t P r o i e c t { MyCmmdc o b j ; long r e z ; @Before public void setUp ( ) {} @Test public void testCmmdc1 ( ) { o b j=new MyCmmdc( 5 6 , 4 2 ) ; r e z=o b j . cmmdc ( ) ; assertEquals (14 , rez ) ; } @Test public void testCmmdc2 ( ) { o b j=new MyCmmdc( 4 5 , 3 1 ) ; r e z=o b j . cmmdc ( ) ; assertEquals (1 , rez ) ; } public s t a t i c void main ( S t r i n g a r g s [ ] ) { o r g . j u n i t . r u n n e r . JUnitCore . main ( p r o i e c t . T e s t P r o i e c t ) ; } }
Intruc at dorim s a folosim cea mai recent a versiune a produsului junit modic am n sierul pom.xml preciz and versiunea junit c at si versiunea distribut iei jdk utilizat a, care trebuie s a e cel put in 1.5 (restrict ie impus a mai nou de junit ).
1 2 3 4 5
< p r o j e c t xmlns= h t t p : //maven . apache . o r g /POM/ 4 . 0 . 0 x m l n s : x s i= h t t p : //www. w3 . o r g /2001/XMLSchema i n s t a n c e x s i : s c h e m a L o c a t i o n= h t t p : //maven . apache . o r g /POM/ 4 . 0 . 0 h t t p : //maven . apache . o r g /maven v 4 0 0 . xsd > < m o d e l V e r s i o n> 4 . 0 . 0 </ m o d e l V e r s i o n>
324
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
< g r o u p I d> u n i t b v . p r o i e c t . mycmmdc</ g r o u p I d> < a r t i f a c t I d >cmmdc</ a r t i f a c t I d > < p a c k a g i n g> j a r </ p a c k a g i n g> <version>1.0 SNAPSHOT </ version> <name>cmmdc</name> < u r l> h t t p : //maven . apache . o r g</ u r l> < d e p e n d e n c i e s> <dependency> < g r o u p I d> j u n i t </ g r o u p I d> < a r t i f a c t I d > j u n i t </ a r t i f a c t I d > <version> 4 . 1 1</ version> < s c o p e> t e s t </ s c o p e> </ dependency> </ d e p e n d e n c i e s> </ p r o j e c t>
Operarea poate
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 etap a al evolut iei unei aplicat ii. Utilizarea const a n completarea sierului pom.xml cu
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-antrun-plugin</artifactId> <executions> <execution> <phase> <!-- etapa de viata : compile, package, install, test --> </phase> <configuration> <tasks> <!-- Exemplu <property name="compile_classpath" refid="maven.compile.classpath"/> <property name="runtime_classpath" refid="maven.runtime.classpath"/> <property name="test_classpath" refid="maven.test.classpath"/> <property name="plugin_classpath" refid="maven.plugin.classpath"/> <echo message="compile classpath: <echo message="runtime classpath: <echo message="test classpath: <echo message="plugin classpath: --> </tasks> </configuration> <goals> <goal>run</goal> ${compile_classpath}"/> ${runtime_classpath}"/> ${test_classpath}"/> ${plugin_classpath}"/>
A.3. APACHE-MAVEN
325
In elementul <tasks> se denesc sarcinile ant care se doresc executate la comanda corespunz atoare prelucr arii etapei din evolut ia proiectului maven compile, package, install, test, etc. Mai precis, elementele <echo> se nlocuiesc cu sarcinile ant care se doresc efectuate. Propriet a tile se denesc n elementul
<properties> <nume.proprietate>valoare</nume.proprietate> . . . </properties>
Clasa App.java se nlocuie ste cu Catalog Clase i ICmmdc.java s CmmdcImpl.java c CmmdcClient.java Fi sierele pom.xml din s,c se completeaz a cu
<dependency> <groupId>i.cmmdc</groupId> <artifactId>icmmdc</artifactId> <version>1.0.0</version> </dependency>
326
1 2 3 4 5 6 7 8 9 10 11 12 13 14
<? xml version= 1 . 0 e n c o d i n g=UTF8 ?> < p r o j e c t> < m o d e l V e r s i o n> 4 . 0 . 0 </ m o d e l V e r s i o n> < a r t i f a c t I d >cmmdc</ a r t i f a c t I d > < g r o u p I d>cmmdc</ g r o u p I d> <version> 1 . 0 . 0 </ version> <name>RMI</name> < p a c k a g i n g>pom</ p a c k a g i n g> <modules> <module> i </ module> <module> s</ module> <module>c</ module> </ modules> </ p r o j e c t>
3. Din c
set Path=. . .\apache-maven-*\bin;%PATH% set JAVA_HOME=. . . mvn exec:java -Dexec.mainClass="c.cmmdc.CmmdcClient"
A.3. APACHE-MAVEN
327
< p r o j e c t xmlns= h t t p : //maven . apache . o r g /POM/ 4 . 0 . 0 x m l n s : x s i= h t t p : //www. w3 . o r g /2001/XMLSchema i n s t a n c e x s i : s c h e m a L o c a t i o n= h t t p : //maven . apache . o r g /POM/ 4 . 0 . 0 h t t p : //maven . apache . o r g /maven v 4 0 0 . xsd > < m o d e l V e r s i o n> 4 . 0 . 0 </ m o d e l V e r s i o n> < g r o u p I d> h e l l o </ g r o u p I d> < a r t i f a c t I d > h e l l o n a m e</ a r t i f a c t I d > < p a c k a g i n g>war</ p a c k a g i n g> <version>1.0 SNAPSHOT </ version> <name> h e l l o n a m e Maven Webapp</name> < u r l> h t t p : //maven . apache . o r g</ u r l> < d e p e n d e n c i e s> <dependency> < g r o u p I d> j u n i t </ g r o u p I d> < a r t i f a c t I d > j u n i t </ a r t i f a c t I d > <version> 3 . 8 . 1 </ version> < s c o p e> t e s t </ s c o p e> </ dependency> </ d e p e n d e n c i e s> < b u i l d> < f i n a l N a m e> h e l l o n a m e</ f i n a l N a m e> </ b u i l d> </ p r o j e c t>
java |--> hello | | HelloServlet.java resources webapp |--> WEB-INF | | web.xml | index.html
HelloServlet.java este cel utilizat n capitolul Servlet din cursul de Programare distribuit a.
328
< !D O C T Y P E webapp PUBLIC //Sun Microsystems , I n c . / /DTD Web A p p l i c a t i o n 2 . 3 / /EN h t t p : // j a v a . sun . com/ dtd /weba p p 2 3 . dtd > <webapp> < d i s p l a y name> Archetype C r e a t e d Web A p p l i c a t i o n</ d i s p l a y name> < s e r v l e t> < s e r v l e t name> h e l l o </ s e r v l e t name> < s e r v l e t c l a s s > h e l l o . H e l l o S e r v l e t </ s e r v l e t c l a s s > </ s e r v l e t > < s e r v l e t mapping> < s e r v l e t name> h e l l o </ s e r v l e t name> < u r l p a t t e r n>/ h e l l o </ u r l p a t t e r n> </ s e r v l e t mapping> </webapp>
Fi sierul index.jsp se nlocuie ste cu sierul index.html utilizat la 5 servletul ment ionat anterior . Fi sierul pom.xml se completeaz a cu Referint ele la resursele javax.servlet.servlet-api, necesare compil arii.
<dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> <scope>provided</scope> </dependency>
< p r o j e c t xmlns= h t t p : //maven . apache . o r g /POM/ 4 . 0 . 0 x m l n s : x s i= h t t p : //www. w3 . o r g /2001/XMLSchema i n s t a n c e x s i : s c h e m a L o c a t i o n= h t t p : //maven . apache . o r g /POM/ 4 . 0 . 0 h t t p : //maven . apache . o r g /maven v 4 0 0 . xsd > < m o d e l V e r s i o n> 4 . 0 . 0 </ m o d e l V e r s i o n> < g r o u p I d> h e l l o </ g r o u p I d> < a r t i f a c t I d > h e l l o n a m e</ a r t i f a c t I d > < p a c k a g i n g>war</ p a c k a g i n g> <version>1.0 SNAPSHOT </ version> <name> h e l l o n a m e Maven Webapp</name> < u r l> h t t p : //maven . apache . o r g</ u r l> < d e p e n d e n c i e s>
Atent ie la parametri de apelare a servlet-ului, care eventual trebuie adaptat i. Contextul aplicat iei coincide cu parametrul artifactId
A.3. APACHE-MAVEN
329
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
<dependency> < g r o u p I d> j u n i t </ g r o u p I d> < a r t i f a c t I d > j u n i t </ a r t i f a c t I d > <version> 3 . 8 . 1 </ version> < s c o p e> t e s t </ s c o p e> </ dependency> <dependency> < g r o u p I d> j a v a x . s e r v l e t </ g r o u p I d> < a r t i f a c t I d > s e r v l e t a p i</ a r t i f a c t I d > <version> 2 . 5</ version> < s c o p e> p r o v i d e d</ s c o p e> </ dependency> </ d e p e n d e n c i e s> < b u i l d> < f i n a l N a m e> h e l l o n a m e</ f i n a l N a m e> < p l u g i n s> < p l u g i n> < g r o u p I d> o r g . mortbay . j e t t y </ g r o u p I d> < a r t i f a c t I d >maven j e t t y p l u g i n</ a r t i f a c t I d > </ p l u g i n> </ p l u g i n s> </ b u i l d> </ p r o j e c t>
Clauza provided din elementul <scope> implic a ne includerea resursei 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 opre ste cu Ctrl+C. (d) testarea servlet-ului: ntr-un navigator se deschide pagina http://localhost:8080/helloname. Pentru a utiliza serverul Web apache-tomcat este sucient s a 1. desf a sur am arhiva war: mvn tomcat:deploy 2. lans am serverul Web n lucru: mvn tomcat:run Serverul se opre ste cu Ctrl+C.
330
Deoarece maven produce o singur a ie sire se vor realiza dou a proiecte maven : unul pentru componenta Java, care va arhivat a si depus a n depozitul local iar cel alalt pentru aplicat ia JSP. 1. Realizarea componentei Java. (a) Generarea proiectului maven
mvn archetype:create -DgroupId=cmmdc -DartifactId=cmmdcjsp
Se nlocuie ste clasa App.java cu clasa CmmdcBean (curs Programare distribuit a). (b) Prelucrarea const a din i. mvn compile ii. mvn package iii. mvn install 2. Realizarea aplicat iei JSP. (a) Generarea cadrului:
mvn archetype:create -DgroupId=jsp -DartifactId=cmmdcjsp -DarchetypeArtifactId=maven-archetype-webapp
(b) Dezvoltarea aplicat iei: i. Se completeaz a aplicat ia cu sierele cmmdc.jsp si index.html din cursul Programare distribuit a, desf a surarea ind
cmmdcjsp |--> src | |--> main | | |--> | | |--> | | | | | | | | | | | | | pom.xml
A.3. APACHE-MAVEN
331
332
334
static void assertEquals(Tip a steptat, Tip actual ) unde Tip poate double, int, long, Object. static void assertEquals(double a steptat, double actual, double delta ) Testul reu se ste dac a |a steptat-actual | < delta. static void assertArrayEquals(Tip[ ] a steptat, Tip[ ] actual ) unde Tip poate byte, char, int, long, short, Object. static void assertTrue(boolean condit ie ) static void assertFalse(boolean condit ie ) static void assertNull(Object object ) static void assertNotNull(Object object ) In cazul exemplului
1 2 4 5 6 8 9 10 12 13 14 15 17 18 19 20
import o r g . j u n i t . ; import s t a t i c o r g . j u n i t . A s s e r t . ; public c l a s s Exemplu { public double r e z u l t a t = 1 . 0 ; public double e p s=1e 6; double g e t V a l u e ( ) { return 1 . 0 0 0 0 0 0 1 ; } @Test public void t e s t ( ) { a s s e r t E q u a l s ( r e z u l t a t , getValue ( ) , eps ) ; } public s t a t i c void main ( S t r i n g [ ] a r g s ) { o r g . j u n i t . r u n n e r . JUnitCore . main ( Exemplu ) ; } }
se obt ine
JUnit version 4.5 . Time: 0.03 OK (1 test)
335
1 2 3 5 6 8 9 10 11 13 14 15 16
package s e r v e r ; import o r g . j u n i t . ; import s t a t i c o r g . j u n i t . A s s e r t . ; public c l a s s TestApp { private App app ; @Before public void i n i t i a l i z a r e ( ) { app=new App ( ) ; } @Test public void t e s t ( ) { a s s e r t E q u a l s ( 8 , app . cmmdc ( 5 6 , 2 4 ) ) ; }
19 20 21 22
package s e r v e r . impl ; import s e r v e r . ; import o r g . j u n i t . ; import s t a t i c o r g . j u n i t . A s s e r t . ; import j a v a . n e t . S e r v e r S o c k e t ; import i s e r v e r . IMyMServer ; public c l a s s TestMyMServer { private IMyMServer o b j ; @Before public void i n i t i a l i z a r e ( ) { o b j=new MyMServer ( ) ; } @Test public void t e s t ( ) { i n t p o r t =7999; O b j e c t r e s u l t=o b j . g e t S e r v e r S o c k e t ( p o r t ) ; a s s e r t N o t N u l l ( Must not r e t u r n a n u l l r e s p o n s e , r e s u l t ) ; a s s e r t E q u a l s ( ServerSocket . class , r e s u l t . g e t C l a s s ( ) ) ; } public s t a t i c void main ( S t r i n g [ ] a r g s ) { o r g . j u n i t . r u n n e r . JUnitCore . main ( s e r v e r . impl . TestMyMServer ) ; } }
336
Anexa C Jurnalizare
Jurnalizarea adic a a sarea / ret inerea rezultatelor sau evenimentelor ntrun sier. Deseori prezint a interes evolut ia procesului de calcul prin prisma In acest sens se pot utiliza: unor rezultate intermediare. pachetul java.util.logging din jdk. apache-log4j-2. slf4j (Simple Logging Facade for Java), (www.QOS.ch, Quality of Open Software). logback (logback.qos.ch).
import j a v a . u t i l . l o g g i n g . Logger ; public c l a s s Exemplu { s t a t i c Logger l o g g e r = Logger . g e t L o g g e r ( Exemplu . c l a s s . getName ( ) ) ; public s t a t i c void main ( S t r i n g a r g s [ ] ) { l o g g e r . s e v e r e ( SEVERE : H e l l o ) ; l o g g e r . warning ( WARNING : H e l l o ) ; l o g g e r . i n f o ( INFO : H e l l o ) ; } }
Programul a seaz a
Jan 23, 2013 2:34:40 PM Exemplu main SEVERE: SEVERE : Hello Jan 23, 2013 2:34:40 PM Exemplu main
337
338
ANEXA C. JURNALIZARE
WARNING: WARNING : Hello Jan 23, 2013 2:34:40 PM Exemplu main INFO: INFO : Hello
Dac a dorim ca rezultatele s a e nscrise ntr-un sier, de exemplu logging.txt atunci clasa de mai sus se modic a n
1 2 3 4 6 7 9 10 11 12 13 14 15 16 17 18 19 20 21 22
public c l a s s Exemplu { s t a t i c Logger l o g g e r = Logger . g e t L o g g e r ( Exemplu . c l a s s . getName ( ) ) ; public s t a t i c void main ( S t r i n g [ ] a r g s ) { try { F i l e H a n d l e r l o g g i n g F i l e = new F i l e H a n d l e r ( l o g g i n g . t x t ) ; l o g g i n g F i l e . s e t F o r m a t t e r ( new S i m p l e F o r m a t t e r ( ) ) ; l o g g e r . addHandler ( l o g g i n g F i l e ) ; } catch ( IOException e ) { System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ; } l o g g e r . s e v e r e ( SEVERE : H e l l o ) ; l o g g e r . warning ( WARNING : H e l l o ) ; l o g g e r . i n f o ( INFO : H e l l o ) ; } }
package l o g t e s t ; import o r g . s l f 4 j . Logger ; import o r g . s l f 4 j . L o g g e r F a c t o r y ; public c l a s s Exemplu { s t a t i c Logger l o g g e r=L o g g e r F a c t o r y . g e t L o g g e r ( Exemplu ) ; public s t a t i c void main ( S t r i n g a r g s [ ] ) { l o g g e r . t r a c e ( TRACE : H e l l o ) ; l o g g e r . debug ( DEBUG : H e l l o ) ; l o g g e r . i n f o ( INFO : H e l l o ) ; l o g g e r . warn ( WARN : H e l l o ) ; l o g g e r . e r r o r ( ERROR : H e l l o ) ; } }
cu sierul de congurare
1 2 3 4 5 6
< c o n f i g u r a t i o n> < appender name=STDOUT c l a s s= ch . q o s . l o g b a c k . c o r e . ConsoleAppender > < e n c o d e r> < p a t t e r n> %d { HH:mm:ss . SSS } [% t h r e a d ] %5 l e v e l %l o g g e r { 36 } %msg%n </ p a t t e r n>
339
7 8 10 11 12 13 14 15 16 17 19 20 21 22 23 24
</ e n c o d e r> </ appender> < appender name=FILE c l a s s= ch . q o s . l o g b a c k . c o r e . F i l e A p p e n d e r > < f i l e > r e s u l t s . l o g</ f i l e > < e n c o d e r> < p a t t e r n> %d a t e %l e v e l [% t h r e a d ] %l o g g e r { 10 } [% f i l e : %l i n e ] %msg%n </ p a t t e r n> </ e n c o d e r> </ appender> < l o g g e r name= l o g t e s t l e v e l=TRACE /> < r o o t l e v e l= t r a c e > <appender r e f r e f=STDOUT /> <appender r e f r e f=FILE /> </ r o o t> </ c o n f i g u r a t i o n>
import o r g . apache . l o g g i n g . l o g 4 j . LogManager ; import o r g . apache . l o g g i n g . l o g 4 j . Logger ; public c l a s s Exemplu { s t a t i c Logger l o g g e r = LogManager . g e t L o g g e r ( Exemplu . c l a s s ) ; public s t a t i c void main ( S t r i n g a r g s [ ] ) { l o g g e r . warn ( WARN : H e l l o ) ; l o g g e r . debug ( DEBUG : H e l l o ) ; l o g g e r . i n f o ( INFO : H e l l o ) ; l o g g e r . f a t a l ( FATAL : H e l l o ) ; } }
cu sierul de congurare
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
<? xml version= 1 . 0 e n c o d i n g=UTF8 ?> < c o n f i g u r a t i o n s t a t u s=OFF> < p r o p e r t i e s> < p r o p e r t y name= f i l e n a m e > r e s u l t s . l o g</ p r o p e r t y> </ p r o p e r t i e s > < a p p e n d e r s> < C o n s o l e name= C o n s o l e t a r g e t=SYSTEM OUT> <P a t t e r n L a y o u t p a t t e r n=%d { HH:mm:ss . SSS } [% t ] %5 l e v e l %l o g g e r { 36 } %msg%n /> </ C o n s o l e> < F i l e name= F i l e f i l e N a m e= $ { f i l e n a m e } > <P a t t e r n L a y o u t p a t t e r n=%d { HH:mm:ss . SSS } [% t ] %5 l e v e l %l o g g e r { 36 } %msg%n /> </ F i l e > </ a p p e n d e r s> < l o g g e r s> < r o o t l e v e l= t r a c e > <appender r e f r e f= C o n s o l e />
340
<appender r e f r e f= F i l e /> </ r o o t> </ l o g g e r s > </ c o n f i g u r a t i o n>
ANEXA C. JURNALIZARE
19 20 21 22
341
342
E.1
Sintaxa utilizat a este import java.lang.annotation.*; modicator @interface NumeAdnotare { declarare Element 1 343
344 declarare Element 2 . . . } unde declarare Element poate : tip numeElement (); tip numeElement () default valoare ; iar tip poate
ANEXA E. ADNOTARI
predenit (int, short, long, byte, char, float, double, boolean); String Class enum adnotare tablou ale c arei elemente sunt de un tip precizat anterior Adnotarea se salveaz a ca sier text, sub numele NumeAdnotare.java. Dup a num arul elementelor declarate ntr-o adnotare, acesta poate 0 - caz n care adnotarea este de tip marker; 1 sau mai multe elemente (single-element / multi-value annotation ).
E.2
O adnotare se poate referi la un pachet, clas a, interfat a , metod a, c amp. Inaintea declar arii elementului asupra c aruia act ioneaz a, adnotarea se indic a prin @NumeAdnotare(numeElement 1=valoare,numeElement 2=valoare,. . . )
345
E.3
Java declar a adnot arile Adnot ari regulate Override Deprecated SuppressWarnings
Adnotarea Override
Adnotarea Override precizeaz a faptul c a se suprascrie un element al clasei p arinte.
1 2 3 4 5 6 8 9 10 11 12
import j a v a . u t i l . Date ; public c l a s s T e s t O v e r r i d e extends Date { @Override public S t r i n g t o S t r i n g ( ) { return super . t o S t r i n g ()+ T e s t O v e r r i d e ; } public s t a t i c void main ( S t r i n g [ ] a r g s ) { Date d=new T e s t O v e r r i d e ( ) ; System . out . p r i n t l n ( d . t o S t r i n g ( ) ) ; } }
Dac a n locul liniei 9 se pune Date d=new Date(); atunci nu mai apare mesajul TestOverride.
Adnotarea Deprecated
Adnotarea Deprecated are ca efect a sarea unui mesaj de avertisment n momentul compil arii. Exemplic am cu clasele
1 2 3 4 5 6
public c l a s s MyDeprecated { @Deprecated public void doJob ( ) { System . out . p r i n t l n ( This i s d e p r e c a t e d ) ; } } public c l a s s T e s t D e p r e c a t e d { public s t a t i c void main ( S t r i n g [ ] a r g s ) { MyDeprecated o b j=new MyDeprecated ( ) ; o b j . doJob ( ) ; } }
1 2 3 4 5 6
ANEXA E. ADNOTARI
Coment and linia adnot arii are ca efect la o nou a compilare disparit ia mesajelor de avertisment.
Adnotarea SuppressWarnings
Adnotarea SuppressWarnings inhib a a sarea mesajelor de avertisment. Relu am exemplul anterior schimb and clasa Test. In urma compil arii nu mai apar mesajele de avertisment ment ionate mai sus.
1 2 4 5 6 7 8
Adnotarea Target
Adnotarea Target precizeaz a elementul asupra c areia act ioneaz a: ElementType.TYPE ElementType.FIELD ElementType.METHOD ElementType.PARAMETER ElementType.CONSTRUCTOR ElementType.LOCAL VARIABLE ElementType.ANNOTATION TYPE
Adnotarea Retention
Adnotarea Retention precizeaz a momentul act iunii adnot arii: RetentionPolicy.SOURCE RetentionPolicy.CLASS RetentionPolicy.RUNTIME
347
Adnotarea Documented
Adnotarea Documented are ca efect ment ionarea adnot arii n documentul obt inut prin javadoc. Fie clasele
1 3 4
si
1 2 3 4 6 7 8 9 10
public c l a s s TestDocumented { public s t a t i c void main ( S t r i n g [ ] a r g s ) { new TestDocumented ( ) . doDocumented ( ) ; } @MyDocumented public void doDocumented ( ) { System . out . p r i n t l n ( Test Documented ) ; } }
Procesarea unei adnot ari se refer a n primul r and la reg asirea n momentul execut iei a valorilor elementelor adnot arii. In funct ie de valorile reg asite se pot implementa act iuni specice. Procesarea unei adnot ari se bazeaz a pe metodele interfet ei AnnotationElement, implementat a de clasele Class, Constructor, Field, Method, Package: <T extends Annotation> T getAnnotation(Class<T> annotationClass ) Annotation[] getAnnotations() Annotation[] getDeclaredAnnotations() boolean isAnnotationPresent(Class<? notationClass ) Consider am adnotarea
1 2 3 4 6
java . lang . annotation . Retention ; j a v a . l a n g . a n n o t a t i o n . Tar ge t ; java . lang . annotation . RetentionPolicy ; j a v a . l a n g . a n n o t a t i o n . ElementType ;
@Retention ( R e t e n t i o n P o l i c y .RUNTIME)
348
ANEXA E. ADNOTARI
7 8 9 10 11
import j a v a . l a n g . r e f l e c t . Method ; public c l a s s T e s t A n n o t a t i o n { public s t a t i c void main ( S t r i n g [ ] a r g s ) { T e s t A n n o t a t i o n o b j=new T e s t A n n o t a t i o n ( ) ; obj . v e r i f ( obj ) ; } @MyAnnotation ( doAction=XYZ , i n d e x =1) public void v e r i f ( O b j e c t o ) { try { C l a s s c l=o . g e t C l a s s ( ) ; Method m =c l . getMethod ( v e r i f , new C l a s s [ ] { ( new O b j e c t ( ) ) . g e t C l a s s ( ) } ) ; i f (m. i s A n n o t a t i o n P r e s e n t ( MyAnnotation . c l a s s ) ) { MyAnnotation a= m. g e t A n n o t a t i o n ( MyAnnotation . c l a s s ) ; i f ( a != n u l l ) { S t r i n g numeElement=a . doAction ( ) ; System . out . p r i n t l n ( numeElement ) ; i n t i n d e x=a . i n d e x ( ) ; System . out . p r i n t l n ( i n d e x ) ; } } } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( MyEx : +e . g e t M e s s a g e ( ) ) ; } } }
Clasa java.lang.Class furnizeaz a o reprezentare (reectare) a unei clase n timpul execut iei. Metoda public Method getMethod(String name, Class<?>... parameterTypes ) throws NoSuchMethodException, SecurityException furnizeaz a o reprezentare (reectare) a unei metode n timpul execut iei unui program.
F.1
Derby / Javadb
Instalarea produsului const a n dezarhivarea sierului desc arcat. Utilizarea produsului. Va utilizat a varianta de ret ea bazat a pe un server al SGBD care utilizeaz a implicit portul 1527. Se ntreprind urm atoarele operat ii: 1. Lansarea serverului Derby / Javadb:
set JAVA_HOME=. . . set DB_HOME=. . . set PATH=%DB_HOME%\bin;%PATH% startNetworkServer.bat -h 0.0.0.0
Prezent a opt iunii -h 0.0.0.0 asigur a accesul la serverul SGBD de pe orice calculator. 2. Crearea bazei de date se va face utiliz and utilitarul ij din distribut ia Derby / Javadb. Acesta se lanseaz a prin:
set JAVA_HOME=. . . set DB_HOME=. . . set PATH=%DB_HOME%\bin;%PATH% ij.bat
349
Baza de date AgendaEMail se creaz a execut and run CreateAgendaE.sql; unde sierul CreateAgendaE.sql este
1 2 3 4 5 6 7
connect j d b c : derby : AgendaEMail ; c r e a t e=t r u e ; create table a d r e s e ( i d i n t g e n e r a t e d a l w a y s as i d en t i ty ( s t a r t with 1 , i n c r e m e n t by 1 ) primary key , nume char ( 2 0 ) not null , e m a i l char ( 3 0 ) not n u l l );
i n s e r t into a d r e s e ( nume , e m a i l ) values ( aaa , aaa@yahoo . com ) , ( bbb , bbb@gmail . com ) , ( c c c , cc c@un itb v . r o ) , ( aaa , xyz@unitbv . r o ) ;
F.2
mysql
Instalarea produsului. Pentru instalare s-a desc arcat varianta f ar a instalare automat a mysqll-*.*.*-win*.zip. Acest sier se dezarhiveaz a ntr-un catalog MYSQL HOME. Implicit, serverul mysql utilizeaz a portul 3306, iar sierele bazelor de date vor g azduite n catalogul MYSQL HOME\data. Pentru utilizarea n aplicat ii Java trebuie desc arcat un conector mysqlconnector-java-*.*.*.tar.gz, cont in and sierul mysql-connector-java*.*.*-bin.jar. Utilizarea produsului. Se ntreprind urm atoarele operat ii: 1. Lansarea serverului mysql :
set MYSQL_HOME=. . . set PATH=%MYSQL_HOME%\bin;%PATH% mysqld
F.2. MYSQL
351
2. Accesul de pe orice calculator c atre utilizatorul root din mysql se asigur a prin
grant all on *.* to root@%;
3. Unui utilizator i se poate atasa o parol a, execut and ntr-o sesiune mysql comenzile
set password for root@localhost=password(parola); set password for root@127.0.01=password(parola);
Daca utilizatorul are o parola atunci la apelarea utilitarului mysql va prezent a si opt iunea -p. 4. Exemplul F.2.1 Crearea bazei de date AgendaEMail se va face prin intermediul sierului de 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
create d a t a b a s e AgendaEMail ; u s e AgendaEMail ; create table a d r e s e ( i d i n t primary key a u t o i n c r e m e n t not null , nume char ( 2 0 ) not null , e m a i l char ( 3 0 ) not n u l l );
u s e AgendaEMail ; i n s e r t a d r e s e values ( 1 , aaa , aaa@yahoo . com ) ; i n s e r t a d r e s e values ( 2 , bbb , bbb@gmail . com ) ; i n s e r t a d r e s e values ( 3 , c c c , ccc @uni tbv . r o ) ; i n s e r t a d r e s e values ( 1 , aaa , xyz@unitbv . r o ) ;
352
F.3
Interact iunea cu baze de date relat ionale implic a: 1. Stabilirea corespondent ei dintre date aate n obiecte si atribute / tabele (object to relational database mapping ). 2. Apelarea act iunilor CRUD (Create, Read, Update, Delete ). Limbajul SQL (Structured Query Language ) este dependent de SGBD utilizat. Dezvoltarea interact iunii dintre un program Java (client) cu o baz a de date dintr-un SGBD s-a n ascut din dorint a de a asigura independent a stratului Java de SGBD. Solut ia g asit a const a n introducerea unui strat suplimentar, ntre Java si SGBD care asigur a corespondent a ntre obiectele Java cu tabelele unei baze de date si permite o congurare simpl a la schimbarea SGBD. Astfel se folose ste terminologia de aplicat ie multistrat. Materializarea acestor idei (Object Relational Mapping - ORM) se a a n interfat a de programare (API) Java Persistence API (JPA); Exist a mai multe implement ari JPA. interfat a de programare (API) Java Data Object (JDO); produsul Hibernate. Hibernate cont ine si o implementare JPA. apache-empire ebean Scopul urm arit este realizarea trecerii de la un SGBD la altul prin modic ari minime n stratul intermediar. In cele ce urmeaz a vom face abstract ie de modelele ment ionate anterior si vom trata n modul cel mai simplu realizarea unei aplicat ii care interact ioneaz a cu o baz a de date gestionat a de un SGBD. Pentru a avea acces la o baz a de date trebuie stabilit a o conexiune la acea baz a de date. In acest sens este necesar cunoa sterea:
353
driver-ului de acces la sistemul de gestiune a bazei de date (SGBD) Tip SGBD access mysql derby javadb postgresql hypeqsql oraclexe Driver sun.jdbc.odbc.JdbcOdbcDriver com.mysql.jdbc.Driver org.apache.derby.jdbc.ClientDriver org.postgresql.Driver org.hsqldb.jdbcDriver oracle.jdbc.driver.OracleDriver Fi sierul driver-ului mysql-connector-java-*.*.*-bin.jar (www.mysql.com) derbyclient.jar (distribut ia derby) postgresql-*.*-*.jdbc4.jar hsqldb.jar ojdbc14.jar
Dac a ntr-un servlet se realizeaz a o conexiune la o baz a de date atunci sierul driver-ului trebuie copiat n catalogul lib al aplicat iei. adresa URI a bazei de date (String URIBazaDate ), sub forma Tip SGBD Referint a Baza de Date mysql jdbc:mysql://host:3306/numeBazaDate derby / javadb jdbc:derby://host:1527/numeBazaDate postgresql jdbc:postgresql://host:5432/numeBazaDate hypersql jdbc:hsqldb:hsql://host/numeBazaDate oracle jdbc:oracle:thin:@host:1521:XE S ablonul 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 asigur a accesul la o baz a de date dac a sunt xat i parametrii username si password. In acest caz se programeaz a con=DriverManager.getConnection(URLBazaDate,username,password); Odat a conexiunea cu baza de date stabilit a se genereaz a un obiect de tip Statement prin intermediul c aruia se execut a interogarea SQL.
354
Statement instructiune=con.createStatement(); String sql=. . . //fraza select; Rezultatele interog arii bazei de date se obt ine prin try{ ResultSet rs=instructiune.executeQuery(sql); while(rs.next()){ prelucrarea rezultatului } } catch(SQLException e){...} Exemplul F.3.1 O interogare simpl a a bazei de date AgendaEMail se realizeaz a cu programul
1 2 3 4 5 6 8 9 10 11 12 14 15 16 17 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
public c l a s s AgendaE { private s t a t i c S t r i n g jdbcURIDerby = j d b c : derby : / / l o c a l h o s t : 1 5 2 7 / AgendaEMail ; private s t a t i c S t r i n g j d b c D r i v e r D e r b y = o r g . apache . derby . j d b c . C l i e n t D r i v e r ; private s t a t i c S t r i n g jdbcURIMysql = j d b c : mysql : / / l o c a l h o s t : 3 3 0 6 / AgendaEMail ? u s e r=r o o t ; private s t a t i c S t r i n g j d b c D r i v e r M y s q l = com . mysql . j d b c . D r i v e r ; public s t a t i c void main ( S t r i n g [ ] a r g s ) { S t r i n g dbms=null , username=null , password=null , jdbcURL=n u l l ; switch ( a r g s . l e n g t h ) { case 0 : System . out . p r i n t l n ( At l e a s t one argument r e q u i r e d ) ; System . out . p r i n t l n ( DBMS username password ) ; System . out . p r i n t l n ( DBMS derby , mysql ) ; System . e x i t ( 0 ) ; break ; case 1 : dbms=a r g s [ 0 ] ; break ; case 2 : dbms=a r g s [ 0 ] ; username=a r g s [ 1 ] ; password= ; break ; default :
355
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 62 63 64 65 66 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
dbms=a r g s [ 0 ] ; username=a r g s [ 1 ] ; password=a r g s [ 2 ] ; } C o n n e c t i o n conn = n u l l ; try { switch ( dbms ) { case derby : C l a s s . forName ( j d b c D r i v e r D e r b y ) . n e w I n s t a n c e ( ) ; jdbcURL=jdbcURIDerby ; break ; case mysql : C l a s s . forName ( j d b c D r i v e r M y s q l ) . n e w I n s t a n c e ( ) ; jdbcURL=jdbcURIMysql ; break ; default : System . out . p r i n t l n ( Unknown DBMS . . . ) ; System . e x i t ( 0 ) ; } System . out . p r i n t l n ( jdbcURI=+jdbcURI ) ; i f ( password==n u l l ) conn = DriverManager . g e t C o n n e c t i o n ( jdbcURI ) ; else conn=DriverManager . g e t C o n n e c t i o n ( jdbcURI , username , password ) ; Statement i n s t r u c t i u n e=conn . c r e a t e S t a t e m e n t ( ) ; S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ; i n t p r e l , no ; S t r i n g ch=Y , nume= , e m a i l= , s q l= ; R e s u l t S e t r s=n u l l ; while ( ch . s t a r t s W i t h ( Y ) ) { do { System . out . p r i n t l n ( Continue ? (Y/N) ) ; ch=s c a n n e r . n e x t ( ) . toUpperCase ( ) ; } while ( ( ! ch . s t a r t s W i t h ( Y ))&&(! ch . s t a r t s W i t h ( N ) ) ) ; i f ( ch . s t a r t s W i t h ( Y ) ) { System . out . p r i n t l n ( Natura i n t e r o g a r i i ? ) ; System . out . p r i n t l n ( ( Dupa nume : 1 , Dupa e m a i l : 2 ) ) ; do { p r e l =0; try { p r e l=s c a n n e r . n e x t I n t ( ) ; } catch ( InputMismatchException e ) { } } while ( ( p r e l <1)&&( p r e l > 2 ) ) ; switch ( p r e l ) { case 1 : System . out . p r i n t l n ( Numele ) ; nume= \ +s c a n n e r . n e x t ( ) . t r i m ()+ \ ; s q l= s e l e c t from a d r e s e where nume=+nume ; r s=i n s t r u c t i u n e . e x e c u t e Q u e r y ( s q l ) ; break ; case 2 : System . out . p r i n t l n ( Email ) ; e m a i l= \ +s c a n n e r . n e x t ( ) . t r i m ()+ \ ; s q l= s e l e c t from a d r e s e where e m a i l=+e m a i l ;
356
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
r s=i n s t r u c t i u n e . e x e c u t e Q u e r y ( s q l ) ; break ; default : System . out . p r i n t l n ( Comanda e r o n a t a ) ; } i f ( r s != n u l l ) { System . out . p r i n t l n ( R e s u l t s : ) ; while ( r s . n e x t ( ) ) { System . out . p r i n t l n ( i d= + r s . g e t I n t ( i d ) ) ; System . out . p r i n t l n ( nume= + r s . g e t S t r i n g ( nume ) ) ; System . out . p r i n t l n ( e m a i l= + r s . g e t S t r i n g ( e m a i l ) ) ; System . out . p r i n t l n ( ) ; } } else { System . out . p r i n t l n ( No item found ! ) ; } } } } catch ( E x c e p t i o n e ) { // h a n d l e t h e e x c e p t i o n e . printStackTrace ( ) ; } } }
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 f ar a apostroafe. Compilarea si execut ia programului necesit a declararea n variabila classpath a sierelor Varianta Derby derbyclient.jar din catalogul %DERBY INSTALL%\lib. Varianta mysql %MYSQL CONNECTOR JAVA HOME%\mysql-connector-java-*.*.*-bin.jar Execut ia programului presupune serverul SGBD activ.
357
1. S a se realizeze conversia temperaturii exprimat a n grade Celsius n grade Fahrenheit si invers. Formula de transformare este tF = 1.8tC + 32o F In RMI, programul server implementeaz a interfat a (la distant a )
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. S a se realizeze conversia a unei sume de bani ntre USD, EURO si RON. Programul server (RMI) implementeaz a interfat a
package exchange; public interface IConversie extends java.rmi.Remote{ public double usdToEuro(double usd) throws java.rmi.RemoteException; public double usdToRol(double usd) throws java.rmi.RemoteException; public double euroToUsd(double euro) throws java.rmi.RemoteException; public double euroToRol(double euro) throws java.rmi.RemoteException; public double rolToEuro(double rol)
359
360
Rata zilnic a de schimb preia dinamic sub forma unui sier xml, apel and http://www.bnr.ro/nbrfxrates.xml. 3. S a se realizeze conversia unui num ar natural, din cifre arabe n cifre romane si invers. Pentru numere x (3999, 3999999], x = a 1000 + b se va folosi scrierea sub forma (A)B, unde A, B reprezint a conversiile lui a, respectiv b. Exemplu: Conversia num arului 2289463 este (MMCCLXXXIX)CDLXIII. Pentru numere x (4000000, 3999999999], x = a 1000000+ b 1000+ c se va folosi scrierea sub forma [A](B )C, unde A, B, C reprezint a conversiile lui a, b, c. 4. S a se realizeze conversia unui num ar dintr-o baz a n alta. 5. Un server adun a la un num ar (init ializat cu 0) o valoare trimis a de un client return and rezultatul. Exist a o singur a instant a a num arului, acela si pentru orice client. S a se programeze serviciul descris mai sus. 6. Aplicat ia produc ator consumator. Fie un sistem format din dou a procese P1 si P2 , primul produc and ni ste date care apoi vor preluate de cel de al doilea. Comunicarea ntre cele dou a procese se realizeaz a prin intermediul unei zone de memorie tampon, de o anumit a dimensiune, n care procesul P1 introduce informat ii (sub forma unor nregistr ari), pe care apoi P2 le extrage. Procesul P2 nu este nevoit s a a stepte pentru ecare nregistrare n parte, iar P1 nu a stept a p an a ce P2 este gata s a recept ioneze nregistrarea produs a. Procesele evolueaz a independent unul de cel alat, P1 introduc and n tampon nregistrarea produs a, de unde P2 o va extrage la nevoie. Se impun urm atoarele restrict ii: Procesul P1 ncearc a s a introduc a o nregistrare n tampon si constat a c a acesta s-a umplut. In acest caz, el va trebui s a a stepte p an a ce se ive ste un loc n tampon (ceea ce se va nt ampla ca urmare a extrageri unei nregistr ari de c atre P2 ).
361
Procesul P2 ncearc a s a extrag a o nregistrare si constat a c a tam ponul este gol. In acest caz el va trebui s a a stepte p an a ce apare o nregistrare ca urmare a introduceri unei nregistr ari n tampon de c atre P1 . Se dene ste interfat a 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 interfet ei IBoundedBuer. (b) Realizarea a dou a programe client Producator, care introduce obiecte n tampon si Consumator pentru extragerea lor. 7. Aplicat ie de e-mail. Un e-mail este denit 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; } }
362
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 instant a a clasei User.
package email; import java.util.*; import iemail.*; public class User implements java.io.Serializable{ String name, password; Vector emails = new Vector(); public User(String name, String password) { this.name = name; this.password = password; } public void addEmail(Email email) { emails.addElement(email); } }
Pentru a putea folosi serverul de e-mail, un client trebuie n prealabil s a se nregistreze (createUser). Un client nregistrat se poate conecta la serverul de e-mail (login) dup a care poate scrie (trimite) sau citi (recept iona) mesaje. Se cere ca la ad agarea unui mesaj (deci naintea apel arii metodei User.addEmail) s a se verice dac a emitentul este conectat si dac a destinatarul este nregistrat. n caz contrar se genereaz a except ia UnknownUserException
package iemail; public class UnknownUserException extends Exception { public UnknownUserException() { super(); }
363
Citirea mesajelor este l asat a la latitudinea client ilor n sensul c a clientul implementeaz a metoda printEmail al interfet ei ICallbackEmail.
package iemail; import java.rmi.*; import java.rmi.server.*; public interface ICallbackEmail extends Remote { public void printEmail(Email email) throws RemoteException; }
Solicitarea recept ion arii mesajelor se realizeaz a de c atre server prin apelarea metodei printEmail pentru ecare mesaj primit de client. Se cere: (a) Implementarea interfet ei IEmailServer. (b) Realizarea a dou a programe client AddClient pentru nregistrarea utilizatorilor si ClientEmail pentru exploatarea serviciului de email. Fiecare din cele dou a programe are ca parametri numele (identicatorul) clientului, parola si referint a serverului. 8. Integrare numeric a. Scopul aplicat iei este calculul unei integrale de un program server cu funct ia de integrat det inut a de c atre client. In cazul aplicat iei RMI, evalu arile funct iei cerute de formula de integrare numeric a se vor realiza prin apel invers. Integrarea numeric a va executat de un server disponibil client ilor prin mecanismul de fabric a de obiecte. Interfat a fabricii de obiecte este
package integ; import java.rmi.*; public interface IFabIntegrator extends Remote{ IIntegrator getIntegrator() throws RemoteException; }
364
declar a o metod a ce calculeaz a un sir (Imk )k p an a n momentul |Imk Imk1 | < . Propunem utilizarea formulei lui Simpson
b a m1 m1
ba f (x)dx Im = [f (a) + 2 6m
f (a2i ) + 4
i=1 i=0
f (a2i+1 ) + f (b)]
a . unde ai = a + i b2 m
S irul (mk )k este denit prin mk = 2k m0 . Semnicat ia parametrilor metodei adaptiveSimpson este leftEnd rightEnd epsilon initParam Interfat a apelului invers este
package integ; import java.rmi.*; double function(double x)throws RemoteException; }
a b m0
Se cere implementarea aplicat iei cu minimizarea num arului de apel ari a metodei function. 9. Agend a telefonic a. Pentru crearea si ntret inerea unei agende telefonice utiliz and RMI consider am: Un ServerCarteTelefon realizeaz a urm atoarele operat ii: adaug a o nregisrare n agenda telefonic a; O nregistrare este alc atuit a dintr-o pereche (nume, num ar).
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; } }
365
sterge nregistrarea corespunz atoare unui nume din agenda telefonic a. interogarea agendei: furnizeaz a num arul de telefon al unui nume; modicarea num arului de telefon corespunz ator unui nume; a sarea nregistr arilor; salvarea nregistr arilor ntr-un sier; restaurarea nregistr arilor dintr-un sier. Interfat a corespunz atoare 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; }
Se cere implementarea aplicat iei de creare si ntret inere a agendei telefonice. Se extinde aplicat ia anterioar a cu funct iunea suplimentar a a serverului de a ret ine toate modic arile efectuate de c atre un client si care la solicitare pot a sate. Modic arile se ret in ntr-o variabil a mod de tip Vector. La solicitarea clientului, pentru ecare modicare memorat a, programul server apeleaz a metoda schimbStare declarat a n interfat a
package itelef; import java.rmi.*; public interface IApelInvers extends Remote{ void schimbStare(Entry e) throws RemoteException; }
366
Metoda schimbStare(Entry e) nu face altceva dec at a seaz a c ampurile variabilei e. Interfat a ICarteTelefon declar a n plus metoda void apelInvers(IApelInvers obj)throws RemoteException; Aceast a metod a va implementat a n programul ServerCarteTelefon.java. Elementelor ret inute n vectorul mod li se aplic a metoda schimbStare(). S a se implementeze acest a funct iune utiliz and tehnica apelului invers. Se poate utiliza baza de date AGENDATELEFONICA format a din tabelul TELEF ID NUME NUMAR 10. S a se determine zodia (chinezeasc a) corespunz atoare unei date calen daristice. Obs. Inceputul anului nou chinezesc nu coincide cu nceputul anului nou calendaristic. Se va crea baza de date AN CHINEZESC alc atuit a din tabelul INCEPUT AN LUNA ZI Se va tine seama de perioada de 12 ani de alternant a a zodiilor. format 11. Se consider a baza de date UNITAT I DE MASUR A a din tabelul CONVERSIE UM SI UM SIMBOL DENUMIRE (ROM) VAL Exemplu: 1 2 3 4 M INCH T ol M FEET (FT) Picior KG UK ONCE Uncie (UK) KG UK POUND Livra (UK) 0.0254 0.3048 0.031103 0.373
367
S a se realizeze o aplicat ie pentru conversia unit a tilor de m asur a extinz and cont inutul bazei de date. 12. Se consider a baza de date NORME-DIDACTICE format a din tabelele CADRU-DIDACTIC COD-CADRU-DIDACTIC NUME MATERIA COD-MATERIE DENUMIRE CURSURI COD-CURS COD-CADRU-DIDACTIC COD-MATERIE
S a se elaboreze programe de ntret inere si interogare a bazei de date. 13. Se consider a baza de date APROVIZIONARE format a din tabelele RESURSA FURNIZOR CONTRACT COD-RESURSA COD-FURNIZOR COD-CONTRACT DENUMIRE NUME COD-FURNIZOR COD-RESURSA CANTITATE S a se elaboreze programe de ntret inere si interogare a bazei de date. 14. Se consider a baza de date DESFACERE format a din tabelele PRODUSE BENEFICIAR CONTRACT COD-PRODUS COD-BENEFICIAR COD-CONTRACT DENUMIRE NUME COD-BENEFICIAR COD-PRODUS CANTITATE S a se elaboreze programe de ntret inere si interogare a bazei de date. 15. Validarea codului numeric personal.
Codul Numeric Personal (CNP) constituie num arul de ordine atribuit de Evident a populat iei unei persoane la na stere, de cet a tenie rom an a, care se nscrie n actele si certicatele de stare civil a si se preia n celelate acte cu caracter ocial.
368
S AA LL ZZ JJ ZZZ C | | | | | | |-> cifra de control | | | | | |-> numar de ordine atribuit | | | | |-> codul judetului | | | |-> ziua nasterii | | |-> Luna nasterii | |-> Anul nasterii |-> Cifra sexului (M/F) 1/2 nascuti intre 1 ian 1900 si 31 dec 3/4 nascuti intre 1 ian 1800 si 31 dec 5/6 nascuti intre 1 ian 2000 si 31 dec 7/8 rezidenti
persoanei
Vericarea cifrei de control: Se folose ste cheia de testare 279146358279. Primele 12 cifre ale CNP se nmult esc pe r and de la st anga spre dreapta cu cifra corespunz atoare a cheii de testare. Cele 12 produse se adun a, iar suma se mparte la 11. Dac a restul mp art irii este mai mic dec at 10, atunci acesta va cifra de control. Dac a restul mp art irii este 10 atunci cifra de control este 1. S a se elaboreze un program pentru vericarea CNP. 16. Informat iile unui aeroport civil privind decol arile(plec ari) si ateriz ari(sosiri) pe parcursul unei perioade sunt cuprinse n tabelul activitate al bazei de date aeroport ACTIVITATE ID FEL aterizare/decolare ZI TIMP ora/minut COMPANIE OBSERVATIE de la/spre S a se realizeze o aplicat ie de furnizare a datelor c atre client i (interogarea bazei de date). 17. Se dau n tipuri de monede Mx1 , Mx2 , . . . , Mxn , xi reprezent and valoarea monedei, i = 1, 2, . . . , n. S a se determine variantele de plat a a unei sume S cu un num ar minim de monede din cele disponibile.
369
Se vor trata cazurile: (a) Num arul monedelor de ecare tip este nelimitat. (b) Num arul monedelor disponibile este m arginit, respectiv de numerele k1 , k2 , . . . , kn (k1 x1 + . . . + kn xn S ). 18. Globul p am antesc este mp art it n 24 de fuse orare de c ate 15o (24 15 = 360) pornind de la meridianul 0 spre st anga si dreapta. D andu-se longitudinile a 2 puncte de pe glob s a se calculeze diferent a de fus orar. Fix and ora n primul punct s a se indice ora n al doilea punct. 19. S a se calculeze unghiurile unui triunghi dat prin coordonatele v arfurilor. 20. Fix and coecient ii a, b, c, d, e, f ale conicei ax2 + 2bxy + cy 2 + 2dx + 2ey + f = 0 s a se reduc a conica la forma canonic a. 21. S a se calculeze suma multiplilor de 3 sau 5 mai mici dec at un num ar dat n. 22. Fie polinomul trigonometric par () = 0 + se calculeze polinomul P (x) = (arccos x).
n j =1
j cos j, n 10. S a
23. Se d a polinomul P (x) = a0 + a1 x + . . . + an xn , n 10. S a se determine polinomul trigonometri par () = a0 + a1 cos + . . . + an cosn sub forma () = 0 + n j =1 j cos j. 24. Fie p N xat si n N, 0 n 2p 1 cu reprezentarea binar a n = ap1 ap2 . . . a1 a0 2 . S a se determine num arul m care are reprezentarea binar a m = a0 a1 . . . ap2 ap1 2 . De exemplu, pentru p = 6, n = 17 = 0100012 num arul c autat este m = 1000102 = 34. 25. S a se determine num arul de aparit ii al ec arui cuv ant dintr-un text dat.
370
26. S a se calculeze Bn (Numerele lui Bernoulli) denit prin dac a n=0 1 n1 n + 1 Bn = Bk k=0 k dac a n>0 n+1 Calculele se fac n Q.
Bibliograe
[1] ALBOAIE L., BURAGA S., 2006, Servicii Web. Ed. Polirom, Ia si. [2] ATHANASIU I., COSTINESCU B., DRAGOI O.A., POPOVICI F.I., 1998, Limbajul Java. O perspectiv a pragmatic a. Ed. Computer Libris Agora, Cluj-Napoca. [3] BOIAN F.M., BOIAN R. F., 2004, Tehnologii fundamentale Java pentru aplicat ii Web. Ed. Albastr a, Cluj-Napoca. [4] BOIAN F.M., 2011, Servicii Web; Modele, Platforme, Aplicat ii. Ed. Albastr a, Cluj-Napoca. [5] BURAGA S.C., 2001, Tehnologii Web. Ed. Matrix Rom,Bucure sti. [6] BURAGA S. (ed), 2007, Programarea n Web 2.0., Ed. Polirom, Ia si. [7] COULOURIS G., DOLLIMORE J., KINDBERG T., Distributed Systems. Concepts and Design. Addison Wesley, 2005. I., 2000, Programarea ret [8] JURCA elelor de calculatoare. Ed. de Vest, Timi soara. [9] SCHEIBER E., 2007, Programare concurent a si paralel distribuit a n Java. Ed. Albastr a, Cluj-Napoca. S [10] TANASA ., ANDREI S ., OLARU C., 2011, Java de la 0 la extert. Ed. Polirom, Ia si. S [11] TANASA ., OLARU C., 2005, Dezvoltarea aplicat iilor Web folosind Java. Ed. Polirom, Ia si.
371