DISTR1
DISTR1
ERNEST SCHEIBER
Braov s
Prefat a
Scopul acestui curs este prezentarea tehnologiilor de programare Java care permit programarea aplicatiilor client - server: socluri Java; apelarea metodelor de la distant (Remote Method Invocation - RMI ); a CORBA - Common Object Request Brocker Arhitecture; mesageria Java; servlet; Java Server Pages - JSP; Portlet i Portal; s Accentul cade pe detaliile tehnice de realizare a comunicatiilor i pe arhi s tectura programelor / aplicatiilor care le utilizeaz. Trebuie semnalat faptul a c exemplele date nu incorporeaz aspecte indispensabile unei aplicatii infora a matice la standardele zilei: securitate, autenticare i autorizare; s interfat grac pentru componenta client; a a utilizarea bazelor de date relationale / NoSQL. Metodele i instrumentele de programare vor exemplicate pe problema s foarte simpl de calcul a celui mai mare divizor comun a dou numere naturale. a a Codul metodei de calcul este
1 2 3 4 5
6 7 8 9 10 11
Pentru aplicatiile care utilizeaz o baz de date, sistemul de gestiune a a a bazei de date (SGBD) va una dintre sistemele Derby/Javadb sau mysql. Tiparul de aare poate nvt 1. Se instaleaz toate resursele necesare (Se exemplic la laborator). a a 2. Se execut aplicatia / aplicatiile din curs (Se exemplic la laborator). a a 3. Pentru ecare tehnologie, citind cursul, se programeaz o alt aplicatie. a a Propunem temele: Conversia dintre grade Celsius i grade Fahrenheit (F = 1.8C + 32). s Crearea, ntretinerea i utilizarea unei agende de adrese de e-mail. s Agenda este o baz de date. a 4. nal, se rezolv tema pentru examen. In a Nu de putine ori metodele / tehnologiile utilizate presupun utilizarea unui ablon de programare specic. Din acest punct de vedere, acest curs se dorete s s a un suport metodic.
No. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
Versiunile produselor informatice utilizate lucrare n Produsul informatic Resursa/versiunea apache-activemq apache-activemq-5.5.0-bin.zip apache-ant apache.ant-1.8.1-bin.tar.gz apache-commons-logging commons-logging-1.1.1-bin.tar.gz apache-commons-codec commons-codec-1.5-bin.tar.gz apache-commons-io commons-io-1.4-bin.tar.gz apache-commons-leupload commons-leupload-1.2.2-bin.tar.gz apache-ftpserver ftpserver-1.0.6.tar.gz apache-log4j apache-log4j-1.2.16.tar.gz apache-maven apache-maven-3.0.3-bin.tar.gz apache-mina apache-mina-2.0.4-bin.tar.gz apache-java-qpid qpid-java-0.12.tar.gz apache-tomcat apache-tomcat-7.0.23.tar.gz apacheds apacheds-1.5.7.tar.gz google appengine appengine-java-sdk-1.6.0.zip db-derby db-derby-10.8.1.2-bin.tar.gz Freedom for Media in Java (fmj) fmj-20070928-0938.zip hessian hessian-4.0.7.jar httpcomponents-client httpcomponents-client-4.1.2-bin.tar.gz httpcomponents-asyncclient httpcomponents-asyncclient-4.0-alpha3-bin.tar.gz Java (jdk) jdk-7u1-windows-i586.exe jetspeed jetspeed-installer-2.2.2.jar
6
No. 22 23 24 25 26 27 28 Produsul informatic junit mysql mysql-connector OpenDS openmq pluto uPortal Resursa/versiunea junit4.8.2.zip mysql-5.5.15-win32.zip mysql-connector-java-5.1.16.tar.gz OpenDS-2.3.0.zip openmq4 5-binary-WINNT.zip pluto-2.0.3-bundle.tar.gz uPortal-3.2.4-quick-start.tar.gz.gz
Cuprins
1 Introducere 13
17
19 19 20 22 26 31 35 39 52 57 59
2 Programare cu socluri Java 2.1 TCP vs. UDP . . . . . . . . . . . . . . . . . . . 2.2 Soclu TCP . . . . . . . . . . . . . . . . . . . . . 2.3 Aplicatie client server cu socluri . . . . . . . . 2.4 Datagrame . . . . . . . . . . . . . . . . . . . . . 2.4.1 Aplicatii client server cu datagrame. . 2.4.2 Multicast vs. Broadcast . . . . . . . . . 2.5 Canale de comunicatie . . . . . . . . . . . . . . 2.6 Apache-MINA . . . . . . . . . . . . . . . . . . . 2.6.1 Mesaje componente Java . . . . . . . . . 2.6.2 Serializare folosind un codec personalizat
3 Regsirea obiectelor prin servicii de nume a 63 3.1 Java Naming and Directory Interface . . . . . . . . . . . . . . . 63 3.1.1 LDAP . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67 4 Invocarea procedurilor la distant a 4.1 Remote Method Invocation . . . . 4.1.1 Crearea unei aplicatii RMI . 4.1.2 Tipare de programare . . . . 4.1.3 Obiect activabil la distanta 4.2 CORBA . . . . . . . . . . . . . . . 4.2.1 Conexiunea RMI - CORBA 4.2.2 Aplicatie Java prin CORBA 7 73 73 77 83 88 93 94 99
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
8 5 Mesaje Java n 5.1 Java Message Service (JMS) . . . . . . . . . . . . . . . 5.2 Open Message Queue . . . . . . . . . . . . . . . . . . . 5.3 Apache ActiveMQ . . . . . . . . . . . . . . . . . . . . . 5.4 Elemente de programare - JMS . . . . . . . . . . . . . 5.4.1 Modul programat: Trimiterea unui mesaj . . . . 5.4.2 Receptia sincron a unui mesaj . . . . . . . . . a 5.4.3 Receptia asincron a unui mesaj . . . . . . . . . a 5.4.4 Publicarea mesajelor . . . . . . . . . . . . . . . 5.4.5 Subscrierea i receptia mesajelor . . . . . . . . . s 5.4.6 Prin JNDI - declararea obiectelor administrator 5.4.7 Comunicatia prin coad - queue . . . . . . . . . a 5.4.8 Comunicatia pe baz de subiect - topic . . . . . a 5.5 Mesaje SOAP prin Java Message Service . . . . . . . . 5.5.1 SOAP . . . . . . . . . . . . . . . . . . . . . . . 5.5.2 Mesaje SOAP . . . . . . . . . . . . . . . . . . . 5.5.3 Ataamente SOAP . . . . . . . . . . . . . . . . s 5.6 Apache-qpid . . . . . . . . . . . . . . . . . . . . . . . 5.7 Protocolul AMQP . . . . . . . . . . . . . . . . . . . . . 5.7.1 Crearea unei cozi . . . . . . . . . . . . . . . . . 5.7.2 Expedierea / publicarea unui mesaj . . . . . . . 5.7.3 Receptionarea mesajelor . . . . . . . . . . . . .
CUPRINS
. . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . .
107 . 107 . 109 . 110 . 110 . 111 . 116 . 118 . 119 . 121 . 122 . 124 . 126 . 129 . 129 . 129 . 137 . 145 . 147 . 148 . 150 . 152
II
157
6 HyperText Transfer Protocol 159 6.1 Transactie http . . . . . . . . . . . . . . . . . . . . . . . . . . . 159 6.2 Server Web - container de servlet . . . . . . . . . . . . . . . . . 165 6.3 Serverul Web apache-tomcat . . . . . . . . . . . . . . . . . . . . 166 7 Applet - Miniaplicatie Java 167 7.1 Clasa Applet . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168 7.2 Desfurarea unui applet . . . . . . . . . . . . . . . . . . . . . . 169 as 7.3 Comunicare Java - JavaScript ntr-un applet . . . . . . . . . . . 175 8 Conexiune simpl prin clase din java.net a 177 8.1 Clasa java.net.URL . . . . . . . . . . . . . . . . . . . . . . . . 177
CUPRINS
9 179 . 180 . 181 . 184 . 191 . 194 . 194 . 200 . 202 . 204 . 206 . 207 . 209 . 211 . 213 . 216 . 221 . 222 . 225 227 . 227 . 232 . 234 . 235 . 236 . 240 . 241 . 246 . 247 . 247 . 251 . 253
9 Servlet 9.1 Marcajul <form> . . . . . . . . . . . . . . . . 9.2 Realizarea unui servlet . . . . . . . . . . . . . 9.2.1 Codul unui servlet . . . . . . . . . . . 9.3 Procesare asincron Java Servlet 3.0 . . . . a n 9.4 Faciliti de programare cu servlet . . . . . . . at 9.4.1 Program client al unui servlet . . . . . 9.4.2 Servlete antuite . . . . . . . . . . . nl 9.4.3 Sesiune de lucru . . . . . . . . . . . . . 9.4.4 Cookie . . . . . . . . . . . . . . . . . . 9.4.5 Autenticare . . . . . . . . . . . . . . 9.4.6 Servlet cu conexiune la o baz de date a 9.4.7 Imagini furnizate de servlet . . . . . . 9.4.8 Servlet cu RMI . . . . . . . . . . . . . 9.4.9 Servlet cu JMS . . . . . . . . . . . . . 9.5 FileUpload . . . . . . . . . . . . . . . . . . . . 9.6 Descrcarea unui ier . . . . . . . . . . . . . a s 9.7 Filtru . . . . . . . . . . . . . . . . . . . . . . 9.8 Server apache-tomcat ncorporat . . . . . . . . 10 Java Server Page JSP 10.1 Tehnologia JSP . . . . . . . . . . . . . . . 10.1.1 Declaratii 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 fr atribute i fr corp. . aa s aa 10.3.2 Marcaje cu atribute i fr corp. . . s aa 10.3.3 Marcaje cu corp. . . . . . . . . . .
. . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
11 Extensii servlet 257 11.1 Aplicatii Web prin Hessian . . . . . . . . . . . . . . . . . . . . . 257 11.2 Google App Engine - GAE . . . . . . . . . . . . . . . . . . . . . 260
10 12 Portlet 12.1 Apache-pluto . . . . . . 12.2 Dezvoltarea unui portlet 12.3 Elemente de programare 12.4 Produse Portal . . . . . 12.4.1 uPortal . . . . . 12.4.2 Jetspeed-2 . . . .
CUPRINS
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
13 Java Web Start 289 13.1 Java Web Start . . . . . . . . . . . . . . . . . . . . . . . . . . . 289 14 Java Management Extensions 14.1 Standard MBean . . . . . . . . . . . 14.1.1 Crearea unui Standard MBean 14.1.2 Crearea unui MBeanServer . . 14.1.3 Noticri . . . . . . . . . . . a 14.1.4 Agent MBean . . . . . . . . . 14.1.5 Invocarea la distanta . . . . . 297 . 298 . 298 . 300 . 304 . 307 . 308
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
III
ANEXE
321
323 . 323 . 326 . 328 345 349 351 . 351 . 352 . 353 357 . 357 . 359 . 361
A Unelte de dezvoltare A.1 XML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A.2 apache-ant . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A.3 apache-maven . . . . . . . . . . . . . . . . . . . . . . . . . . . B Testare cu junit C Component Java a D Adnotri a D.1 Denirea unei adnotri . . . . . . . . . . . . . . . . . . . . . . a D.2 Declararea unei adnotri . . . . . . . . . . . . . . . . . . . . . a D.3 Procesarea unei adnotri . . . . . . . . . . . . . . . . . . . . . a E Utilizarea SGBD Java n E.1 Derby / Javadb . . . . . . . . . . . . . . . . . . . . . . . . . . E.2 mysql . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . E.3 Sablonul de utilizare a unei baze de date . . . . . . . . . . . .
CUPRINS
11
12
CUPRINS
Capitolul 1 Introducere
Retelele locale, internetul, rspndirea pe o arie geograc a resurselor i a a a a s locatiilor care se petrec actiuni ce in de o activitate bine denit sau sunt n t a urmrite, gestionate din alte locuri au drept consecinta existenta aplicatiilor a distribuite. Termenul distribuit se refer tocmai la faptul c componente ale a a aplicatiei se a pe calculatoare diferite dar a ntre care au loc schimburi de date. Dac prtile unei aplicatii sau resursele utilizate se gsesc pe calculatoare a a a distincte atunci aplicatia se numete distribuit. s a Intre prtile sau resursele unei aplicatii distribuite au loc schimburi de a date, ceea ce se face utiliznd diferite mecanisme la realizarea crora concur a a a sistemul de calcul, sistemul de operare i limbajul de programare. s Astfel se vorbete de programare distribuit ca mijloc de realizare a aplicatiilor s a distribuite. Pe lng algoritm, structuri de date, limbaj de programare, la a a realizarea unei aplicatii distribuite intervin comunicatiile: schimbul de date dintre dou componente aate pe calculatoare diferite. a Punem evidenta dou modele de aplicatii distribuite: n a client-server: Programul server execut cererile clientilor. a O aplicatie client server se compune din: componenta server - alctuit din programe / clase ce asigur una a a a sau mai multe functiuni (servicii), care pot apelate de ctre clienti. a componenta client - alctuit din programe / clase care permit aca a cesul la server i apelarea serviciilor acestuia. s Serverul i clientul (clientii) ruleaz, de obicei, pe calculatoare distincte. s a Un server trebuie s satisfac cererile mai multor clienti. a a 13
14
CAPITOLUL 1. INTRODUCERE
Durata de viata a unei aplicatii client server este dat de durata a functionrii serverului. Aceast durat poate alctuit din intervale a a a a a disjuncte de timp, ntre acele intervale, din diverse motive, serverul este inactiv. Intervalul de timp determinat de conectarea unui client la server i pn s a a aceast perioad, clientul la deconectare poart numele de sesiune. In a a a poate invoca mai multe servicii ale serverului. Un client poate initia mai multe sesiuni. Un client trebuie s-i regseasc datele cadrul unei sesiuni, as a a n ntre sesiuni, pe toat durata de viat a aplicatiei. Astfel se pune problema a a retinerii / persistentei datelor pentru ecare client parte. n Amintim urmtoarele tehnologii Java pentru realizarea aplicatiilor clienta server: Tehnologii destinate retelelor locale, nebazate pe protocolul http. Socluri RMI (Remote Method Invocation) CORBA (Common Object Request Brocker Arhitecture) Comunicatiile utilizeaz porturi care nu trebuie s e a a nchise de eventuale aplicatii de tip rewall. Tehnologii cu comunicatii prin Internet, bazate pe protocolul http. JMS (Java Message Service) Servlet i JSP (Java Server Pages) s Portlet Java Web Start dispecer-lucrtor: Programul dispecer distribuie sarcinile de execua tat lucrtorilor i le coordoneaz activitatea. Exist multe abordri de a s a a a programere a aplicatiilor dispecer-lucrtor. a Exist diferente mari a ntre o aplicatie care ruleaz pe un calculator i o a s 1 aplicatie distribuit a latenta (latency): diferenta timp n ntre o operatie executat pe un cal a culator la distant de executia ei pe calculatorul local. Receptia rezula tatului unei operatii executate pe un calculator la distanta se poate pro grama
Waldo J., Wyant G., Wollrath A., Kendall S., 1994, A Note on Distributed Computing. Sun Microsystems Corporation, Technical report, SMLI TR-94-29.
1
15 sincron de obicei receptia blocheaz rul de executie al apelului a pn la sosirea rezultatului; a a asincron receptia se obtine ntr-un obiect dedicat care se execut a afara rului de executie al apelului. n O preocupare continu este dezvoltarea de tehnologii hard i soft pentru a s micorarea latentei. s accesul la memorie (memory access) Aplicatiile distribuite pot rula pe platforme diferite (de exemplu Java i .NET) iar componentele ei pot s realizate limbaje de programare diferite. Instrumente de programare n cadre de lucru (framework ) care mijlocesc realizarea aplicatiilor asigur a accesul la resursele aate memoria calculatoarelor. n Exist o preocupare pentru produse care asigur interoperabilitatea dina a tre platformele de calcul. prbuirea partial (partial failure) const a s a a n ncetarea functionrii unei a prti a aplicatiei distribuite. Tratarea acestei probleme pare a cea mai a dicil tem a programrii distribuite. a a a Precizm sensul unor notiuni utilizate lucrare: a n protocol - pachet de reguli, ablon utilizat comunicatii, accesarea s n n unor resurse. Exemple de protocoale utilizate sunt: http - HyperText Transfer Protocol este principalul protocol utilizat comunicatiile prin Internet; n https protocol http securizat; le - protocol pentru specicarea ierelor aate pe calculatorul s local; ftp - File Transfer Protocol - protocol pentru transferul ierelor s ntre dou calculatoare; a smtp - Simple Message Transfer Protocol utilizat de pota elecronic. s a host - calculatorul gazd, cel pe care se lucreaz. Acest calculator se a a specic printr-o adres IP (Internet Protocol ) sau printr-un nume. a a port - o adres de memorie cuprins a a ntre 0 i 65535. Porturile cuprinse s ntre 0 i 1023 sunt rezervate sistemului de operare. Dintre acestea amins tim:
CAPITOLUL 1. INTRODUCERE
Referintele resurselor se indic folosind Uniform Resource Identiers - (URI) a i mai precis Uniform Resource Locator - (URL). URI identic o resurs s a a n timp ce URL desemneaz locatia resursei. URL se consider ca un caz partica a ular de URI. Sintaxa folosit pentru URI este a protocol://host[:port][cale][?cerere]
17
2.1
Calculatoarele ce ruleaz retea comunic a n a ntre ele folosind protocolul TCP (Transmission Control Protocol) sau UDP (User Datagram Protocol). Intr-un program Java se utilizeaz clasele pachetului java.net prin intera mediul crora se acceseaz nivelele deservite de protocoalele TCP sau UDP. a a felul acesta se pot realiza comunicatii independente de platforma de calcul. In Pentru a alege care clas Java s e utilizat trebuie cunoscut diferenta dintre a a a a TCP i UDP. s TCP Cnd dou aplicatii comunic a a a ntre ele se stabilete o conexiune prin s intermediul creia se schimb date. Folosind protocolul TCP, comunicatia a a garanteaz c datele trimise dintr-un capt ajung cellalt capt cu pstrarea a a a n a a a ordinii care au fost trimise. Acest tip de comunicatie seamn cu o convorn a a bire telefonic. TCP furnizeaz un canal sigur de comunicatie a a ntre aplicatii. UDP Utilizarea protocolului UDP presupune trimiterea unor pachete de date numite datagrame de la o aplicatie la alta fr s se asigure faptul aa a c datagramele ajung la destinatie i nici ordinea lor de sosire. Acest tip de a s comunicatie seamn cu trimiterea scrisorilor prin pot. a a sa 19
20
2.2
Soclu TCP
Pentru a comunica utiliznd TCP programul client i programul server a s stabilesc o conexiune sigur. Fiecare program se leag la conexiune printr-un a a soclu (socket). Un soclu este captul unei ci de comunicatie bidirectional a a ntre dou programe ce ruleaz retea. Un soclu este legat de un port prin a a n care nivelul TCP poate identica aplicatia creia sunt transmise datele. a i Pentru a comunica att clientul ct i serverul citesc date de la i scriu date a a s s la soclul legat la conexiunea dintre ele. pachetul java.net clasele Socket i ServerSocket implementeaz un In s a soclu din partea clientului i respectiv din partea serverului. s Clientul cunoate numele calculatorului pe care ruleaz serverul ct i pors a a s tul la care acesta este conectat. Pentru stabilirea conexiunii, clientul ncearc a un rendez-vous cu serverul de pe maina serverului i la portul serverului. Dac s s a totul decurge bine, serverul accept conexiunea. Dup acceptare, serverul a a creaz pentru client un nou soclu legat la un alt port aa fel at asa n s nc cultarea cererilor la soclul initial s poat continua timp ce sunt satisfcute a a n a cererile clientului conectat. Din partea clientului, dup acceptarea conexiunii a soclul este creat i este utilizat pentru comunicatia cu serverul. s
Clasa java.net.Socket
Resursele clasei Socket sunt destinate clientului. Constructori public Socket(String host, int port) throws UnknownHostException, IOException Creaz un soclu conectat la calculatorul cu portul specicat. a public Socket(InetAddress host, int port) throws IOException Creaz un soclu conectat la calculatorul cu portul specicat. a Metode public InputStream getInputStream() throws IOException Returneaz un ux de intrare ataat soclului, pentru citirea (preluarea) a s informatiilor de la soclu.
21
public OutputStream getOutputStream() throws IOException Returneaz un ux de ieire ataat soclului, pentru scrierea (transmiterea) a s s informatiilor la soclu. public synchronized void close() throws IOException nchide soclul de referinta.
Clasa java.net.ServerSocket
Resursele clasei ServerSocket sunt destinate serverului. Constructori public ServerSocket(int port) throws IOException Creaz un soclu la portul specicat. Dac port=0, atunci va utilizat a a orice port disponibil. Capacitatea irului (tamponului) de ateptare pens s tru cererile de conectare se zeaz la valoarea implicit 50. Cererile a a n exces vor refuzate. public ServerSocket(int port, int lung) throws IOException plus xeaz lungimea irului (tamponului) de ateptare. In a s s public ServerSocket(int port, int lung, InetAddress adr ) throws IOException Se specic plus calculatorul de la care se ateapt cereri. Dac a n s a a adr =null, atunci se accept cereri de la orice calculator. a Metode public Socket accept() throws IOException Metoda blocheaz procesul (rul de executie) apelant pn la sosirea a a a unei cereri de conectare i creaz un soclu client prin care se va desfura s a as comunicarea cu solicitantul acceptat. public synchronized void close() throws IOException nchide soclul de referinta.
22
2.3
Serverul trebuie s satisfac simultan solicitrile mai multor clienti. Fiecare a a a client apeleaz programul server la acelai port i consecinta cererile de a s s n conectare sunt receptionate de acelai ServerSocket. Serverul receptioneaz s a apelurile secvential. La un apel, se creaz de partea severului un soclu prin a care se va face schimbul de date cu clientul. Cererile clientilor pot satisface concurent/paralel, utiliznd re de executie ce implementeaz serviciul oferit a a sau secvential - cazul unor servicii de durat scurt. n a a Exemplul 2.3.1 Sistem client - server pentru calculul celui mai mare divizor comun a dou numere naturale. Portul obiectului de tip ServerSocket este a 7999. Programul client CmmdcClient se conecteaz la server, transmite serverua lui cele dou numere naturale i receptioneaz rezultatul pe care apoi aeaz. a s a l s a esent orice program client trebuie s execute: In a a 1. Deschide/creaz un soclu. a 2. Deschide/creaz uxuri de date pentru comunicatia cu serverul. a 3. Transmite i receptioneaz date potrivit specicului aplicatiei (protos a colului serverului). Acest pas variaz de la un program client la altul. a 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
package c l i e n t ; import j a v a . i o . ; import j a v a . n e t . ; 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 ) throws IOException { 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 c a n n e r . nextLong ( ) ; =s System . out . p r i n t l n ( n= ) ; n=s c a n n e r . nextLong ( ) ;
23
20 21 22 23 24 25 26 27 28 29 30 31 32 33
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 ( ) ) ; } } }
Se presupune c programul server ruleaz pe calculatorul local i utilizeaz a a s a portul 7999. Dac aceti parametri se modic - de exemplu serverul ruleaz a s a a retea pe calculatorul atlantis la portul 8200 - atunci la apelare transmitem n aceti parametri prin java CmmdcClient atlantis 8200 s Partea server este alctuit din mai multe clase: a a Clasa MyMServer, independent de un serviciu anume, preia apelurile a clientilor i lanseaz satisfacerea cererii. s a
1 2 3 4 6 7 8 10 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
package s e r v e r . impl ; import j a v a . n e t . ; import j a v a . i o . ; import j a v a . u t i l . c o n c u r r e n t . ; 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 ) ; } } }
ciclul while, la receptia unei solicitri de conexiune se creaz i In a a s se lanseaz un r de executie a crei metod run contine actiunile ce a a a
24 rspund solicitrii. a a
package s e r v e r ; import j a v a . n e t . ; import j a v a . i o . ; 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 ( 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 n . readLong ( ) ; =i 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 corespunztoare calcului celui mai mare divizor comul a dou a a numere naturale.
1 2 3
Rularea programelor. Se pornete la s nceput programul server MyMServer iar apoi clientul CmmdcClient. Clientul se poate rula de pe orice calculator al retelei. Dac programul client se execut pe alt calculator dect cel pe care a a a ruleaz programul server, atunci la apelarea clientului trebuie precizat numele a calculatorului server i eventual portul utilizat. s O alt arhitectur a aplicatiei este dezvoltat continuare. Aceast arhia a a n a tectur este mai bun sensul c poate utilizat alte cadre de lucru / de a a n a a n dezvoltare (de exemplu OSGi, Junit). Aplicatia se va compune din:
25
Implementarea interfetei
1 2 3 4 5 6 8 10 11 12 13 14 15 16 17 18 19 20 21 22 24 25 26 27 28 29 30 31 32 33 34 35 36 37
package s e r v e r . impl ; import s e r v e r . ; import i s e r v e r . IMyMServer ; import j a v a . n e t . ; import j a v a . i o . ; import j a v a . u t i l . c o n c u r r e n t . ; 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 de lansare a serverului a
1 2 3 4
26
6 7 8 9 10 11 12 13 14 15
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 ) ; } }
2.4
Datagrame
Pentru utilizarea datagramelor pachetul java.net pune la dispozitie clasele DatagramSocket DatagramPacket MulticastSocket O aplicatie trimite i receptioneaz pachete DatagramPacket prin inter s a mediul unui DatagramSocket. Un pachet DatagramPacket poate trimis la mai multi destinatari prin intermediul unui MulticastSocket. Reamintim c o datagram este un mesaj trimis prin retea a crei sosire a a a nu este garantat iar momentul de sosire este neprecizat. a
Clasa java.net.DatagramPacket.
Trimiterea unui pachet UDP necesit crearea unui obiect a DatagramPacket care contine corpul mesajului i adresa destinatiei. Apoi s acest obiect DatagramPacket poate pus retea vederea trimiterii sale. n n Primirea unui pachet UDP necesit crearea unui obiect DatagramPacket i a s apoi acceptarea unui pachet UDP din retea. Dup primire, se poate extrage a din obiectul DatagramPacket adresa surs i continutul mesajului. as Constructori Exist doi constructori pentru datagrame UDP. Primul constructor este a folosit pentru primirea de pachete i necesit doar furnizarea unei memorii s a tampon, iar cellalt este folosit pentru trimiterea de pachete i necesit specia s a carea adresei destinatarului.
2.4. DATAGRAME
27
DatagramPacket(byte[ ] buer ,int lung) Acest contructor este folosit pentru primirea pachetelor. Un pachet se memoreaz tamponul buer avnd lung octeti. Dac lungimea paa n a a chetului depete aceast lungime, atunci pachetul este trunchiat iar as s a octetii plus se pierd. n DatagramPacket(byte[ ] buer ,int lung ,InetAddress adresa ,int port) Acest constructor este folosit pentru crearea unui pachet vederea exn pedierii. Corpul pachetului este continut tamponul buer avnd lung n a octeti. Pachetul va trimis ctre adresa i portul specicat. Trebuie s a s a existe un server UDP care ascult la portul specicat pentru trimiterea a pachetelor. Un server UDP poate coexista cu un server TCP care ascult a acelai port. s Metode InetAddress getAddress() returneaz adresa IP a expeditorului. a int getPort() returneaz portul expeditorului. a byte[] getData() returneaz continutul pachetului. a int getLength() returneaz lungimea pachetului. a void setAddress(InetAddress adresa) xeaz adresa IP a pachetului. a void setPort(int port) xeaz portul. a void setData(byte[] buer ) xeaz continutul pachetului. a void setLength(int lung) xeaz lungimea pachetului. a
28
Clasa java.net.DatagramSocket
Aceast clas se folosete att pentru trimiterea, ct i pentru primirea a a s a a s obiectelor DatagramPacket. Un obiect DatagramSocket ascult la un port a cuprins ntre 1 i 65535 (porturile cuprinse s ntre 1 i 1023 sunt rezervate pentru s aplicatiile sistem). Deoarece UDP nu este orientat pe conexiune, se va crea un singur obiect DatagramSocket pentru trimiterea pachetelor ctre diferite a destinatii i primirea pachetelor de la diferite surse. s Constructori DatagramSocket() throws SocketException Creaz un obiect DatagramSocket cu un numr de port aleator; a a DatagramSocket(int port) throws SocketException Creaz un obiect DatagramSocket cu numrul de port specicat; a a DatagramSocket(int port, InetAddress adres ) throws SocketException a Creaz un obiect DatagramSocket la adresa i portul specicat. a s Metode Clasa DatagramSocket contine metode pentru trimiterea i primirea de s obiecte DatagramPacket, nchiderea soclului, determinarea informatiilor adre sei locale i setarea timpului de primire. s void send(DatagramPacket pachet) throws IOException Trimite pachetul prin retea. Dac se trimit pachete la o destinatie ne a cunoscut sau care nu ascult, cele din urm se genereaz o exceptie a a n a a IOException. void receive(DatagramPacket pachet) throws IOException Metoda primete un singur pachet UDP obiectul pachet specicat. s n Apoi, pachetul poate inspectat pentru determinarea adresei IP surs, a portul surs i lungimea mesajului. Executia metodei este blocat pn as a a a cnd se primete cu succes un pachet sau se scurge timpul de ateptare. a s s InetAddress getLocalAddress() Returneaz adresa local ctre care este legat acest DatagramSocket; a a a int getLocalPort() Returneaz numrul de port unde ascult DatagramSocket. a a a
2.4. DATAGRAME
29
void close() Inchide DatagramSocket. void setSoTimeout(int timpDeAteptere) throws SocketException s Metoda xeaz timpul de ateptare ( milisecunde) a soclului. Metoda a s n receive() se va bloca pentru timpul de ateptare specicat pentru prims irea unui pachet UDP, dup care va arunca o exceptie Interrupted a Exception. Dac valoarea parametrului este 0, atunci soclul este bloa cat. int getSoTimeout() throws SocketException Returneaz timpul de ateptare. a s void setSendBufferSize(int lungime) throws SocketException Fixeaz lungimea tamponului de trimitere a soclului la valoarea specia cat. Nu poate trimis mesaj UDP de lungime mai mare de aceast a a valoare. int getSendBufferSize() throws SocketException Returneaz lungimea tamponului de trimitere a soclului. a void setReceiveBufferSize(int lungime) throws SocketException Fixeaz lungimea tamponului de primire a soclului la valoarea specia cat. Nu poate primit un mesaj UDP de lungime mai mare de aceast a a valoare. int getReceiveBufferSize() throws SocketException Returneaz lungimea tamponului de primire a soclului. a void connect(InetAddress adresa, int port) throws SocketException Conecteaz soclul la adresa i portul specicat. Aceast metod nu este a s a a cerut pentru operatiile uzuale UDP. a void disconnect() Deconecteaz soclul conectat. a InetAddress getInetAddress() Returneaz obiectul InetAddress ctre care este conectat soclul sau a a null dac acesta nu este conectat. a
30 int getPort()
Returneaz portul la care este conectat soclul sau -1 dac acesta nu este a a conectat.
Clasa java.net.InetAddress
Datele pot trimise prin retea indicnd adresa IP corespunztoare mainii a a s destinatie. Clasa InetAddress furnizeaz acces la adresele IP. a Nu exist constructori pentru aceast clas. Instantele trebuie create folosind a a a metodele statice: InetAddress getLocalHost() throws UnknownHostException Returneaz un obiect InetAddress corespunztor mainii locale. a a s InetAddress getByName(String host) throws UnknownHostException Returneaz un obiect InetAddress corespunztor mainii host, parametru a a s care poate specicat prin nume (de exemplu atlantis) sau prin adresa IP (168.192.0.1). InetAddress [ ]getAllByName(String host) throws UnknownHostException Returneaz un ir de obiecte InetAddress corespunztor ecrei adrese a s a a IP a mainii host. s Metodele clasei InetAddress byte [ ] getAddress() Returneaz irul de octeti corespunztor obiectului InetAddress de referint. as a a String getHostName() Returneaz numele mainii gazd. a s a String getHostAddress() Returneaz adresa IP a mainii gazd. a s a boolean isMulticastAddress() Returneaz true dac obiectul InetAddress reprezint o adres IP mula a a a ticast (cuprins ntre 224.0.0.0 i 239.255.255.255). s
2.4. DATAGRAME
31
Exemplul urmtor aeaz numele i adresa calculatorului gazd ct i a s a s a a s acela al calculatoarelor ale cror nume este transmis programului ca parametru. a Exemplul 2.4.1
1 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
import j a v a . n e t . ; 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.4.1
Un pachet de tip DatagramPacket este alctuit dintr-un ir de octeti. Este a s datoria programatorului s transforme datele (mesajul) iruri de octeti la a n s expediere i la receptie. s Transformarea unui obiect serializabil ntr-un ir de octeti i invers se poate s s realiza cu schema
32
Fie socket un obiect de tip DatagramSocket prin intermediul cruia se a execut expedierea / receptionarea pachetelor de tip DatagramPacket. a principiu expedierea i transformarea obiectului obj In s ntr-un ir de octeti s se poate realiza cu secventa de cod ByteArrayOutputStream baos=new ByteArrayOutputStream(256); ObjectOutputStream out=new ObjectOutputStream(baos); out.writeObject(obj); byte[] bout=baos.toByteArray(); DatagramPacket packet=new DatagramPacket(bout,bout.length, address,port); socket.send(packet); unde address i port sunt adresa i portul destinatarului. Dac packet este un s s a obiect DatagramPacket receptionat atunci metodele getAddress() i getPort() s furnizeaz adresa i portul expeditorului a s Receptionarea i transformarea invers este s a byte[] bin=new byte[256]; packet=new DatagramPacket(bin,bin.length); socket.receive(packet); ByteArrayInputStream bais=new ByteArrayInputStream(bin); ObjectInputStream in=new ObjectInputStream(bais); obj=in.readObject(); Dac mesajul este un obiect String atunci el se transform a a ntr-un ir de s octeti cu metoda byte[] String.getByte() i invers, el se obtine prin new s String(bin) sau new String(packet.getData()). Exemplul 2.4.2 Programm serviciul calculului celui mai mare divizor coa mun a dou numere. a
2.4. DATAGRAME
33
Clientul va trimite un obiect Protocol, care va contine datele problemei i va s receptiona un obiect de acelai tip cu rezultatul (cel mai mare divizor comun) s primul cmp al obiectului. Aceasta clasa este disponibil att serverului ct n a a a a i clientului. s Se va utiliza arhitectura de aplicatie dezvoltat nalul sectiunii ante a n rioare. Aplicatia se va compune din: Aplicatia server alctuit din: a a 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 interfetei
1 2 3 4 5 6 8 10 11 12 13 14 15 16 17 18 19 20 21 22
package s e r v e r . impl ; import s e r v e r . ; import i s e r v e r . IMyMServer ; import j a v a . n e t . ; import j a v a . i o . ; import j a v a . u t i l . c o n c u r r e n t . ; 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 ) ; 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 ; }
34
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 53
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 ) ; } }
Aplicatia client
1 2 3 4 5
2.4. DATAGRAME
35
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
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.4.2
Clasa java.net.MulticastSocket
Prin intermediul unui soclu de tip MulticastSocket se pot receptiona datagrame expediate de un server ctre toti clientii cu un asemenea soclu. a Constructori MulticastSocket(int port) throws SocketException Metode void joinGroup(InetAddress adres ) throws SocketException a
36
Soclul se conecteaz la grupul denit de adresa IP (de tip D, adic a a cuprins ntre 224.0.0.0 i 239.255.255.255). s void leaveGroup(InetAddress adres ) throws SocketException a Soclul se deconecteaz la grupul denit de adresa IP. a void close() Pregtirea clientului vederea receptionrii datagramelor printr-un soclu a n a de tip MulticastSocket const din a MulticastSocket socket= new MulticastSocket(port); InetAddress adresa=InetAddress.getByName("230.0.0.1"); socket.joinGroup(adresa); nal, clientul se deconecteaz i In a s nchide soclul. socket.leaveGroup(adresa); socket.close(); Pachetele trimise de programul server trebuie s se adreseze grupului, idena ticat prin adresa IP de tip D. Astfel prin multicast serverul trimite pachete la o adres de grup i la un a s port xat. Pachetele emise de server sunt receptionate de orice client ce creaz a un soclu de tip MulticastSocket pentru portul la care emite serverul i care s se altur grupului. a a Prin broadcast serverul emite datagrame ctre orice calculator al retelei a locale la un anumit port. Faptul c emiterea datagramelor este de tip broadcast a se indic prin a DatagramSocket.setBroadcast(true) Orice client care si creaz un soclu la portul la care emite serverul receptioneaz a a datagramele trimise de server. Adresa utilizat de server la crearea dataa gramelor trebuie s identice reteaua. a Observatie. cazul unui calculator izolat este nevoie de instalarea In driverului Microsoft Loopback Adapter, care simuleaz existenta unei plci de a a retea active. Exemplul 2.4.3 Multicast i Broadcast: programele server emit din cinci s n cinci secunde ora exact. Un client va receptiona cte cinci datagrame. a a Codurile sunt date Fig. 2.1 i Fig. 2.2, respectiv pentru partea de server n s i cea de client. s
2.4. DATAGRAME
37
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()); } } }
38
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(); } }
39
2.5
Canale de comunicatie
Odat cu versiunea j2sdk1.4 apar clase noi pentru operatii de intrare - ieire a s pachetele java.nio i java.nio.channels. Pachetul java.nio.channels n s contine clase pentru comunicatia retea, i anume canalele de comunicatie. n s Utilizm clasele java.nio.channels.SocketChannel, java.nio.channel. a DatagramChannel. Informatia transportat aceste canale de comunicatie a n trebuie nglobat obiecte container de tip Buffer. a n
Clasa java.nio.Buffer
Ierarhia claselor Buffer abstract Buffer ByteBuffer ShortBuffer IntBuffer LongBuffer FloatBuffer DoubleBuffer CharBuffer Un obiect de tip typeBuffer este un tampon (container) care contine date de tipul specicat de denumirea clasei. Un obiect de tip Buffer este caracterizat de capacitate (capacity) numrul elementelor care pot a nmagazitate n tampon; limit (limit) marginea superior a indicelui; a a indice (position) valoarea curent a indicelui, ce corespunde unui cursor a 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 e re arcat. Fixeaz a nc a limita = capacitate i indice = 0. s ip() pregtete obiectul de tip Buffer pentru consultare (citire). Fixa s eaz limita =numrul elementelor din tampon i indice = 0. a a s rewind() pregtete obiectul de tip Buffer pentru re-citire. a s
40
Clasa java.nio.ByteBuffer
Instantierea unui obiect se obtine prin metoda static a static ByteBuffer allocate(capacitate) Introducerea i extragerea datelor din tampon se poate face mod s n relativ - implic modicarea indicelui tamponului; a absolut - far modicarea indicelui. a Metode Introducerea datelor mod relativ: n ByteBuffer put(byte b) ByteBuffer putTip(tip x ) Extragerea datelor mod relativ: n byte get() tip getTip() Introducerea datelor mod absolut: n ByteBuffer put(int index ,byte b) ByteBuffer putTip(int index ,tip x ) Extragerea datelor mod absolut: n byte get(int index ) tip getTip(int index ) unde tip poate char, short, int, long, float, double. Alte metode public final boolean hasRemaining() Dac indicele nu este egal cu limita atunci returneaz true, semnalnd a a a existenta tampon a unor octeti. n static ByteBuffer wrap(byte[] array)
41
public static ByteBuffer wrap(byte[] array,int oset,int length) Convertete irul de octeti s s ntr-un obiect Bytebuffer. public final byte[] array() Transformarea invers, obiectul ByteBuffer este convertit a ntr-un ir de s octeti. 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();
Clasa java.net.InetSocketAddress
Clasa InetSocketAddress extinde clasa SocketAddress i s ncapsuleaz a adresa unui calculator din Internet mpreun cu un port vederea legrii la a n a 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 prin a static ServerSocketChannel open() throws IOException Unui asemenea obiect i se asociaz un ServerSocket prin metoda a ServerSocket socket() throws IOException. Obiectul de tip ServerSocket trebuie leagat la un port de comunicatie prin metoda void bind(InetSocketAddress endpoint) throws IOException. Sablonul de utilizare este
42
try{ ServerSocketChannel ssc=ServerSocketChannel.open(); ServerSocket ss=ssc.socket(); InetSocketAddress isa=new InetSocketAddress(addr,port); ss.bind(isa); } catch(Exception e){. . .} La apelul unui client, serverul trebuie s genereze un obiect de tip Socket a Channel prin care se vor derula comunicatiile cu clientul. Acest canal de comunicatie se obtine cu metoda accept().
Clasa java.nio.channels.SocketChannel
Crearea unui obiect de tip SocketChannel se realizeaz prin a 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 i se receptioneaz prin metoda s a int read(ByteBuffer destinatie) Valoarea returnat de cele dou metode reprezint numrul octetilor trimii a a a a s / receptionati. Doar octetii unui obiect de tip ByteBuffer cuprini s ntre indice i limit s a sunt transmii prin canal. Astfel, dup arcarea unui obiectului ByteBuffer s a nc cu metode relative trebuie apelat metoda flip(). a Canalul se nchide cu metoda close(). Exemplul 2.5.1 Calculul celui mai mare divizor comun a dou numere nata urale. Aplicatie client-server bazat pe canale de comunicatie prin socluri se com pune din: Aplicatia server alctuit din: a a
43
Interfat a
1 2 3 4 5 6
Implementarea interfetei
1 2 3 4 5 6 7 8 10 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 29 30 31 32 33 34 35 36 37 38 39 40 41 42
package s e r v e r . impl ; import s e r v e r . ; import i s e r v e r . IMyMServer ; import j a v a . n e t . ; import j a v a . n i o . ; 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 . ; 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
44
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 32 33 34 35 36 37 38 39 40
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 . ; 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 ; } 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 b . g e t ( 0 ) ; =l // 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 ) ; } }
Aplicatia client
45
1 2 3 4 5 6 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 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 . i o . ; import j a v a . n e t . ; import j a v a . n i o . ; import j a v a . n i o . c h a n n e l s . ; 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= 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 c a n n e r . nextLong ( ) ; =s 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 ( ) ) ; } }
46
}
59
Clasa java.nio.channels.DatagramChannel
Sablonul de programare pentru instantierea unui obiect de tip DatagramChannel este DatagramChannel dc=null; InetSocketAddress isa=new InetSocketAddress(port); try{ dc=DatagramChannel.open(); DatagramSocket datagramSocket=dc.socket(); datagramSocket.bind(isa); } catch(Exception e){. . .} unde port este portul folosit de DatagramChannel. Dac port=0 atunci se a alege aleator un port disponibil. Transmiterea unui obiect ByteBuffer se face cu metoda public int send(ByteBuffer src, SocketAddress target) throws IOException Metoda returneaz numrul de octeti expediati. Receptia unui ByteBuffer se a a obtine cu metoda public SocketAddress receive(ByteBuffer dst) throws IOException Obiectul returnat reprezint adresa expeditorului. a Exemplul 2.5.2 Calculul celui mai mare divizor comun a dou numere nata urale. Aplicatia server este alctuit din: a a 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 ) ; }
47
Implementarea interfetei
1 2 3 4 5 6 7 8 10 12 13 14 15 16 17 18 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 53 54 55 56 57
package s e r v e r . impl ; import s e r v e r . ; import i s e r v e r . IMyMServer ; import j a v a . n e t . ; import j a v a . n i o . ; import j a v a . n i o . c h a n n e l s . DatagramChannel ; import j a v a . u t i l . c o n c u r r e n t . ; 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 ) ; } 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; 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 ) { 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 b . g e t ( 0 ) ; =l // 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 ( ) ) ; } } } }
48
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 ) ; } }
Aplicatia client
1 2 3 4 5 6 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
package c l i e n t ; import j a v a . i o . ; import j a v a . n e t . ; import j a v a . n i o . ; import j a v a . n i o . c h a n n e l s . ; 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 ) 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 ) ;
49
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
System . out . p r i n t l n ( m ) ; = m c a n n e r . nextLong ( ) ; =s 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 // r=l b . g e t ( 0 ) ; System . out . p r i n t l n ( Cmmdc = +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 e r r o r : +e . g e t M e s s a g e ( ) ) ; } finally { i f ( dc != n u l l ) dc . d i s c o n n e c t ( ) ; } } }
Clasa java.nio.channels.FileChannel
Clasa FileChannel simplic copierea pe un calculator a unui ier dintr-o a s locatie alta i are posibilitatea de a alimenta / de a alimentat de un alt n s a tip de canal. Durata acestor operatii este mai mic dect cazul programrii a a n a cu clasele pachetului java.io. O instanta a clasei FileChannel se poate obtine cu metoda FileChannel getChannel() a claselor FileInputStream, FileOutputStream. Fluxul de octeti este directionat spre, respectiv din, obiectul de tip FileChannel instantiat. Transferul octetilor din ux spre / dintr-un SocketChannel se face uti liznd ablonul a s long fileSize=fileChannel.size(); fileChannel.transferTo(0,fileSize,socketChannel); respectiv fileChannel.transferFrom(0,fileSize,socketChannel);
50
caz care valoarea variabilei leSize trebuie stabilit pe alt cale. n a a Exemplul 2.5.3 Aplicatie de transfer a unui ier de la server la client. s Codul clasei server este
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 32 33 34 35 37 38 39 40 41 42 44 45 46 47 48 49 51 52
import import import import import import import import import import
java . io . F i l e ; java . io . FileInputStream ; j a v a . i o . IOException ; java . net . InetSocketAddress ; java . net . ServerSocket ; java . nio . ByteBuffer ; java . nio . LongBuffer ; java . nio . channels . FileChannel ; java . nio . channels . ServerSocketChannel ; java . nio . channels . SocketChannel ;
public c l a s s S e r v e r { public s t a t i c void main ( S t r i n g [ ] a r g s ) { int port = 7999; ServerSocketChannel s s c = null ; try { s s c = 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 ) ; ServerSocket ss = ssc . socket ( ) ; 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 . 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 . . . ) ; while ( true ) { serviciu ( ssc ); } } private s t a t i c void s e r v i c i u ( S e r v e r S o c k e t C h a n n e l s s c ) { S t r i n g f i l e = xmlp i c . j p g ; 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 ) ; String pathToFiles = f i l e s ; SocketChannel sc = null ; try { sc = ssc . accept ( ) ; F i l e i n p u t F i l e = new F i l e ( p a t h T o F i l e s + f s + f i l e ) ; F i l e I n p u t S t r e a m f i s = new F i l e I n p u t S t r e a m ( i n p u t F i l e ) ; FileChannel f i l e C h a n n e l = f i s . getChannel ( ) ; // T r i m i t dimensiunea f i s i e r u l u i c a t r e c l i e n t long f i l e S i z e = f i l e C h a n n e l . s i z e ( ) ; 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 ( Long . SIZE / 8 ) ; L o n g B u f f e r b u f = bb . a s L o n g B u f f e r ( ) ; b u f . put ( f i l e S i z e ) ; s c . w r i t e ( bb ) ; // T r a n s f e r f i s i e r u l c a t r e c l i e n t fileChannel . transferTo (0 , f i l e S i z e , sc ) ;
51
54 55 56 57 58 59 60
java . io . F i l e ; java . i o . FileOutputStream ; j a v a . i o . IOException ; java . net . InetSocketAddress ; java . nio . ByteBuffer ; java . nio . channels . FileChannel ; java . nio . channels . SocketChannel ;
public c l a s s C l i e n t { private s t a t i c S t r i n g path = r e p o s i t o r y ; private s t a t i c S t r i n g f i l e = xmlp i c . j p g ; 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 ] ) ; SocketChannel sc = null ; 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 ) ; 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 ( ho st , 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 ) ; // Se p r e i a dimensiunea f i s i e r u l u i ( p e n t r u v e r i f i c a r e ) 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 ( Long . SIZE / 8 ) ; s c . r e a d ( bb ) ; long f i l e S i z e = bb . getLong ( 0 ) ; // D e s c h i d c a n a l u l S t r i n g fileOutName = path + f s + f i l e ; F i l e f i l e P a t h = new F i l e ( path ) ; if (! filePath . exists ()) { f i l e P a t h . mkdirs ( ) ; } F i l e O u t p u t S t r e a m f o s = new F i l e O u t p u t S t r e a m (new F i l e ( fileOutName ) ) ; FileChannel f c = f o s . getChannel ( ) ; f c . t r a n s f e r F r o m ( sc , 0 , f i l e S i z e ) ; System . out . p r i n t l n ( F i s i e r r e c e p t i o n a t + f i l e + de + fileSize + octeti ); sc . clos e ( ) ; fos . close (); fc . close (); } catch ( IOException e ) {
52
49 50 51 52
System . out . p r i n t l n ( C l i e n t E r r o r : +e . g e t M e s s a g e ( ) ) ; } } }
2.6
Apache-MINA
Apache-MINA: Multiporpose Infrastructure for Network Applications denete o interfata de programare (API: Application Programming Interface) s pentru utilizarea mai multor protocoale de transport TCP, UDP, etc., oferind o performant sporit. a a Instalarea produsului se face prin dezarhivarea resursei binare descrcate. a Utilizarea necesit includerea variabila de sistem classpath a ierului a n s mina-core-*.*.*.jar. Suplimentar, sunt necesare slf4j-api-*.*.*.jar, slf4j-jdk14-*.*.*.jar din pachetul slf4j, Simple Logging Faade for Java. c Modelul de programare MINA este diferentiat pe partea de server i pe s partea de client, dar esent const din: n a a 1. Denirea unui adaptor/conector al operatiilor de intrare/ieire; s 2. Denirea ltrului care transform irul de octeti al datelor serializate as n obiecte / tipuri predenite sau invers; 3. Ataarea manipulatorului datelor vehiculate, obiectul care implementeaz s a logica aplicatiei; 4. Conectarea. Vom urmrii aceti pai pentru a s s Exemplul 2.6.1 Calculul celui mai mare divizor comun a dou numere nata urale. Clientul trimite datele sub forma unui ir de caractere alcatuit din cele s dou numere separate printr-un spatiu. Serverul trimite rspunsul ca String. a a
Aplicatia server
Aplicatia server se compune din clasele: CmmdcServer - ndeplinete sarcinile MINA; s
2.6. APACHE-MINA
53
CmmdcHandler - manipulatorul prtii server; a App - contine metoda de calcul a celui mai mare divizor comun. Manip ulatorul va instantia un obiect de tip App. Sarcinile MINA se programeaz prin a 1. Denirea unui adaptor pentru protocolul TCP al operatiilor de intrare/ieire: s IoAcceptor acceptor = new NioSocketAcceptor(); Pentru protocolului UDP se utilizeaz clasa NioDatagramAcceptor. a 2. Denirea ltrului care transform irul de octeti al datelor serializate as n cazul care datele sunt iruri obiecte / tipuri predenite sau invers. In n s de carctere (String), codul este acceptor.getFilterChain().addLast( "codec", new ProtocolCodecFilter( new TextLineCodecFactory( Charset.forName( "UTF-8" )))); 3. Ataarea manipulatorului datelor vehiculate, obiectul care implementeaz s a logica aplicatiei: CmmdcHandler handler=new CmmdcHandler(); acceptor.setHandler(handler); 4. Conectarea: acceptor.bind(new InetSocketAddress(PORT) ); Codul complet al clasei CmmdcServer este
1 2 4 5 6 7 8 10 11 13
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 r s e t . C h a r s e t ; import o r g . apache . mina . c o r e . s e r v i c e . I o A c c e p t o r ; import o r g . apache . mina . f i l t e r . c o d e c . P r o t o c o l C o d e c F i l t e r ; import o r g . apache . mina . f i l t e r . c o d e c . t e x t l i n e . TextLineCodecFactory ; import o r g . apache . mina . t r a n s p o r t . s o c k e t . n i o . N i o S o c k e t A c c e p t o r ; // i m p o r t o r g . apache . mina . t r a n s p o r t . s o c k e t . n i o . NioDatagramAcceptor ; public c l a s s CmmdcServer{ private s t a t i c f i n a l i n t PORT = 8 9 9 9 ; public s t a t i c void main ( S t r i n g [ ] a r g s ) throws Throwable {
54
14 15 16 17 18 20 21 22 23 24 25
I o A c c e p t o r a c c e p t o r = new N i o S o c k e t A c c e p t o r ( ) ; // I o A c c e p t o r a c c e p t o r = new NioDatagramAcceptor ( ) ; a c c e p t o r . g e t F i l t e r C h a i n ( ) . addLast ( c o d e c , new P r o t o c o l C o d e c F i l t e r ( new TextLineCodecFactory ( C h a r s e t . forName ( UTF8 ) ) ) ) ; CmmdcHandler h a n d l e r=new CmmdcHandler ( ) ; acceptor . setHandler ( handler ) ; System . out . p r i n t l n ( S e r v e r r e a d y on p o r t + PORT) ; a c c e p t o r . bind (new I n e t S o c k e t A d d r e s s (PORT) ) ; } }
Clasa manipulatorului extinde clasa IoHandlerAdapter. Sarcina programatorului const suprascrierea unora din metodele: a n public void sessionOpened(IoSession session)throws Exception public void sessionCreated(IoSession session)throws Exception public void sessionClosed(IoSession session)throws Exception public void sessionIdle(IoSession session,IdleStatus status)throws Exception public void exceptionCaught(IoSession session,Throwable cause)throws Exception public void messageReceived(IoSession session,Object message)throws Exception public void messageSent(IoSession session,Object message)throws Exception Codul clasei CmmdcHandler este
1 2 4 5 6 7 8 9 11 12 13 14 15
import o r g . apache . mina . c o r e . s e r v i c e . I o H a n d l e r A d a p t e r ; import o r g . apache . mina . c o r e . s e s s i o n . I o S e s s i o n ; public c l a s s CmmdcHandler extends I o H a n d l e r A d a p t e r { @Override public void e x c e p t i o n C a u g h t ( I o S e s s i o n s e s s i o n , Throwable c a u s e ) throws E x c e p t i o n { cause . printStackTrace ( ) ; } @Override public void m e s s a g e R e c e i v e d ( I o S e s s i o n s e s s i o n , O b j e c t message ) throws E x c e p t i o n { S t r i n g l s=System . g e t P r o p e r t y ( l i n e . s e p a r a t o r ) ; S t r i n g s t r = message . t o S t r i n g ( ) . t r i m ( ) ;
2.6. APACHE-MINA
55
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
String [ ] pieces = str . s p l i t ( ) ; i f ( p i e c e s . l e n g t h <2){ session . write ( l s ) ; s e s s i o n . w r i t e ( Numar i n s u f i c i e n t de p a r a m e t r i ) ; session . write ( l s ) ; } else { try { long var1 , v a r 2 ; v a r 1 = Long . par se Lon g ( p i e c e s [ 0 ] ) ; v a r 2 = Long . par se Lon g ( p i e c e s [ 1 ] ) ; session . write ( l s ) ; App o b j=new App ( ) ; s e s s i o n . w r i t e ( o b j . cmmdc( var1 , v a r 2 ) ) ; session . write ( l s ) ; } catch ( NumberFormatException ex ) { session . write ( l s ) ; s e s s i o n . w r i t e ( Date i n c o r e c t e nu s u n t numere ) ; session . write ( l s ) ; } } } }
Aplicatia client
Aplicatia client se compune din clasele: CmmdcClient - ndeplinete sarcinile MINA; s CmmdcClientHandler - manipulatorul prtii client; a Sarcinile MINA se programeaz prin a 1. Denirea unui adaptor pentru protocolul TCP al operatiilor de intrare/ieire: s IoAcceptor acceptor = new NioSocketAcceptor(); Pentru protocolului UDP se utilizeaz clasa NioDatagramAcceptor. a 2. Denirea ltrului care transform irul de octeti al datelor serializate as n cazul care datele sunt iruri obiecte / tipuri predenite sau invers. In n s de carctere (String), codul este acceptor.getFilterChain().addLast( "codec", new ProtocolCodecFilter( new TextLineCodecFactory( Charset.forName( "UTF-8" ))));
56
3. Ataarea manipulatorului datelor vehiculate, obiectul care implementeaz s a logica aplicatiei: CmmdcClientHandler handler=new CmmdcClientHandler(); acceptor.setHandler(handler); 4. Conectarea: acceptor.bind(new InetSocketAddress(PORT) ); Codul complet al clasei CmmdcClient este
1 2 3 4 5 6 7 9 10 11 12 14 15 16 17 18 19 20 21 22 23 24 25 26 27 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
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 o r g . apache . mina . c o r e . R unti meIoE xcep tion ; import o r g . apache . mina . c o r e . f u t u r e . ConnectFuture ; import o r g . apache . mina . c o r e . s e s s i o n . I o S e s s i o n ; import o r g . apache . mina . t r a n s p o r t . s o c k e t . n i o . N i o S o c k e t C o n n e c t o r ; // i m p o r t o r g . apache . mina . t r a n s p o r t . s o c k e t . n i o . NioDatagramConnector ; import o r g . apache . mina . c o r e . s e r v i c e . I o C o n n e c t o r ; import import import import o r g . apache . mina . f i l t e r . c o d e c . P r o t o c o l C o d e c F i l t e r ; o r g . apache . mina . f i l t e r . c o d e c . t e x t l i n e . TextLineCodecFactory ; java . nio . c h a r s e t . Charset ; java . u t i l . Scanner ;
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 Throwable { 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 =8999; 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 ] ) ; 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 c a n n e r . nextLong ( ) ; =s System . out . p r i n t l n ( n= ) ; n=s c a n n e r . nextLong ( ) ; I o C o n n e c t o r c o n n e c t o r = new N i o S o c k e t C o n n e c t o r ( ) ; // IoConnector c o n n e c t o r = new NioDatagramConnector ( ) ; c o n n e c t o r . g e t F i l t e r C h a i n ( ) . addLast ( c o d e c , new P r o t o c o l C o d e c F i l t e r ( new TextLineCodecFactory ( C h a r s e t . forName ( UTF8 ) ) ) ) ; c o n n e c t o r . s e t H a n d l e r (new CmmdcClientHandler (m, n ) ) ; I o S e s s i o n s e s s i o n = null ; try { ConnectFuture f u t u r e = c o n n e c t o r . c o n n e c t (new I n e t S o c k e t A d d r e s s ( hos t , p o r t ) ) ; future . awaitUninterruptibly ( ) ; session = future . getSession ( ) ; } catch ( R unti meIoE xcep tion e ) { System . out . p r i n t l n ( C o n e c t a r e e s u a t a ) ;
2.6. APACHE-MINA
57
44 45 46 47 48 49
import o r g . apache . mina . c o r e . s e r v i c e . I o H a n d l e r A d a p t e r ; import o r g . apache . mina . c o r e . s e s s i o n . I o S e s s i o n ; public c l a s s CmmdcClientHandler extends I o H a n d l e r A d a p t e r { private long m, n ; public CmmdcClientHandler ( long m, long n ) { t h i s .m = m; this . n = n ; } @Override public void s e s s i o n O p e n e d ( I o S e s s i o n s e s s i o n ) { S t r i n g message = m + + n ; System . out . p r i n t l n ( M e s a j u l t r i m i s : +message ) ; s e s s i o n . w r i t e ( message ) ; } @Override public void m e s s a g e R e c e i v e d ( I o S e s s i o n s e s s i o n , O b j e c t message ) { S t r i n g r e s u l t = message . t o S t r i n g ( ) ; i f ( r e s u l t . l e n g t h () >0) { System . out . p r i n t l n ( R e z u l t a t u l e s t e : +r e s u l t ) ; s e s s i o n . c l o s e ( true ) ; } } @Override public void e x c e p t i o n C a u g h t ( I o S e s s i o n s e s s i o n , Throwable c a u s e ) { s e s s i o n . c l o s e ( true ) ; } }
2.6.1
import j a v a . i o . S e r i a l i z a b l e ; public c l a s s CmmdcMessage implements S e r i a l i z a b l e { private long m, n ; private long r e s u l t ; public long getM ( ) { return m; } public void setM ( long m) {
58
10 11 13 14 15 16 17 18 20 21 22 23 24 25 27 28 29 30
t h i s .m = m; } public long getN ( ) { return n ; } public void setN ( long n ) { this . n = n ; } public long g e t R e s u l t ( ) { return r e s u l t ; } public void s e t R e s u l t ( long r e s u l t ) { t h i s . r e s u l t=r e s u l t ; } public S t r i n g t o S t r i n g ( ) { return CmmdcMessage ( + + , +n+ ) ; m } }
Filtrul care transform irul de octeti al datelor serializate obiecte i invers as n s va acceptor.getFilterChain().addLast( "codec", new ProtocolCodecFilter( new ObjectSerializationCodecFactory())); Codurile celor dou clase manipulatoare devin a CmmdcHandler
1 2 4 5 6 7 8 9 11 12 13 14 15 16 17 18 19 20 21 22
import o r g . apache . mina . c o r e . s e r v i c e . I o H a n d l e r A d a p t e r ; import o r g . apache . mina . c o r e . s e s s i o n . I o S e s s i o n ; public c l a s s CmmdcHandler extends I o H a n d l e r A d a p t e r { @Override public void e x c e p t i o n C a u g h t ( I o S e s s i o n s e s s i o n , Throwable c a u s e ) throws E x c e p t i o n { cause . printStackTrace ( ) ; } @Override public void m e s s a g e R e c e i v e d ( I o S e s s i o n s e s s i o n , O b j e c t message ) throws E x c e p t i o n { i f ( message instanceof CmmdcMessage ) { CmmdcMessage msg = ( CmmdcMessage ) message ; App o b j=new App ( ) ; long r e z = o b j . cmmdc( msg . getM ( ) , msg . getN ( ) ) ; msg . s e t R e s u l t ( r e z ) ; s e s s i o n . w r i t e ( msg ) ; } } }
2.6. APACHE-MINA
59
CmmdcClientHandler
1 2 4 5 7 8 9 10 12 13 14 15 16 17 18 19 21 22 23 24 25 26 27 28 30 31 32 33 34
import o r g . apache . mina . c o r e . s e r v i c e . I o H a n d l e r A d a p t e r ; import o r g . apache . mina . c o r e . s e s s i o n . I o S e s s i o n ; public c l a s s CmmdcClientHandler extends I o H a n d l e r A d a p t e r { private long m, n ; public CmmdcClientHandler ( long m, long n ) { t h i s .m = m; this . n = n ; } @Override public void s e s s i o n O p e n e d ( I o S e s s i o n s e s s i o n ) { CmmdcMessage message = new CmmdcMessage ( ) ; message . setM (m) ; message . setN ( n ) ; System . out . p r i n t l n ( M e s a j u l t r i m i s : +message . t o S t r i n g ( ) ) ; s e s s i o n . w r i t e ( message ) ; } @Override public void m e s s a g e R e c e i v e d ( I o S e s s i o n s e s s i o n , O b j e c t message ) { i f ( message instanceof CmmdcMessage ) { CmmdcMessage mesaj = ( CmmdcMessage ) message ; System . out . p r i n t l n ( R e z u l t a t u l e s t e : +mesaj . g e t R e s u l t ( ) ) ; s e s s i o n . c l o s e ( true ) ; } } @Override public void e x c e p t i o n C a u g h t ( I o S e s s i o n s e s s i o n , Throwable c a u s e ) { s e s s i o n . c l o s e ( true ) ; } }
2.6.2
Stergnd serializarea din codul clasei CmmdcMessage suntem obligati s a a denim o clas care realizeaz serializarea, CmmdcMessageCodecFactory a a
1 2 3 4 6 7 8 10 11 12 13 15
public c l a s s CmmdcMessageCodecFactory implements P r o t o c o l C o d e c F a c t o r y { private P r o t o c o l E n c o d e r e n c o d e r ; private P r o t o c o l D e c o d e r d e c o d e r ; public CmmdcMessageCodecFactory ( ) { e n c o d e r = new CmmdcMessageEncoder ( ) ; d e c o d e r = new CmmdcMessageDecoder ( ) ; } public P r o t o c o l E n c o d e r g e t E n c o d e r ( I o S e s s i o n i o S e s s i o n ) throws E x c e p t i o n {
60
16 17 19 20 21 22
cu CmmdcMessageEncoder
1 2 3 4 6 8 9 10 11 12 13 14 15 16 17 18 19 20
core . buffer . IoBuffer ; core . session . IoSession ; f i l t e r . codec . ProtocolEncoderAdapter ; f i l t e r . codec . ProtocolEncoderOutput ;
public c l a s s CmmdcMessageEncoder extends P r o t o c o l E n c o d e r A d a p t e r { public void en c ode ( I o S e s s i o n s e s s i o n , O b j e c t message , P r o t o c o l E n c o d e r O u t p u t out ) throws E x c e p t i o n { i f ( ( message instanceof CmmdcMessage ) == f a l s e ) return ; CmmdcMessage msg = ( CmmdcMessage ) message ; IoBuffer buffer = IoBuffer . a l l o c a t e (24 , false ) ; b u f f e r . putLong ( msg . getM ( ) ) ; b u f f e r . putLong ( msg . getN ( ) ) ; b u f f e r . putLong ( msg . g e t R e s u l t ( ) ) ; buffer . f l i p (); out . w r i t e ( b u f f e r ) ; } }
CmmdcMessageDecoder
1 2 3 4 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
core . buffer . IoBuffer ; core . session . IoSession ; f i l t e r . codec . CumulativeProtocolDecoder ; f i l t e r . codec . ProtocolDecoderOutput ;
public c l a s s CmmdcMessageDecoder extends C u m u l a t i v e P r o t o c o l D e c o d e r { protected boolean doDecode ( I o S e s s i o n s e s s i o n , I o B u f f e r in , P r o t o c o l D e c o d e r O u t p u t out ) throws E x c e p t i o n { i f ( i n . r e m a i n i n g ( ) >= 2 4 ) { long m = i n . getLong ( ) ; long n = i n . getLong ( ) ; long r e s u l t = i n . getLong ( ) ; CmmdcMessage msg = new CmmdcMessage ( ) ; msg . setM (m) ; msg . setN ( n ) ; msg . s e t R e s u l t ( r e s u l t ) ; out . w r i t e ( msg ) ; return true ; } else { return f a l s e ; } } }
2.6. APACHE-MINA
61
Filtrul care transform irul de octeti al datelor serializate obiecte i invers as n s va acceptor.getFilterChain().addLast( "codec", new ProtocolCodecFilter( new CmmdcMessageCodecFactory()));
62
3.1
Java Naming and Directory Interface - JNDI este o interfata de programare (Application Programming Interface - API ) care descrie functionalitatea unui serviciu de nume. Cuvntul servici este utilizat sens comun, entitate care pune la dispozitie a n faciliti de folosire. at Alturi de interfata JNDI, arhitectura JNDI mai contine interfata Service a Provider Interface - SPI. Implementarea interfetei SPI de un furnizor de ser vicii JNDI are ca efect independenta programului Java de furnizorul de servicii JNDI. 63
64
JNDI este implementat de serviciile de nume: Filesystem are ca obiect asocierea dintre numele de ier sau catalog cu s obiectul corespunztor. a DNS - Domain Name System are ca obiect asocierea dintre adresa Internet cu adresa IP. RMI registry utilizat aplicatii RMI, din Java. Are ca obiect asocierea n ntre un nume de serviciu de invocare ale obiectelor la distant cu un a delegat al serviciului (stub). COS - Common Object Service Naming utilizat aplicatii CORBA. Are n ca obiect asocierea ntre numele unui serviciu de invocare ale obiectelor la distanta cu referinta la serviciu. LDAP - Lightweight Directory Access Protocol denete un protocol pens tru accesarea datelor retinute ntr-un catalog LDAP (LDAP directory, information directory). Un catalog LDAP permite retinerea i regsirea s a referintelor obiectelor denite pe un calculator.
Interfata javax.naming.Context
Printr-un context se va elege o multime de asocieri nume - obiect. Corent spunztor unui context, JNDI denete interfata Context, cu metodele a s void bind(String nume,Object object) void rebind(String nume,Object object) void unbind(String nume) Object lookup(String nume) NamingEnumeration list(String nume) Returneaz lista cu nume obiectelor a mpreuna cu tipul lor. NamingEnumeration listBindings(String nume) Returneaz lista cu nume obiectelor a mpreuna cu tipul i locatia acestora. s Specicatiile JNDI prevd denirea unui context initial, implementat prin a clasa javax.naming.InitialContext, clas ce implementeaz interfata Context. a a Constructori.
65
public InitialContext() throws NamingException public void InitialContext(Hashtable<?,?> environment)throws NamingException Pentru crearea contextului initial trebuie specicata clasa care creaz con a textul initial prin parametrul java.naming.factory.initial sau constanta Context.INITIAL CONTEXT FACTORY. Acest parametru se poate da mai multe moduri: n Includerea obiectul Hashtable care apare constructorul clasei InitalContext. n n 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 interiorul programului prin n System.setProperty("java.naming.factory.initial",...); sau System.setProperty(Context.INITIAL_CONTEXT_FACTORY,...); Atribut ierul de proprieti jndi.properties. n s at aceste ultime dou cazuri, contextul initial se creaz prin In a a Context ctx=new InitialContext();
66
Functie de serviciul de nume, clasa care creaz contextul initial este dat a 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 Utiliznd serviciul JNDI Filesystem se creaz un context a a prin intermediul creia se aeaz continutul unui catalog indicat de client. a s a
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 33 34 35 36 37 38 39
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 ( ) ; } 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 ( ) ) ; }
67
41 42 43 44 45 46 48 49 50 51 52 53 55 56 57 58 59 60 61 62 63 64 65 66 67
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
3.1.1
LDAP
LDAP poate privit ca un sistem de gestiune a unei baze de date (ne relational). Baza de date este alctuit din atribute ale cror nume este pre a a a cizat de protocolul LDAP. Punctele de intrare (rdcinile) sunt date de DN (Distinguished Name). a a Uzual DN se denete printr-una din variantele s 1. o=organization,c=country
68
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 i are s acces la LDAP prin precizarea simultan a atributelor DN i cn. a s Implementri gratuite LDAP sunt: a OpenDS (Open Directory Service); ApacheDS (Apache Directory Service). Apache Directory Studio incorporeaz i ofer interfata grac pentru ApacheDS. as a a Vom utiliza produsul OpenDS. Instalarea const din: a 1. dezarhivarea distributiei; 2. se completeaz sursa ierului OpenDS-*\setup.bat cu a s set OPENDS JAVA HOME=... ca prima linie; 3. se execut OpenDS-*\setup.bat. Prin intermediul unei interfete grace a se xeaz a o parola pentru cn=Directory Manager. Fie 1q2w3e aceast parol. a a un punct de intrare, e acesta DN: dc=example,dc=com. Implicit, serverul OpenDS utilizeaz portul 389. a Operatiile de congurare se fac utiliznd interfata grac a componentei a a OpenDS Directory Server Control Panel, lansat prin
set OPENDS_JAVA_HOME=. . . set OpenDS_HOME=. . .\OpenDS-* %OpenDS_HOME%\bat\control-panel.bat
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 i Reset User Password. s
69
Prin aceast component se poate porni i opri serverul OpenDS, ambele a a s operatii putnd executate i apelnd start-ds, stop-ds din catalogul a s a OpenDS HOME\bat. Actiunile care pot ntreprinse de un client care interactioneaz cu serverul a constau n autenticare: datele necesare sunt DN i parola; s conectare (bind) / deconectare (unbind) la un punct de intrare. Conectarea implic crearea unui punct de intrare precizat prin cn; a cutarea / localizarea (lookup) unui punct de intrare precizat prin cn. a Exemplul 3.1.2 Program pentru nregistrarea i tergerea referintei unui obiect s s 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 32 33 34 35 36 37
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 ; 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 ( ) ;
70
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
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 regsit pe baza referintei a din serverul LDAP.
1 2 3 4 5 6 8 9 10 11 12 13 14 15 16 17 18 19 20 21
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 ( ) ; 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 ) ;
71
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
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 ) ) ; } } catch ( NamingException e ) { System . out . p r i n t l n ( LDAPClientCmmdc : +e . g e t M e s s a g e ( ) ) ; } } }
72
4.1
Regsirea obiectelor la distant. Ideea gsirii unui obiect la distant a a a a este c serverul a nscrie un reprezentant al su numit stub (ciot) a ntr-un obiect registry - registru. Acest obiect se creaz cu programul rmiregistry.exe a din distributia java i se lanseaz executie prin s a n start rmiregistry [port] unde valoarea implicit a portului este 1099. Comanda start apartine sisa temului de operare. rmiregistry este un serviciu de nume JNDI. 73
74
Un client obtine din registry stub-ul serverului, prin intermediul cruia a realizeaz comunicatia cu programul server. a Cnd un obiect al clientului apeleaz o metod a unui obiect aat la a a a distanta, se va face, de fapt, un apel de metod a unui obiect care reprezint a a serverul. Acesta este stub-ul, aat pe aceai main cu clientul. s s a Rolul acestui obiect este s a mpacheteze (marshalling) parametrii de apel ai metodei ntr-un mesaj ce va transferat prin retea. Impachetarea se face ntr-o manier independent de calculator, mai precis irurile de caractere i a a s s obiecte sunt transmise ntr-un format care nu se bazeaz pe referinte. Pentru a obiecte se utilizeaz serializarea obiectelor Java. a Serializarea datelor reprezint transformarea acestora din tipuri de date a diferite ntr-un ir de octeti care va transportat prin retea fr interpretare, s aa dar care pstreaz informatiile despre structura initial a datelor. a a a Deserializarea este procesul invers de refacere a structurilor trimise prin retea. Mesajul asamblat este transmis ctre server, care tie s desfac mesajul a s a a receptionat invocnd mod corespunztor metoda referit de client. a n a a Atunci cnd clientul face apel la o metod aat pe o alt main, este a a a a s a invocat stub-ul client, care ncepe conversatia cu serverul. Acest lucru este complet transparent utilizatorului, care are impresia c invoc o metod local. a a a a Metodele apelate la distanta trebuie declarate ca apartinnd unei interfete a ce extinde interfata java.rmi.Remote. Fiecare asemenea metod trebuie s a a arunce o exceptie java.rmi.RemoteException. Obiectele care circul prin a retea trebuie s implementeze interfata java.io.Serializable. a Structura unei aplicatii RMI. O aplicatie RMI este alctuit din trei a a componente: 1. O interfata la distanta (remote) care se declar serviciile puse la n a dispozitie de server; 2. Aplicatia server care poate implementa serviciile interfetei la distant i a s nscrie registry stub-ul corespunztor; n a 3. Aplicatia client ce apeleaz unul sau mai multe servicii ale serverului. a Aplicatia server trebuie s aib acces la clasele interfetei i a celor care a a s o implementeaz. Locatia acestor clase se xeaz prin atributul de nume a a java.rmi.server.codebase. Valoarea atributului trebuie indicat printr-unul din protocoalele http, ftp, file. Utiliznd protocoalele http sau ftp arhiva interfetei i a claselor care o a s implementeaz se depun a ntr-un server Web (Microsoft Internet Interchange
75
Server (IIS), apache-tomcat, respectiv ntr-un server ftp (apache-ftp). moIn mentul lansrii aplicatiei server, serverul http / ftp trebuie s e activ. a a Dac se indic prin protocolul file calea ctre cataloagele care contin a a a clasele interfetei i ale implementrii lor atunci ultimul caracter al cii este /. s a a Din punctul de vedere al executiei sunt implicate componentele: Serviciul de nume rmiregistry; Aplicatia server; Aplicatia client. Aplicatia server i rmiregistry trebuie s ruleze pe acelai calculator. s a s Registrul rmiregistry implementeaz interfata java.rmi.registry.Registry1 . a Metodele oferite sunt: void bind(String numeServiciu, Remote obj )throws RemoteException, AlreadyBoundException, AccessException Inregistreaz registry obiectul obj ce implementeaz interfata Remote a n a sub numele numeServiciu. void rebind(String numeServiciu, Remote obj )throws RemoteException, AccessException Re nregistreaz registry obiectul obj ce implementeaz interfata Remote a n a sub numele numeServiciu. Aceast metod poate apelat doar dac programul care face a a a a nregistrarea se a pe aceai main ca registrul registry. a s s a String[] list()throws RemoteException, AccessException Returneaz o list a tuturor serviciilor a a nregistrate registry. n Remote lookup(String numeServiciu)throws RemoteException, NotBoundException, AccessException Returneaz stub-ul serviciului a nregistrat sub numele numeServiciu. void unbind(String numeServiciu)throws RemoteException, NotBoundException, AccessException Sterge din registru serviciul.
1
76
Localizarea registrului se obtine utiliznd metoda static getRegistry a a a clasei java.rmi.registry.LocateRegistry. public static Registry getRegistry() throws RemoteException public static Registry getRegistry(String host) throws RemoteException public static Registry getRegistry(int port) throws RemoteException public static Registry getRegistry(String host,int port) throws RemoteException Metoda public static Registry createRegistry(int port) throws RemoteException creaz un registru la portul specicat pe calculaa torul local. Ansamblul (rmiregistry, port) determin mod univoc o aplicatie / servia n ciu. Interfata Remote servete la marcarea interfetelor ale cror metode urmeaz s a a a apelate de pe alt main virtual Java. a s a a Un obiect de tip java.rmi.server.UnicastRemoteObject mijlocete transs miterea obiectelor i servete la generarea unui stub unui serviciu. Generarea s s stub-ului unui serviciu se obtine prin intermediul metodei statice static Remote UnicastRemoteObject.exportObject(Remote obj ,int port) Inregistrarea stub-ului unui serviciu descris de interfata IService i im s plementat de clasa ServiceImpl registry se face prin n 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,
77
"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 dorete s foloseasc trebuie s cunoasc : s a a a a calculatorul pe care se gsete obiectul registry i portul la care ascult a s s a serviciul; numele sub care serviciul s-a nregistrat registry; n metodele puse la dispozitie de serviciu.
4.1.1
Exemplicm construirea unei aplicatii RMI care serviciul asigurat de a n server este calculul celui mai mare divizor comun a dou numere naturale. a 2 Pentru exemplele care urmeaz, presupunem c textele surs se retin a a a subcataloage ale unui catalog src, la care are acces doar programatorul, n iar clasele obtinute prin compilare se depun subcataloagele unui catalog n public\classes, accesibil prin retea. Dezvoltarea unei aplicatii se va face pe un calculator. acest sens, celor In 3 componente li se asociaz cataloagele \i - pentru interfata la distanta, \s a pentru componenta server i \c - pentru componenta client. Pai necesari coms s pilrii i desfurrii componentelor aplicatiei se vor realiza prin intermediul a s as a lui ant. Pentru ecare component se vor executa succesiv obiectivele: a 1. Install - creaz o structur de cataloage src i public\classes. a a s 2. Init - creaz structura de cataloage specic aplicatiei. a a 3. Compile - compileaz programele surs. a a Dezvoltarea unei aplicatii RMI const din parcurgerea urmtorilor pai: a a s 1. Denitea interfetei la distanta.
78
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 interfetei retine textul surs a ICmmdc.java catalogul \i\src\cmmdc. n 2. Compilarea i arhivarea interfetei se poate realiza ierul ant-build s s
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 3 4 5 6 7 8
79
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 al programului server CmmdcImpl.java se retine catalogul a n \s\src\server 4. (a) Compilarea programului server; (b) Crearea obiectului registry; (c) Lansarea serverului lucru n se obtin 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
/>
80
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 57 58 59 60 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 } /> </ java> </ target>
81
70
</ project>
Obiectivele Rmi i Server se lanseaz ferestre dos distincte care rmn s a n a a active pe durata de viata a aplicatiei server. Obiectivul Archive creaz arhiva jar necesar desfurrii interfetei i a a as a s a claselor care o implementeaz a ntr-un server http / ftp. Aa cum s s-a amintit mai sus, acest arhiv este preluat de aplicatia server, la a a a lansare, prin atributul java.rmi.server.codebase. 5. Realizarea programului client
1 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 34 35 36 38 39 40 41 42
package c l i e n t ; import cmmdc . ; import j a v a . u t i l . S c a n n e r ; // V a r i a n t a d i r e c t a // i m p o r t j a v a . rmi . r e g i s t r y . ; // V a r i a n t a JNDI import j a v a x . naming . ; 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 =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 Lon g ( 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 ( ) ) ;
82
} } }
43 44 45
Sursa programului client CmmdcClient.java apartine catalogului \c\src\client 6. Compilarea programului client i lansarea acestuia executie. s n
1 2 4 6 7 8 9 10 11 12 14 15 16 17 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
<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 /> <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>
83
4.1.2
Tipare de programare
Fabrica de obiecte
Tiparul fabrica de obiecte va permite crearea dinamic a unui server. Prin a aceea schem, se va crea o clas - fabrica de obiecte - care implementeaz cte a a a a o metod get, ce returneaz o instanta de server. Aceste metode sunt declarate a a ntr-o interfata la distanta. Un client, apelnd o asemenea metod, va instantia serverul dorit i va a a s obtine stub-ul corespunztor. a felul acesta se vor putea utiliza o multime de aplicatii distincte prin In intermediul unui singur rmiregistry. Fiecrei aplicatii corespunde un server, a i instantiat la apelul clientului de metoda get corespunztoare. a Programarea unui server care poate lansat dinamic trebuie s satisfac a a restrictiile: Clasa serverului extinde clasa UnicastRemoteObject. Exist un constructor fr argumente ce arunc exceptia java.rmi.Remote a aa a Exception. Pentru exemplicarea tehnicii de lucru relum aplicatia pentru calculul a celui mai mare divizor comun a dou numere naturale, considernd interfata a a
1 2 3 4 5
Aceas interfata va implementat de clasa ServerCmmdc. Metoda coma a pute este o metod de calcul a celui mai mare divizor comun a dou numere. a a Obiecte de tip ServerCmmdc se creaz, de la distanta prin fabrica de obiecte a FabObiecte, o clas ce implementeaz interfata a a
1 2 3 4 5
84
7 9 11 12 13 14
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 6 8 9 10 11 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
package cmmdc0 ; im po rt j a v a . rmi . ; im po rt j a v a . rmi . s e r v e r . ; im po rt j a v a . rmi . 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 ] ; 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 ( ) ) ; } } }
Aplicatia client se compune din dou clase a 1. RemoteClient Clientul obtine stub-ul serviciului, prin intermediul cruia apeleaz metada a a getCmmdc() a fabricii de obiecte, obtinnd un obiect remote de tip a ServerCmmdc, ce implementeaz interfata la distanta ICmmdc0. a
1 2 3 4 6 8
85
10 12 13 14 15 16 17 18 19 20 21 22 23
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 ( ) ) ; } } }
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 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 ) ; = l o n g m c a n n e r . nextLong ( ) ; =s 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 ) ; } }
86
1. denirea unei interfete la distanta ce va implementat de programul client; 2. programul client ce implementeaz interfata extinde clasa UnicastRemote a Object i are un constructor ce arunc o exceptie java.rmi.RemoteException. s a Extindem aplicatia anterioar cu posibilitatea suplimentar a serverului a a (ServerCmmdc) de a alege metoda de calcul a celui mai mare divizor comun dintre varianta nerecursiv i cea recursiv a algorimului lui Euclid. as a Extindem interfata ICmmdc0 cu metoda public void setMethod(ICallbackCmmdc obj)throws RemoteException;
1 2 3 4 5 6
package cmmdc0 ; im po rt j a v a . rmi . ; p u b l i c i n t e r f a c e ICmmdc0 e x t e n d s Remote{ p u b l i c l o n g compute ( l o n g m, l o n g n ) throws RemoteException ; p u b l i c v o i d setMethod ( ICallbackCmmdc o b j ) throws RemoteException ; }
package cmmdc0 ; im po rt j a v a . rmi . ; im po rt j a v a . rmi . s e r v e r . ; im po rt j a v a . i o . ; 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 ( ) ; }
87
25 26 27 28 29 30 31 32 33 35 36 37 38 39 40 41 42 43 44 45 46
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= %n ; m m ; =n n=r ; } while ( r !=0); return c ; } }
Dup obtinerea stub-ului, clientul apeleaz metoda setMethod a serverului a a remote, care, prin apel invers, apeleaz metoda getMethod din RemoteClient. a Clientul stabilete metoda de calcul i apeleaz metoda compute a lui remote. s s a Programele client devin
1 2 3 4 5 7 8 9 11 13 14 15 16 17 18 19 20 21 22 23 24 25 27 28 29
package cmmdc0 ; im po rt j a v a . rmi . ; im po rt j a v a . rmi . s e r v e r . ; im po rt j a v a . rmi . 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 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 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 ner 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 {
88
30 31 32 33 34 35 36 37 38
i s
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
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 ) ; = l o n g m c a n n e r . nextLong ( ) ; =s 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 instanta a clasei UnicastRemoteObject reprezint un obiect la distanta a care ruleaz permanent, folosind resursele mainii server. a n a s Incepnd cu versiunea JDK 1.2, prin a ntroducerea clasei java.rmi.activation.Activatable i a programului rmid (...\jdk...\bin\rmid.exe) se pot crea s programe care nregistreaz informatii despre obiecte la distant ce vor create a a i executate la cerere. s Invocarea de la distant a unei metode apartinnd unui asemenea obiect a a are ca efect activarea obiectului.
89
Pe ecare main virtual Java exist un grup de activare (activation s a a a group), care realizeaz activarea. Activarea este fcut de un activator. Un a a a activator contine o tabel care face legtura dintre clasa obiectului cu URL-ul a a acestuia i eventual, cu date necesare initializrii obiectului. Atunci cnd actis a a vatorul constat c nu exist un obiect referit, face apel la grupul de activare a a a care va produce activarea obiectului. Din punctul de vedere al clientului utilizarea mecanismului de activare la distanta nu implic modicri. Modicrile intervin numai din punctul de a a a vedere al serverului i al s nregistrrii sale. a Relum aplicatia dezvoltat la a a nceputul capitolului, privind calculul celui mai mare divizor comun a dou numere naturale. a Aplicatia server este compus din dou clase a a 1. o clasa ce implementeaz interfata ICmmdc : CmmdcActivabil; a 2. clasa Setup, cu metoda main, care face posibil mecanismul de activare a i s nscrie serviciul registry. Aceast clas este preluat din tutorialul n a a a dedicat activrii a documentatiei ce ete distributia Java. a nsot s Clasa ce implementeaz interfata la distanta trebuie a 1. s extind clasa Activatable; a a 2. s aib un constructor ce are doi parametrii a a (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 initializare a obiec cazul nostru, acest parametru nu va folosit. tului activabil. In Codul surs al clasei CmmdcActivabil este a
1 2 3 4 6 7 9 10 11 12 14 15
package acmmdc ; im po rt j a v a . rmi . ; im po rt j a v a . rmi . a c t i v a t i o n . ; im po rt cmmdc . ; 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 ) { . . . } }
90
Clasa Setup necesit o serie de date furnizare ca proprieti: a at 1. drepturile de securitate ale grupului de activare myactivation.policy=group.policy; cu continutul
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 din classpath-ul a local; 3. localizarea (URL) clasei ce implementeaz interfata a myactivation.impl.codebase; 4. localizarea unui ier cu date de initializare a obiectului activabil s myactivation.file; 5. numele sub care nregistreaz serviciul registry a n myactivation.name. Programul Setup realizeaz: a 1. Construirea unui descriptor al grupului de activare. Grupul de activare este un container ce gestioneaz obiectele activabile continute. a 2. Inregistrarea descriptorului grupului de activare i obtinerea unui idens ticator al grupului de activare. 3. Construirea descriptorului de activare. Trebuie cunoscute idendicatorul grupului de activare; numele clasei ce implementeaz interfata la distanta; a localizarea (URL) clasei ce implementeaz interfata la distanta; a
91
obiectul de tip MarshalledObject, cu datele de initializare a obiec tului activabil. 4. Inregistrarea descriptorului de activare, urma creia se obtine stub-ul n a obiectului activabil. 5. Inregistrarea stub-ului mpreun cu numele serviciului registry. a n Codul clasei setup este
1 3 4 5 6 8 10 12 14 15 16 17 18 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
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 > ) ; 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 ( ) ) {
92
47 48 50 51 53 54 55 57 58 59 60 61 62
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 programe CmmdcActivabil.java i respectiv Setup.java a s sunt catalogul \c\src\acmmdc. n Lansarea serverului executie const din n a 1. Pornirea demon-ului rmid start rmid -J-Djava.security.policy=rmid.policy -J-Dmyactivation.policy=group.policy unde rmid.policy este
grant { // allow activation groups to use certain system properties permission com.sun.rmi.rmid.ExecOptionPermission "-Djava.security.policy=${myactivation.policy}"; permission com.sun.rmi.rmid.ExecOptionPermission "-Djava.class.path=no_classpath"; permission com.sun.rmi.rmid.ExecOptionPermission "-Dmyactivation.impl.codebase=*"; permission com.sun.rmi.rmid.ExecOptionPermission "-Dmyactivation.file=*";};
4.2. CORBA
93
3. Lansarea programului Setup set classpath=\s\public\classes\cmmdc.jar;\s\public\classes java -Djava.rmi.server.codebase=file:/s/public/classes/ -Dmyactivation.impl.codebase=file:/s/public/classes/ -Dmyactivation.name=CmmdcServer -Dmyactivation.file="" -Dmyactivation.policy=group.policy acmmdc.Setup acmmdc.CmmdcActivabil Localizarea (URL) interfetei la distanta se precizeaz prin a java.rmi.server.codebase; Drept client se utilizeaz programul realizat sectiunea 4.1. a n
4.2
CORBA
Retelele de calculatoare sunt eterogene timp ce majoritatea interfetelor n de programare a aplicatiilor sunt orientate spre platforme omogene. Pentru a facilita integrarea unor sisteme dezvoltate separat, ntr-un singur mediu distribuit eterogen, OMG (Object Management Group consortiu cuprinznd peste 800 de rme) a elaborat standardul CORBA (Common Oba ject Request Broker Arhitecture): un cadru de dezvoltare a aplicatiilor dis tribuite medii eterogene. n La CORBA au aderat toate marile rme de software - cu exceptia Microsoft, rm care a dezvoltat propriul su model DCOM (Distributed Component a a Object Model), incompatibil CORBA. Aplicatia server se nregistreaz a ntr-un Object Request Broker (ORB) sub un nume simbolic - nume servici. Pe baza acestui nume de servici, un client accesnd ORB va avea acces la functiile oferite de aplicatia server. a ORB este un pachet de servicii, independent de aplicatii, dar care permit aplicatiilor s interactioneze prin retea. ORB face parte din middleware un a intermediar ntre softul de retea i cel de aplicatie. s 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. Distributia jdk ofer un ORB utilizabil Java sub forma unui servici a n JNDI.
94
CORBA face o separare ntre interfata unui obiect i implementarea sa i s s folosete un limbaj neutru pentru denirea interfetelor: IDL -- Interface s Definition Language. IDL permite realizarea descrierii de interfete independent de limbajul de programare i de sistemul de operare folosit. O interfat IDL denete legtura s a s a dintre client i server. s
4.2.1
Firma Oracle - Sun Microsystems a dezvoltat o solutie prin care interfetele RMI pot implementate pentru a putea accesate ca obiecte CORBA. Aceasta este cunoscut sub numele de solutia RMI-IIOP, concretizat printr-o serie de a a acest fel nu mai este necesar utilizarea limbapachete din distributia jdk. In jului IDL pentru descrierea interfetelor la distanta. Instrumente necesare utilizrii solutiei RMI-IIOP: a compilatorul rmic Optiunea -iiop genereaza stub-ul i legtura (tie) din partea serverului. s a Cu optiunea -d se specic catalogul care aceste iere sunt scrise. a n s serviciul ORB care asigur regsirea resurselor CORBA. Acest server se a a lanseaz executie prin a n start orbd -ORBInitialPort [port] Programele orbd, rmic sunt distributia jdk. n
4.2. CORBA
95
6 7 9 10 11 13 14
6 7 8 9 10 11 12 13 14 15 16 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
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 ) ; 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 i CmmdcServer.java. s 5. Generarea stub-ului cmmdc. ICmmdc Stub.class corespunztor interfetei a ICmmdc i a ierului Tie cmmdciiop. CmmdcImpl Tie.class corespunztor s s a clasei CmmdcImpl. Acestea se obtin rulnd utilitarul rmic - din distrubutia a Java cu optiunea -iiop rmic -iiop cmmdciiop.CmmdcImpl
96
6. Pornirea serverului CORBA de regsire a serviciilor a start orbd -ORBInitialPort 1050 7. Lansarea serverului executie. n Activitile legate de server se obtin prin ant cu ierul build at s
1 2 4 6 7 8 9 10 11 12 13 14 16 17 18 19 20 21 22 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
<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 /> <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 >
4.2. CORBA
97
51 52 53 55 56 57 58 59 60 61 62 63 64
<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 7 9 10 11 12 13 14 15 16 18 19 20 21 22 23 24 25 26 27 28 30 31 32 33 35 36 37
package cmmdciiop ; import j a v a . rmi . ; import j a v a x . rmi . ; import j a v a . n e t . MalformedURLException ; import j a v a x . naming . ; import j a v a . u t i l . S c a n n e r ; import cmmdc . ; 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 ; 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 Lon g ( 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 ) ;
98
38 39 40 41 42 43 44 45
9. Compilarea i lansarea clientului executie. Clientul trebuie s dispun s n a a de ierul stub (cmmdc. ICmmdc Stub.class) i bine eles de interfata s s nt ICmmdc.jar. Fiierul buildle pentru executarea clientului: s
1 2 4 6 7 8 9 10 11 12 13 14 15 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
<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 stubl 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= stubc 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 /> <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 stubl o c a t i o n } i n c l u d e s= ${ stubc 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 />
4.2. CORBA
99
43 45 46 47 48 49 50 52 53 54 55 56 57 58 59 60 61
</ 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 sectiuni este prezentarea dezvoltrii unei aplicatii pe baza a unei interfete bazat pe IDL. Pentru dezvoltarea aplicatiilor limbajul de programare Java, translatarea n interfetei IDL Java se realizeaz cu utilitarul idlj din distributia jdk. n a Corespondenta ntre entitile IDL i Java este dat Tabelul 4.1 at s a n Legarea cererii unui client de codul serviciului care satisface cererea utilizeaz componenta CORBA Portable Object Adapter (POA). a
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 ) ; }; };
100
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
Salvm acest text a ntr-un ier denumit Cmmdc.idl. s Cmmdc va numele interfetei utilizat de un client i implementat s de server. Serviciul contine o singur metod cmmdc. a a (b) Translatarea interfetei Java n idlj -fall Cmmdc.idl Programul idlj creaz un subcatalog CmmdcApp cu un pachet Java CmmdcApp a continnd ierele: a s Cmmdc.java CmmdcPOA.java ; CmmdcOperations.java; CmmdcStub.java; CmmdcHelper.java;
4.2. CORBA
101
CmmdcHolder.java. 2. Realizarea programelor server. Punem evidenta programul servant n CmmdcImpl.java ce implementeaz interfata Cmmdc. a
1 2 4 5 7 8 9 11 12
im po rt CmmdcApp . ; im po rt o r g . omg .CORBA. ; 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 ) { . . . } }
i programul CmmdcServer.java, care s nscrie registrul ORB referintele n servantului. Activitile ce trebuie at ntreprinse sunt declarate prin comentarii textul surs al programului n a
1 2 3 4 5 7 8 9 10 11 13 14 15 16 17 19 20 22 23 24 26 27 28 29 31 32 33 34
im po rt im po rt im po rt im po rt im po rt
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 ) ;
102
36 38 39 40 41 42 43 44 45 46
. . . );
Aceast clas corespunde unui ablon de programare adaptat exemplului a a s acest caz numele serviciului inregistrat ORB va Cmmdctratat. In n Service. Evidenta numelor serviciilor CORBA nregistrate ORB este n fcut de serviciul NameService. a a 3. Realizarea programului client CmmdcClient.java:
1 2 3 4 5 7 8 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
im po rt im po rt im po rt im po rt im po rt
CmmdcApp . ; o r g . omg . CosNaming . ; o r g . omg . CosNaming . NamingContextPackage . ; o r g . omg .CORBA. ; java . u t i l . Scanner ;
p u b l i c c l a s s CmmdcClient { s t a t i c Cmmdc 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 [ ] ) { 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 c a n n e r . nextLong ( ) ; =s 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 ) ; }
4.2. CORBA
103
39 40
} }
Din nou clasa client contine ablonul de accesare a unui serviciu CORBA. s Programele se compileaz a javac CmmdcApp\*.java 4. Pornirea serviciului de intregistrare a numelor cu programul orbd.exe din distributia jdk. start orbd -ORBInitialHost localhost -ORBInitialPort 1050 5. Pornirea programului server prin start java CmmdcServer -ORBInitialHost localhost -ORBInitialPort 1050 6. Lansarea programului client prin java CmmdcClient -ORBInitialHost localhost -ORBInitialPort 1050
im po rt im po rt im po rt im po rt
104
9 10 11 12 13 15 16 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 34 35 37 38 39 40 42 43 44 45 46 48 49 50 51 52 53 54 55 56
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 p e r s i s t e n t P O A . a c t i v a t e o b j e c t ( cmmdcImpl ) ; // Pas 5 : // // Numele // Numele F i x a r e a c o n t e x t u l u i RootNaming s i l e g a r e a de numele s e r v a n t u l u i s e r v i c i u l u i de nume : NameService s e r v a n t u l u i PersistentCmmdcServer
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 4 6 7 8
im po rt im po rt im po rt im po rt
4.2. CORBA
105
10 11 12 13 14 15 16 17 18 19 20 22 23 24 25 26 27 28 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
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 canner . nextInt ( ) ; =s 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 ) ) ; } catch ( Exception e ) { System . e r r . p r i n t l n ( E x c e p t i o n i n P e r s i s t e n t C l i e n t . j a v a . . . + e . getrMessage ( ) ) ; } } }
Serverul trebuie s e pe acelai calculator pe care ruleaz orbd. Exea s a cutarea aplicatiei presupune: 1. Pornirea serviciului de intregistrare a numelor cu programul orbd.exe din distributia jdk. orbd -ORBInitialPort 1050 -serverPollingTime 200 2. Activarea serverului: (a) Se lanseaz utilitarul servertool a servertool -ORBInitialPort 1050 (b) Se nregistreaz serverul a mpreun cu numele serviciului pe care a l ndeplinete: s
106
servertool > register -server PersistentServer -applicationName PersistentCmmdcServer -classpath cale_catre_fisierele_server\ Indeplinirea actiunii de nregistrare a serverului este indicat printr-un mesaj de forma server registered (serverid=257). Alte comenzi servertool Comanda servertool> servertool> servertool> servertool> Semnicatie shutdown -serverid 257 Oprirea serviciului unregister -serverid 257 Stergerea serviciului quit Inchiderea utilitarului help
Observatie 4.2.1 Dac se utilizeaz referinta a a c:\Program Files\Java\jdk1.7.0 *\bin n variabila de sistem PATH (n loc de c:\Progra 1\Java\jdk1.7.0 *\bin) atunci apelarea serviciilor orbd i servertool se va face prin s
c:\Progra~1\Java\jdk1.7.0_*\bin\orbd -ORBInitialPort 1050 -serverPollingTime 200 c:\Progra~1\Java\jdk1.7.0_*\bin\servertool -ORBInitialPort 1050
5.1
JMS denete un cadru de programare Java (API) pentru realizarea aplicatiilor s bazate pe comunicatii asincrone. Exist mai multe implementri JMS, dintre a a care semnalm: a Open Message Queue a rmei Oracle. Numele anterior al produsului a fost Java Message Queue 107
108 ActiveMQ realizat de fundatia apache. a qpid realizat de fundatia apache. a O aplicatie JMS este alctuit din a a
un furnizor JMS (provider JMS) : un sistem de mesagerie ce implementeaz specicatiile JMS; a client JMS : aplicatie Java care trimite i receptioneaz mesaje; s a mesaje : obiecte utilizate schimbul de informatii de clienti JMS; n obiecte administrator : obiecte (resurse) create de administrator pentru a utilizate de clientii JMS, precum fabrica de conexiuni, obiectele destinatie mpreun cu resursele lor. a Modele de comunicatie: Comunicatii punctuale : Un mesaj este generat de un productor (exped a itor) i la care va avea acces un singur consumator (destinatar). Mesajul s este depus ntr-o coad, de unde este preluat de ctre consumatorul care a a s-a legat de coad. Dac de coad nu se leag nici un consumator, atunci a a a a mesajul este pstrat coad. a n a Comunicatii axate pe subiect (topic) : Mesajele sunt depuse (publicate) destinatii specice subiectului. Consumatorii ce au subscris la acel n subiect au acces la mesajele respective. Mai multi productori pot genera a mesaje specice unui subiect, mesaje care pot accesate de consumatorii care au subscris subiectului. Structura unui mesaj Un mesaj este alctuit din a Antet (header) : contine informatii pentru identicarea destinatiei ct i a s pentru identicarea mesajului. Proprieti : au caracter optional i sunt sub forma (nume, valoare). at s Proprietile ajut consumatorii s selecteze mesajele. at a a Corpul mesajului : optional. Potrivit specicatiilor JMS exist 6 tipuri a de mesaje. Message : mesaj fr corp; aa
109
StreamMessage : corpul mesajului contine un ux Java de date de tip predenit; ByteMessage : MapMessage : corpul mesajului contine o familie de perechi (nume, valoare); TextMessage : corpul mesajului contine un string; ObjectMessage : corpul mesajului contine un obiect serializat.
5.2
Instalarea. Functie de resursa descrcat, mediul Windows, instalarea a a n const din a Se dezarhiveaz ierul openmq* *-installer-WINNT.zip i se lanseaz a s s a n executie programul de instalare. s a Se dezarhiveaz ierul openmq* *-binary-WINNT.zip i se xeaz atributele a s ierului etc\mq\imqenv.conf. s Lansarea serviciului JMS. Orice aplicatie JMS necesit functionarea a serviciului JMS. Serviciul JMS se instaleaz prin a imqbrokerd -tty Optiunea -tty are ca efect aarea mesajelor pe ecran. Functionarea corect s a este indicat prin mesajul a imqbroker@hostname:7676 ready Dac se dorete schimbarea portului atunci se folosete optiunea -port a s s port. Pe un calculator pot coexista mai multe servicii JMS doar dac folosesc a acest caz, lansarea unui nou serviciu porturi distincte i au nume diferite. In s se face prin imqbrokerd -tty -port port -name name Cu utilitarul imqsvcadmin putem dezinstala : imqsvcadmin remove verica : imqsvcadmin query instala : imqsvcadmin install
110
serviciul JMS ca serviciu Windows. Dezinstalarea i instalarea are efect odat s a cu repornirea calculatorului. Compilarea i executarea unui program necesit completarea variabilei s a sistem classpath cu ierele s JMS HOME\lib\jms.jar JMS HOME\lib\imq.jar
5.3
Apache ActiveMQ
Instalarea se face dezarhivnd ierul descrcat a s a ntr-un catalog ACTIVEMQ HOME. Acest ier este specic sistemului de operare utilizat, Windows sau Linux. s Lansarea serverului JMS se obtine prin
set JAVA_HOME=. . . set ACTIVEMQ_HOME=. . . %ACTIVEMQ_HOME%\bin\activemq
cazul unui calculator izolat este nevoie de instalarea driver-ului Microsoft In Loopback Adaptor care simuleaz existenta functionrii unei plci de retea a a a active. Distributia apache-activemq-5.*.* contine, ca exemplu, clasa Embedded Broker.java care lanseaz serverul JMS lucru. a n Compilarea unui program necesit prezenta variabila de sistem classpath a n a referintei ctre ierul ACTIVEMQ HOME\activemq-all-*.*.*.jar. Pentru a s executie, variabila de sistem classpath nevoie s contin referintele ctre a a a ierele jar din catalogul ACTIVEMQ HOME\lib. s
5.4
Semnalm dou modaliti de programare / generare / regsire a obiectelor a a at a administrator: Programat: obiectele administrator se instantiaz prin API-ul oferit de a produsul informatic; Prin JNDI. Codul surs al programelor este independent de furnizorul a de servicii de mesagerie. Elementele specice se declar iere de a n s proprieti. at
111
5.4.1
Trimiterea unui mesaj necesit: a 1. Generarea unei fabrici de conexiuni. Fabrica de conexiuni este un obiect administrator. Aceast operatie este specic distributiei JMS. a a cazul de fata folosim obiectele create prin MessageQueue. In Se poate obtine prin ConnectionFactory cf= new com.sun.messaging.ConnectionFactory(); Clasa com.sun.messaging.ConnectionFactory contine metoda setProperty( String name, String value) prin intermediul creia a se precizeaz calculatorul i portul furnizorului de servicii JMS, a s xnd atributele "imqBrokerHostName" i respectiv "imqBrokerHostPort". a s Utiliznd apache-activemq, fabrica de conexiuni se obtine prin a org.apache.activemq.ActiveMQConnectionFactory cf= new org.apache.activemq.ActiveMQConnectionFactory ("tcp://host:61616"); 2. Generarea conexiunii. Se realizeaz prin a Connection conn=cf.createConnection(); Pentru realizarea acestui obiectiv se utilizeaz metoda createConnection, a dup caz, dintr-una din clasele a class ConnectionFactory{ Connection createConnection() throws JMSException; Connection createConnection(String userName,String password) throws JMSException; } class QueueConnectionFactory{ QueueConnection createQueueConnection() throws JMSException; QueueConnection createQueueConnection(String userName, String password) throws JMSException; }
112
class TopicConnectionFactory{ TopicConnection createTopicConnection() throws JMSException; TopicConnection createTopicConnection(String userName, String password) throws JMSException; } unde Connection, QueueConnection, TopicConnection sunt interfete din javax.jms. Amintim urmtoarele metode ale unei interfete Connection a interface Connection{ Session createSession(boolean transacted, int acknowledgeMode) throws JMSException; void start() throws JMSException; void close() throws JMSException; } interface QueueConnection{ QueueSession createQueueSession(boolean transacted, int acknowledgeMode) throws JMSException; void start() throws JMSException; void close() throws JMSException; } interface TopicConnection{ TopicSession createTopicSession(boolean transacted, int acknowledgeMode) throws JMSException; void start() throws JMSException; void close() throws JMSException; } Un obiect ce implementeaz interfata Connection asigur legtura cliena a a tului cu furnizorul JMS. Acest obiect este creat de fabrica de conexiuni. Un client JMS trebuie s a nchid conexiunile create. a Metoda start() asigur pornirea sau repornirea conexiunii vederea a n receptionrii mesajelor sosite. a 3. Crearea unei sesiuni de lucru se face cu o metod createSession(). a Session session=conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
113
Primul argument asigur (true) sau nu (false) caracterul indivizibil al a unitii de lucru, adic al unei sesiuni. at a Al doilea argument indic modul de conrmare al receptrii mesajului. a a Un obiect de tip Session denete un context format dintr-un singur r s de executie care are loc producerea i consumul de mesaje. n s Sunt denite interface Session{ | MessageProducer createProducer(Destination destination); | MessageConsumer createConsumer(Destination destination); | Message createMessage(); | TextMessage createTextMessage(); | TextMessage createTextMessage(String s); | StreamMessage createStreamMessage(); | MapMessage createMapMessage(); | ObjectMessage createObjectMessage(); | ObjectMessage createObjectMessage(Serializable object); | BytesMessage createBytesMessage(); | } |->interface QueueSession{ | QueueSender createQueueSender(Queue queue); | QueueReceiver createQueueReceiver(Queue queue); | } |->interface TopicSession{ TopicPublisher createPublisher(Topic topic); TopicSubscriber createSubscriber(Topic topic); TopicSubscriber createDurableSubscriber(Topic topic, String name); } 4. Generarea obiectului destinatie. cazul comunicatiilor punctuale obiectul destinatie este de tip Queue, In iar crearea se face prin Destination numeDestinatie=sesssion.createQueue(String numeCoada) iar pentru comunicatii axate pe subiect obiectul destinatie, de tip Topic se instantiaz prin a
114
Destination numeDestinatie=sesssion.createTopic(String numeSubiect) Sunt denite arborescentele: interface Destination | |->interface Queue | |->interface Topic class Destination implements Destination | |->class Queue implements Destination, Queue, Serializable | |->class Topic implements Destination, Topic, Serializable Utiliznd Oracle-Open Message Queue obiecte de tip Queue sau Topic a se pot crea i prin s Queue q=new com.sun.messaging.Queue(String numeCoada); Topic t=new com.sun.messaging.Topic(String numeSubiect); 5. Generarea productorului de mesaje. Se realizeaz prin a a MessageProducer producer=session.createProducer(obiectDestinatie); Sunt denite interfetele interface MessageProducer{ void send(Message mesaj); } interface QueueSender{ void send(Message mesaj); } interface TopicPublisher{ void publish(Message mesaj); } 6. Generarea mesajelor. Un mesaj de tip TextMessage se poate crea prin
115
TextMessage m=session.createTextMessage(); m.setText(string); 7. Expedierea mesajelor se face cu metoda send(...) a productorului de a mesaje. Exemplul 5.4.1 Clasa urmtoare genereaz ntr-un r de executie, un numr a a a de mesaje de tip TextMessage ntr-o comunicatie punctual. Sfritul expe a a s dierii mesajelor se indic prin generarea unui mesaj de tip Message. Numrul a a mesajelor este indicat de un parametru al constructorului.
1 3 4 5 7 8 9 10 12 13 14 15 16 18 19 20 21 22 23 25 26 27 28 29 30 32 34 36 37 38 39 40 41 42 43
import j a v a x . jms . ; 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 { // V a r i a n t a OracleOpen Message Queue 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 ( ) ; // s e t P r o p e r t y e s t e metoda a c l a s e i // com . sun . m e s s a g i n g . QueueConnnectionFactory // ce i m p l e m e n t e a z a i n t e r f a t a QueueConnectionFactory // dar nu a i n t e r f e t e i 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 ) ; // 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 ( t c p : / / l o c a l h o s t : 6 1 6 1 6 ) ; C o n n e c t i o n conn=c f . c r e a t e C o n n e c t i o n ( ) ; S e s s i o n s e s s i o n=conn . c r e a t e S e s s i o n ( f a l s e , S e s s i o n .AUTO ACKNOWLEDGE) ; D e s t i n a t i o n q=s e s s i o n . c r e a t e Q u e u e ( queueName ) ; MessageProducer p r o d u c e r=s e s s i o n . c r e a t e P r o d u c e r ( q ) ; TextMessage m e s s i o n . c r e a t e T e x t M e s s a g e ( ) ; =s f o r ( i n t i =0; i <n ; i ++){ m. s e t T e x t ( H e l l o +i ) ; p r o d u c e r . send (m) ; } // indicam s f a r s i t u l t r i m i t e r i i m e s a j e l o r p r o d u c e r . send ( s e s s i o n . c r e a t e M e s s a g e ( ) ) ; session . close ();
116
44 45 46 47 48 49 50 51
5.4.2
Primele patru actiuni sunt identice cu cele de la trimiterea unui mesaj, adic a 1. Generarea unei fabrici de conexiuni. 2. Generarea conexiunii. 3. Crearea unei sesiuni de lucru. 4. Generarea obiectului destinatie. 5. Generarea consumatorului de mesaje. Se realizeaz prin a MessageConsumer consumer=session.createConsumer(q); q desemnnd obiectul destinatie. a Sunt denite interfetele interface MessageConsumer{ | Message receive(); | Message receive(long timeout); | Message receiveNoWait(); | } |-> interface QueueReceiver | |-> interface TopicSubscriber 6. Receptia mesajelor se face cu una din metodele consumatorului de mesaje: Message receive() Message receive(long timeout)
117
Message receiveNoWait() Exemplul 5.4.2 Receptia de tip sincron a mesajelor ntr-un r de executie este efectuat de clasa urmtoare: a
1 3 4 6 7 8 10 11 12 13 14 15 16 17 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
import j a v a x . jms . ; 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 { // V a r i a n t a OracleOpen Message Queue 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 ( ) ; // s e t P r o p e r t y e s t e metoda a c l a s e i QueueConnnectionFactory // ce i m p l e m e n t e a z a i n t e r f a t a QueueConnectionFactory // dar nu e s t e a i n t e r f e t e i . // 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 ) ; // 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 ( t c p : / / l o c a l h o s t : 6 1 6 1 6 ) ; C o n n e c t i o n conn=c f . c r e a t e C o n n e c t i o n ( ) ; S e s s i o n s e s s i o n=conn . c r e a t e S e s s i o n ( f a l s e , S e s s i o n .AUTO ACKNOWLEDGE) ; D e s t i n a t i o n q=s e s s i o n . c r e a t e Q u e u e ( queueName ) ; MessageConsumer consumer=s e s s i o n . createConsumer ( q ) ; conn . s t a r t ( ) ; 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 ; } session . close (); conn . 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 ) ; } }
118
1 2 3 4 5 6 7 8 9 10 11 12 13 14
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.4.3
Receptia asincron a mesajelor presupune implementarea interfetei a MessageListener ce contine o singur metod a a public void onMessage(Message mesaj); care xeaz prelucrarea mesajului. a Metoda MessageConsumer.setMessageListener(MessageListener obj ) xeaz obiectul ce implementeaz interfata Messagelistener. a a Astfel, caracterul asincron const din faptul c mesajele sunt preluate de a a asculttor - adic obiectul ce implementeaz interfata MessageListener i nu a a a s de clientul JMS. Exemplul 5.4.4 In ideea exemplelor anterioare, un consumator de tip asincron al mesajelor este dat n clasa urmtoare: a
1 2 3 5 6 7 9 10 11 12 13 14 15 16 17
import j a v a x . jms . ; 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 { // V a r i a n t a OracleOpen Message Queue 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 ( ) ; // s e t P r o p e r t y e s t e metoda a c l a s e i QueueConnnectionFactory // ce i m p l e m e n t e a z a i n t e r f a t a QueueConnectionFactory // dar nu e s t e a i n t e r f e t e i . // c f . s e t P r o p e r t y ( imqBrokerHostName , h o s t ) ;
119
18 20 21 22 23 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
// c f . s e t P r o p e r t y ( imqBrokerHostPort , 7 6 7 6 ) ; // 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 ( t c p : / / l o c a l h o s t : 6 1 6 1 6 ) ; C o n n e c t i o n conn=c f . c r e a t e C o n n e c t i o n ( ) ; S e s s i o n s e s s i o n=conn . c r e a t e S e s s i o n ( f a l s e , S e s s i o n .AUTO ACKNOWLEDGE) ; D e s t i n a t i o n q==s e s s i o n . c r e a t e Q u e u e ( queueName ) ; MessageConsumer consumer=s e s s i o n . 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 ) ; conn . s t a r t ( ) ; t e x t L i s t e n e r . run ( ) ; conn . 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 ) ; } }
mpreun cu asculttorul a a
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 18 19 20 21
import j a v a x . jms . ; 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 { System . out . p r i n t l n (m. g e t T e x t ( ) ) ; } 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 ( ) { while ( ! s f a r s i t ) ; } }
5.4.4
Publicarea mesajelor
Publicarea mesajelor corespunztoare unui subiect se face asemntor cu a a a transmiterea mesajelor comunicatia punctual, dar folosind instante ale n a claselor dedicate acestui tip de comunicatie. Exemplul 5.4.5
120
1 3 4 5 7 8 9 10 12 13 14 15 16 17 18 20 21 22 23 25 26 27 28 29 31 32 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
import j a v a x . jms . ; 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 ) { 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 { // V a r i a n t a OracleOpen Message Queue 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 ) ; // 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 ( t c p : / / l o c a l h o s t : 6 1 6 1 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 ( ) ; TopicSession session = 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 t = session . createTopic ( subiect ) ; 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 ) ; // Topic t=new com . sun . m e s s a g i n g . Topic ( s u b i e c t ) ; // T o p i c P u b l i s h e r p u b l i s h e r=s e s s i o n . c r e a t e P u b l i s h e r ( t ) ; TextMessage m e s s i o n . c r e a t e T e x t M e s s a g e ( ) ; =s f o r ( i n t i =0; i <n ; i ++){ m. s e t T e x t ( Despre +s u b i e c t+ +i ) ; p r o d u c e r . send (m) ; // p u b l i s h e r . p u b l i s h (m) ; } p r o d u c e r . send ( s e s s i o n . c r e a t e M e s s a g e ( ) ) ; // p u b l i s h e r . p u b l i s h ( s e s s i o n . c r e a t e M e s s a g e ( ) ) ; session . close (); conn . 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 ) ; } }
Varianta comentat este o solutie specic implementrii Oracle-Open Mesa a a sage Queue.
121
5.4.5
Dac t este obiectul de tip Destination, clientii se aboneaz - subscriu a a unui subiect prin TopicSubscriber consumer=session.createSubscriber((Topic)t); Subscrierea este valabil atta timp ct clientul este activ. Pentru a primi a a a toate mesajele specice subiectului, chiar i cnd clientul este inactiv, acesta s a trebuie s e durabil, adic crearea consumatorului s se fac prin a a a a conn.setClientID("myID"); TopicSubscriber consumer= session.createDurableSubscriber((Topic)t,"nameClient"); ambele cazuri, clientul primete doar mesajele publicate din momentul subIn s scrierii. Exemplul 5.4.6
1 3 4 5 6 8 9 10 11 12 14 15 16 17 18 19 20 22 23 24 25 27 28 29 30 31 32
import j a v a x . jms . ; 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 { // V a r i a n t a OracleOpen Message Queue 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 ) ; // 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 ( t c p : / / l o c a l h o s t : 6 1 6 1 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 t = session . createTopic ( subiect ) ; T o p i c S u b s c r i b e r consumer=
122
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
s e s s i o n . c r e a t e D u r a b l e S u b s c r i b e r ( ( Topic ) t , c l i e n t N a m e ) ; conn . s t a r t ( ) ; 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 : + g e t T e x t ( ) ) ; m. } else break ; } session . close (); conn . 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 ( ) ) ; } } }
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.4.6
Obiectele administrator coada sau topic, care retin mesajele corespunztoare a se precizeaz iere de proprieti - jndi.properties. Aceste iere sunt specia n s at s ce produsului de mesagerie folosit (Oracle - Open Message Queue, apache ActiveMQ, qpid, etc.) Varianta Oracle-Open Message Queue
1 2 3
123
5 7 8 9 11 12 13
# 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
acest caz este nevoie de crearea prealabil a obiectelor corespunztoare In n a conexiunii, a cozii (queue) i a subiectului (topic). Aceaste obiecte se creaz s a cu utilitarul imqobjmgr din distributia Oracle-Open Message Queue. Obiectele se pot crea cu ierul de comenzi: s
1 2 3 4 5 6 7 8 9 10 11 12 13
s e t PATH : \mq\ b i n ;%PATH =d % 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 : \mq\ b i n ;%PATH =d % 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
Varianta ActiveMQ
1 2 4 5 7 8 9
j a v a . naming . f a c t o r y . i n i t i a l = o r g . apache . a c t i v e m q . j n d i . A c t i v e M Q I n i t i a l C o n t e x t F a c t o r y # 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 j a v a . naming . p r o v i d e r . u r l = t c p : // l o c a l h o s t : 6 1 6 1 6 # 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
124
11 12 13
Varianta qpid :
1 2 4 5 6 7 9 10 11 13 14
j a v a . naming . f a c t o r y . i n i t i a l = o r g . apache . q p i d . j n d i . P r o p e r t i e s F i l e I n i t i a l C o n t e x t F a c t o r y # r e g i s t e r some c o n n e c t i o n f a c t o r i e s # c o n n e c t i o n f a c t o r y . [ jndiname ] = [ ConnectionURL ] c o n n e c t i o n f a c t o r y . ConnectionFactory = amqp: // g u e s t : g u e s t @ c l i e n t i d / t e s t ? b r o k e r l i s t= t c p : // l o c a l h o s t : 5 6 7 2 # 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 # t o p i c . [ jndiName ] = [ physicalName ] t o p i c . t o p i c = mytopic
Relum aplicatiile anterioare privind transmiterea / receptia unui mesaj a prin comunicatie punctual utiliznd o coad i publicarea i receptionarea a a a s s unui mesaj prin comunicatie bazat pe subiect a ntr-o variant independentent a a de suportul middleware de serviciu de mesagerie folosit. Regsirea resurselor a gestionate de serviciul de mesagerie sa va face utiliznd JNDI. 1 . a
5.4.7
Aplicatia este alctuit din clasele MsgHelloT, MsgSenderT, SyncMsgRe a a ceiverT, AsyncMsgReceiverT, TextListener. Fat de versiunea prezentat se a a modic doar clasele MsgSenderT, SyncMsgReceiverT, AsyncMsgReceiverT. a clasa MsgHelloT cmpul queueName reprezint numele JNDI al cozii. In a a Clasa MsgSenderT
1 2 3 4 6 7 8 9 10 12 13 14 15
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 ; }
Aplicatiile pot executate utiliznd oricare din implementrile JMS, schimbnd doar a a a ierul jndi.properties. s
125
17 18 19 20 21 22 23 24 25 26 27 29 30 31 32 33 34 35 36 37 38 39 40 41 42 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 62 63 64 65 66 67 68 69 70
public void run ( ) { try { setupJNDI ( ) ; // l o o k u p t h e c o n n e c t i o n f a c t o r y QueueConnectionFactory c f= ( QueueConnectionFactory ) c t x . l o o k u p (CONNECTION JNDI NAME ) ; C o n n e c t i o n conn=c f . c r e a t e C o n n e c t i o n ( ) ; S e s s i o n s e s s i o n=conn . c r e a t e S e s s i o n ( f a l s e , S e s s i o n .AUTO ACKNOWLEDGE) ; D e s t i n a t i o n q=( D e s t i n a t i o n ) c t x . l o o k u p (QUEUE JNDI NAME ) ; closeJNDI ( ) ; MessageProducer p r o d u c e r=s e s s i o n . c r e a t e P r o d u c e r ( q ) ; TextMessage m e s s i o n . c r e a t e T e x t M e s s a g e ( ) ; =s f o r ( i n t i =0; i <n ; i ++){ m. s e t T e x t ( H e l l o +i ) ; p r o d u c e r . send (m) ; } p r o d u c e r . send ( s e s s i o n . c r e a t e M e s s a g e ( ) ) ; session . close (); conn . 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 ( ) { // S e t t h e p r o p e r t i e s . . . 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 ( JNDIP 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 ( ) ) ; } // C r e a t e t h e i n i t i a l c o n t e x t 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 ( ) ; } catch ( NamingException e ) { System . e r r . p r i n t l n ( Unable t o c l o s e JNDI Context : + e ) ; } } }
Clasa SyncMsgReceiverT
1
import j a v a x . jms . ;
126
import j a v a x . naming . ; import j a v a . u t i l . P r o p e r t i e s ; import j a v a . i o . ;
2 3 4 6 7 8 9 11 12 13 15 16 17 18 19 20 21 22 23 24 26 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 48 50 52
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 ( ) ; // l o o k u p t h e c o n n e c t i o n f a c t o r y QueueConnectionFactory c f= ( QueueConnectionFactory ) c t x . l o o k u p (CONNECTION JNDI NAME ) ; C o n n e c t i o n conn=c f . c r e a t e C o n n e c t i o n ( ) ; S e s s i o n s e s s i o n=conn . c r e a t e S e s s i o n ( f a l s e , S e s s i o n .AUTO ACKNOWLEDGE) ; D e s t i n a t i o n q=( D e s t i n a t i o n ) c t x . l o o k u p (QUEUE JNDI NAME ) ; closeJNDI ( ) ; MessageConsumer consumer=s e s s i o n . createConsumer ( q ) ; conn . s t a r t ( ) ; 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 ; } } session . close (); conn . 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 ( ) { . . . } }
5.4.8
Aplicatia este alctuit din clasele MsgPS, MsgPublisherT, MsgSubscrib a a erT. Fat de versiunea prezentat se modic doar clasele MsgPublisherT, a a a
127
MsgSubscriberT. clasa MsgPS cmpul subiect reprezint numele JNDI ataat topic-ului. In a a s Clasa MsgPublisherT
1 2 3 4 6 7 8 9 10 12 13 14 15 17 18 19 20 21 22 23 24 25 26 27 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 45 47 49
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 ( ) ; // l o o k u p t h e c o n n e c t i o n f a c t o r y 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 ) ; 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 t =( D e s t i n a t i o n ) c t x . l o o k u p (TOPIC JNDI NAME ) ; closeJNDI ( ) ; 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 m e s s i o n . c r e a t e T e x t M e s s a g e ( ) ; =s f o r ( i n t i =0; i <n ; i ++){ m. s e t T e x t ( Despre JMS+ +i ) ; p r o d u c e r . send (m) ; } p r o d u c e r . send ( s e s s i o n . c r e a t e M e s s a g e ( ) ) ; session . close (); conn . 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 ( ) { . . . } }
Clasa MsgSubscriberT
1 2 3
128
import j a v a . i o . ;
4 6 7 8 9 10 11 13 14 15 16 17 19 20 21 22 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 54 56 58
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 ( ) ; // l o o k u p t h e c o n n e c t i o n f a c t o r y 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 ) ; 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 =( D e s t i n a t i o n ) c t x . l o o k u p (TOPIC JNDI NAME ) ; closeJNDI ( ) ; // 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 , c l i e n t N a m e ) ; T o p i c S u b s c r i b e r consumer=s e s s i o n . c r e a t e S u b s c r i b e r ( ( Topic ) t ) ; conn . s t a r t ( ) ; 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 : + g e t T e x t ( ) ) ; m. } else break ; } session . close (); conn . 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 ( ) { . . . } }
129
5.5
Rezultatele acestei sectiuni sunt valabile doar cazul pachetului Oracle n Open Message Queue.
5.5.1
SOAP
SOAP - Simple Object Access Protocol - este un protocol de comunicatii prezent SOAP este protocolul standard pentru servicii Web ntre aplicatii. In prin Internet. SOAP este independent de platforma de calcul i de limbajul s de programare. SOAP se bazeaz pe XML (eXtensible Markup Language) i este un stana s dard W3C (World Wide Web Consortium).
5.5.2
Mesaje SOAP
Un mesaj SOAP este un document XML constnd din a o nvelitoare (envelope) care poate contine un numr arbitrar de antete (header ); a un corp (body); un numr variabil de obiecte ataate (attachments) MIME (Multipurpose a s Internet Mail Exchange). Astfel un mesaj SOAP apare sub forma documentului XML <?xml version="1.0" encoding="UTF-8"?> <Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/"> <Header/> <Body> <Fault/> </Body> </Envelope> Facilitile Java de manipulare a mesajelor SOAP sunt continute paat n chetul javax.xml.soap, din distributia jdk. acest sectiune vom crea mesaje SOAP, le transformm mesaje JMS In a a n pe care le trimitem furnizorului JMS, de unde un client le receptioneaz, dup a a care transform mesajul JMS mesaj SOAP i regsete datele expediate. a n s a s Solutia este specic implementrii Oracle-Open Message Queue. a a
MessageFactory mf=MessageFactory.newInstance(); SOAPMessage soapMsg=mf.createMessage(); Mesajul creat are denit structura de baz a mesajului SOAP: invelia a toarea, un antet i corp. Aceste elemente pot accesate prin s SOAPPart part=soapMsg.getSOAPPart(); SOAPEnvelope envelope=part.getEnvelope(); SOAPHeader header=envelope.getHeader(); SOAPBody body=envelope.getBody(); Completarea corpului unui mesaj SOAP Generm numele elementului, e1 cazul exemplului, a n Name n1=envelope.createName("e1"); body un element se poate include, pe baza numelui creat prin In SOAPElement e1=body.addBodyElement(n1); general, un element se include elementul printe, care pote chiar i In n a s body, prin metoda clasei SOAPElement SOAPElement addChildElement(Name name) Completm elementul e1 cu un text: primul, prin a e1.addTextNode("primul"); Exemplul 5.5.1 Mesajul SOAP
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
<SOAPENV:Envelope xmlns:SOAPENV= h t t p : // schemas . x m l s o a p . o r g / s o a p / e n v e l o p e / > <SOAPENV:Header /> <SOAPENV:Body> <e1> primul <e11> al treilea </ e11> </ e1> <e2> al doilea </ e2> </SOAPENV:Body> </SOAPENV:Envelope>
131
se obtine cu programul
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
import j a v a x . xml . soap . ; import j a v a . i o . ; public c l a s s MsgSOAP{ public s t a t i c void main ( S t r i n g [ ] a r g s ) { Name name=n u l l ; try { Me ss ag eFa ct ory mf=Me ssa ge Fac to ry . n e w I n s t a n c e ( ) ; SOAPMessage soapMsg=mf . c r e a t e M e s s a g e ( ) ; SOAPPart p a r t=soapMsg . getSOAPPart ( ) ; SOAPEnvelope e n v e l o p e=p a r t . g e t E n v e l o p e ( ) ; SOAPBody body=e n v e l o p e . getBody ( ) ; Name n1=e n v e l o p e . createName ( e1 ) ; SOAPElement e1=body . addBodyElement ( n1 ) ; e1 . addTextNode ( p r i m u l ) ; Name n2=e n v e l o p e . createName ( e2 ) ; SOAPElement e2=body . addBodyElement ( n2 ) ; e2 . addTextNode ( a l d o i l e a ) ; Name n11 =e n v e l o p e . createName ( e11 ) ; SOAPElement e11=e1 . addChildElement ( n11 ) ; e11 . addTextNode ( a l t r e i l e a ) ; F i l e O u t p u t S t r e a m f=new F i l e O u t p u t S t r e a m ( MySOAPMessage . xml ) ; soapMsg . w r i t e T o ( f ) ; } 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 ( ) ) ; } } }
Un mesaj SOAP se poate salva ntr-un ier text cu s FileOutputStream f=new FileOutputStream(. . .); soapMsg.writeTo(f); Transformarea unui mesaj SOAP mesaj JMS n SOAPMessage soapMsg=. . . Message msg= MessageTransformer.SOAPMessageIntoJMSMessage(soapMsg,session); Transformarea unui mesaj JMS mesaj SOAP n MessageFactory mf=. . . Message msg=. . . SOAPMessage soapMsg = MessageTransformer.SOAPMessageFromJMSMessage(msg,mf);
132
Preluarea elementelor din corpul unui mesaj SOAP SOAPBody body=. . . SOAPBodyElement element=null; Iterator iterator=body.getChildElements(); while(iterator.hasNext()){ element=(SOAPBodyElement)iterator.next(); String name=element.getElementName(); if(name.getLocalName().equals("numeCamp")){ String s=element.getValue(); . . . } } Exemplul 5.5.2 Un client introduce ntr-un mesaj SOAP dou numere ntregi, a transmite mesajul altui program care calculeaz cel mai mare divizor comun al a celor dou numere i transmite clientului rezultatul tot sub forma unui mesaj a s SOAP. Activitatea clientului este se compune din Transmiterea ctre server a cererii. Mesajul este alctuit din cele dou a a a numere i un topic, indicativ dup care se va gsi rspunsul. s a a a
1 2 3 4 6 8 9 10 12 13 14 15 16 17 18 19 20 21 22 24 25 26
public c l a s s
long a , b ; String topicResult ; S t r i n g c l i e n t I D , clientName ; MsgSOAPClientSender ( S t r i n g c l i e n t I D , S t r i n g c l i e n t N a m e ) { 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 : ) ; a=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 n : ) ; b=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 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 ( ) { Me ss ag eFa ct ory mf=n u l l ; SOAPMessage soapMsg=n u l l ;
133
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 73 74 75 76 77 78 79 80 81 82
SOAPPart p a r t=n u l l ; SOAPEnvelope e n v e l o p e=n u l l ; SOAPBody body=n u l l ; SOAPElement elem=n u l l ; Name name=n u l l ; 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 , a t l a n t i s ) ; // 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 ) ; TopicSession session = 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 ) ; MessageProducer p r o d u c e r=s e s s i o n . c r e a t e P r o d u c e r ( tDate ) ; mf=Me ss age Fa cto ry . n e w I n s t a n c e ( ) ; soapMsg=mf . c r e a t e M e s s a g e ( ) ; p a r t=soapMsg . getSOAPPart ( ) ; e n v e l o p e=p a r t . g e t E n v e l o p e ( ) ; body=e n v e l o p e . getBody ( ) ; name=e n v e l o p e . createName ( n1 ) ; elem=body . addChildElement ( name ) ; elem . addTextNode ( (new Long ( a ) ) . t o S t r i n g ( ) ) ; name=e n v e l o p e . createName ( n2 ) ; elem=body . addChildElement ( name ) ; elem . addTextNode ( (new Long ( b ) ) . t o S t r i n g ( ) ) ; name=e n v e l o p e . createName ( t o p i c ) ; elem=body . addChildElement ( name ) ; elem . addTextNode ( t o p i c R e s u l t ) ; D e s t i n a t i o n t R e s u l t=s e s s i o n . c r e a t e T o p i c ( t o p i c R e s u l t ) ; 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 ) ; Message m = M es s ag e Tr an s fo r me r . SOAPMessageIntoJMSMessage ( soapMsg , s e s s i o n ) ; p r o d u c e r . send (m) ; F i l e O u t p u t S t r e a m f=new F i l e O u t p u t S t r e a m ( MySOAPMessage . xml ) ; soapMsg . w r i t e T o ( f ) ; conn . 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 ( ) ) ; } System . out . p r i n t l n ( Sen de 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 ) { 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 MsgSOAPClientSender c l i e n t I D c l i e n t N a m e ) ; System . e x i t ( 0 ) ; } MsgSOAPClientSender c l i e n t=new MsgSOAPClientSender ( a r g s [ 0 ] , a r g s [ 1 ] ) ; client . service (); } }
Receptionarea rspunsului. a
134
1 2 3 4 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 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
public c l a s s
String topicResult ; S t r i n g c l i e n t I D , clientName ; MsgSOAPClientReceiver ( S t r i n g c l i e n t I D , S t r i n g c l i e n t N a m e ) { 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 ( ) { Me ss ag eFa ct ory mf=n u l l ; SOAPMessage soapMsg=n u l l ; SOAPPart p a r t=n u l l ; SOAPEnvelope e n v e l o p e=n u l l ; SOAPBody body=n u l l ; SOAPBodyElement e l e m e n t=n u l l ; Name name=n u l l ; 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 , a t l a n t i s ) ; // 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 R e s u l t ) ; 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 ) ; mf=Me ssa ge Fac to ry . n e w I n s t a n c e ( ) ; conn . s t a r t ( ) ; Message msg=consumer . r e c e i v e ( ) ; soapMsg=Me s sa ge T ra n sf o rm er . SOAPMessageFromJMSMessage ( msg , mf ) ; System . out . p r i n t l n ( C l i e n t Mesaj SOAP r e c e p t i o n a t ) ; p a r t=soapMsg . getSOAPPart ( ) ; e n v e l o p e=p a r t . g e t E n v e l o p e ( ) ; body=e n v e l o p e . getBody ( ) ; I t e r a t o r i t e r a t o r=body . g e t C h i l d E l e m e n t s ( ) ; S t r i n g s= ; while ( i t e r a t o r . hasNext ( ) ) { e l e m e n t =(SOAPBodyElement ) i t e r a t o r . n e x t ( ) ; name=e l e m e n t . getElementName ( ) ; i f ( name . getLocalName ( ) . e q u a l s ( cmmdc ) ) s=e l e m e n t . g e t V a l u e ( ) ; } System . out . p r i n t l n ( Cmmdc : +s ) ; conn . c l o s e ( ) ; } catch ( E x c e p t i o n e ) {
135
59 60 61 62 64 65 66 67 68 69 70 71 72 73
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 ( R e c e i 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 ) { 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 ) ; } MsgSOAPClientReceiver c l i e n t=new MsgSOAPClientReceiver ( a r g s [ 0 ] , a r g s [ 1 ] ) ; client . service (); } }
public c l a s s
long cmmdc( long m, long n ) { . . . } public void s e r v i c e ( ) { Me ss age Fa ct ory mf=n u l l ; SOAPMessage soapMsg=n u l l ; SOAPPart p a r t=n u l l ; SOAPEnvelope e n v e l o p e=n u l l ; SOAPBody body=n u l l ; SOAPBodyElement e l e m e n t=n u l l ; SOAPElement elem=n u l l ; Name name=n u l l ; 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 , a t l a n t i s ) ; // 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 ( ) ; Message msg=n u l l ; mf=Me ss age Fa cto ry . n e w I n s t a n c e ( ) ; while ( true ) { msg=consumer . r e c e i v e ( ) ; soapMsg=Me s sa ge T ra n sf o rm er . SOAPMessageFromJMSMessage ( msg , mf ) ; System . out . p r i n t l n ( S e r v e r Mesaj SOAP r e c e p t i o n a t ) ; p a r t=soapMsg . getSOAPPart ( ) ; e n v e l o p e=p a r t . g e t E n v e l o p e ( ) ; body=e n v e l o p e . getBody ( ) ; I t e r a t o r i t e r a t o r=body . g e t C h i l d E l e m e n t s ( ) ; S t r i n g sn1= , sn2= , t o p i c R e s u l t= ;
136
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 72 73 75 76 77 78 79
while ( i t e r a t o r . hasNext ( ) ) { e l e m e n t =(SOAPBodyElement ) i t e r a t o r . n e x t ( ) ; name=e l e m e n t . getElementName ( ) ; i f ( name . getLocalName ( ) . e q u a l s ( n1 ) ) sn1=e l e m e n t . g e t V a l u e ( ) ; i f ( name . getLocalName ( ) . e q u a l s ( n2 ) ) sn2=e l e m e n t . g e t V a l u e ( ) ; i f ( name . getLocalName ( ) . e q u a l s ( t o p i c ) ) t o p i c R e s u l t=e l e m e n t . g e t V a l u e ( ) ; } System . out . p r i n t l n ( sn1+ : +sn2+ : +t o p i c R e s u l t ) ; long a=Long . par se Lon g ( sn1 ) ; long b=Long . pa rs eL ong ( sn2 ) ; long c=cmmdc( a , b ) ; soapMsg=mf . c r e a t e M e s s a g e ( ) ; p a r t=soapMsg . getSOAPPart ( ) ; e n v e l o p e=p a r t . g e t E n v e l o p e ( ) ; body=e n v e l o p e . getBody ( ) ; name=e n v e l o p e . createName ( cmmdc ) ; elem=body . addChildElement ( name ) ; elem . addTextNode ( (new Long ( c ) ) . t o S t r i n g ( ) ) ; Message m = M es s ag e Tr an s fo rm e r . SOAPMessageIntoJMSMessage ( soapMsg , s e s s i o n ) ; D e s t i n a t i o n t R e s u l t=s e s s i o n . c r e a t e T o p i c ( t o p i c R e s u l t ) ; 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 ) ; p r o d u c e r . send (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 ( ) ) ; } 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 ) { MsgSOAPCmmdcServer s e r v e r=new MsgSOAPCmmdcServer ( ) ; server . service (); } }
Mesajul SOAP utilizat de client, pentru n1 = 45, n2 = 35 i topic = nume s este <soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/"> <soap-env:Header/> <soap-env:Body> <n1>45</n1> <n2>35</n2> <topic>nume</topic> </soap-env:Body> </soap-env:Envelope>
137
5.5.3
Ataamente SOAP s
Crearea ataamentelor s 1. Crearea mesajului SOAP MessageFactory mf=MessageFactory.newInstance(); SOAPMessage soapMsg=mf.createMessage(); 2. Ataament text s (a) Crearea unui obiect de tip AttachmentPart AttachmentPart attachment=soapMsg.createAttachmentPart(); (b) Completarea continutului String stringContent=. . . attachment.setContent(stringContent, "text/plain"); Continutului i se poate ataa un cod de identicare s attachment.setContentId("Text1"); Ataament imagine jpeg/png s (a) Crearea unui obiect de tip AttachmentPart cu arcarea imagnc inii. URL url=new URL("file://localhost/c:\\. . .\\***.jpg"); DataHandler dataHandler = new DataHandler(url); AttachmentPart attachment = soapMsg.createAttachmentPart(dataHandler); attachment.setContentId("Imagine1"); Ataament cu sunet format mp3. s n (a) Crearea unui obiect de tip AttachmentPart cu arcarea ierului nc s mp3. URL url=new URL("file://localhost/c:\\. . .\\***.mp3"); DataHandler dataHandler=new DataHandler(url); AttachmentPart attachment = soapMsg.createAttachmentPart(dataHandler); attachment.setContentId("attached_mp3"); Ataament video. s (a) Fiierele video au de obicei dimensiuni mari. Pentru a putea s include asemenea iere trebuie mrit dimensiunea maxim a s a a a unui ataament prin includerea setrii s a imq.autocreate.destination.maxBytesPerMsg=35M ierul mq\lib\props\broker\install.properties. n s
138
(b) Crearea unui obiect de tip AttachmentPart cu arcarea ierului nc s cu continut video. String video_location="c:\\. . .; URL url=new URL("file://"+video_location); dataHandler= new DataHandler(url); AttachmentPart attachment = soapMsg.createAttachmentPart(dataHandler); (c) Pentru redarea continutului video vom avem nevoie de tipul continutului video, informatie dat de extensia ierului video. a s Aceat dat este furnizat prin metoda setContentId. a a a File videoFile = new File(video_location); String fileName = videoFile.getName(); int index=fileName.lastIndexOf("."); String ext=fileName.substring(index+1); attachment.setContentId("attached_video"+ext); 3. Includerea ataamentului mesajul SOAP s n soapMsg.addAttachmentPart(attachment); Extragerea ataamentelor s Tipul unui ataament se poate deduce din rezultatul metodei getContentId s sau getContentType a clasei AttachmentPart. Iterator iterator = soapMsg.getAttachments(); while (iterator.hasNext()) { AttachmentPart attached = (AttachmentPart)iterator.next(); // Codul de identificare String id = attached.getContentId(); // Tipul atasamentului String type = attached.getContentType(); // Preluarea unui string if (type.equals("text/plain")) { Object content = attached.getContent(); . . . }
139
// Preluarea unei imagini if (type.equals("image/jpeg")){ Image image=(Image)attached.getContent(); . . . } // Preluarea unei inregistrari mp3 if(type.equals("audio/x-wav")){ System.out.println("Play MP3"); MP3Player mp3Player=new MP3Player(attached.getRawContent()); mp3Player.play(); } // Preluarea continutului video if(id.startsWith("attached_video")){ String videoFileName = "videoFile."+id.substring(14); // Salvarea continutului video intr-un fisier local InputStream inputStream = attached.getRawContent(); File f=new File(videoFileName); OutputStream out=new FileOutputStream(f); byte buf[]=new byte[1024]; int len; while((len=inputStream.read(buf))>0) out.write(buf,0,len); out.close(); // Redarea continutului video utilizand FMJ String[]arguments = new String[1]; arguments[0]=URLUtils.createUrlStr(f); System.out.println("Video show"); FmjStudio.main(arguments); }
Valoarea rezultat din metoda getContentType cazul unui ataament video a n s difer de tipul acesteia. Astfel pentru tipul avi valoarea retunat este application/x-troff-msvideo a a iar pentru wmv se obtine content/unknown. Redarea continutului video se face utiliznd produsul Freedom for Media in Java - FMJ. a Exemplul 5.5.3 Crearea unui mesaj SOAP cu ataamente text, imagine, muzic s a mp3 i video. Textul, imaginea, muzica mp3 i continutul video sunt continute s s iere. Cile ctre aceste iere se vor da ca proprieti. n s a a s at
140
1 2 3 4 5 6 8 10 11 12 13 14 15 16 17 19 20 21 22 23 24 25 26 27 28 29 30 31 33 34 35 36 37 38 39 40 42 44 46 47 49 50 51 52 53 54 55 57 58
j a v a x . jms . ; j a v a x . xml . soap . ; com . sun . m e s s a g i n g . xml . Me s sa g eT ra n sf o rm e r ; java . io . ; j a v a x . a c t i v a t i o n . DataHandler ; j a v a . n e t .URL; MsgSOAPPublisher extends Thread {
public c l a s s
String f i l e l o c a t i o n , image location , mp3 location , v i d e o l o c a t i o n ; MsgSOAPPublisher ( S t r i n g f i l e l o c a t i o n , S t r i n g i m a g e l o c a t i o n , String mp3 location , String v i d e o l o c a t i o n ){ this . f i l e l o c a t i o n=f i l e l o c a t i o n ; t h i s . i m a g e l o c a t i o n=i m a g e l o c a t i o n ; t h i s . m p 3 l o c a t i o n=m p 3 l o c a t i o n ; t h i s . v i d e o l o c a t i o n=v i d e o l o c a t i o n ; } 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 , a t l a n t i s ) ; // 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) ; // Topic t=new com . sun . m e s s a g i n g . Topic ( Date ) ; // T o p i c P u b l i s h e r p u b l i s h e r=s e s s i o n . c r e a t e P u b l i s h e r ( t ) ; D e s t i n a t i o n t=s e s s i o n . c r e a t e T o p i c ( Date ) ; 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 ) ; Me ss ag eFa ct ory mf=Me ssa ge Fac to ry . n e w I n s t a n c e ( ) ; SOAPMessage soapMsg=mf . c r e a t e M e s s a g e ( ) ; SOAPPart p a r t=soapMsg . getSOAPPart ( ) ; SOAPEnvelope e n v e l o p e=p a r t . g e t E n v e l o p e ( ) ; SOAPBody body=e n v e l o p e . getBody ( ) ; Name bodyName=e n v e l o p e . createName ( v e r i f ) ; SOAPElement e l e m e n t=body . addBodyElement ( bodyName ) ; e l e m e n t . addTextNode ( MyAttachment ) ; // Crearea a t a s a m e n t u l u i de t i p t e x t AttachmentPart attachment1=soapMsg . c r e a t e A t t a c h m e n t P a r t ( ) ; F i l e R e a d e r f r = new F i l e R e a d e r (new F i l e ( f i l e l o c a t i o n ) ) ; 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 ) ; S t r i n g stringContent = ; S t r i n g l i n e = br . r e a d L i n e ( ) ; while ( l i n e != n u l l ) { stringContent = stringContent . concat ( l i n e ) ; s t r i n g C o n t e n t = s t r i n g C o n t e n t . c o n c a t ( \n ) ; l i n e = br . r e a d L i n e ( ) ; } attachment1 . s e t C o n t e n t ( s t r i n g C o n t e n t , t e x t / p l a i n ) ; attachment1 . s e t C o n t e n t I d ( a t t a c h e d t e x t ) ;
141
soapMsg . addAttachmentPart ( attachment1 ) ; // Crearea a t a s a m e n t u l u i de t i p imagine URL u r l = new URL( f i l e : / / +i m a g e l o c a t i o n ) ; DataHandler d a t a H a n d l e r = new DataHandler ( u r l ) ; AttachmentPart attachment2 = soapMsg . c r e a t e A t t a c h m e n t P a r t ( d a t a H a n d l e r ) ; attachment2 . s e t C o n t e n t I d ( a t t a c h e d i m a g e ) ; soapMsg . addAttachmentPart ( attachment2 ) ; // Crearea unui atasament de t i p mp3 u r l=new URL( f i l e : / / +m p 3 l o c a t i o n ) ; d a t a H a n d l e r= new DataHandler ( u r l ) ; AttachmentPart attachment3 = soapMsg . c r e a t e A t t a c h m e n t P a r t ( d a t a H a n d l e r ) ; attachment3 . s e t C o n t e n t I d ( attached mp3 ) ; soapMsg . addAttachmentPart ( attachment3 ) ; // Crearea unui atasament v i d e o u r l=new URL( f i l e : / / +v i d e o l o c a t i o n ) ; d a t a H a n d l e r= new DataHandler ( u r l ) ; AttachmentPart attachment4 = soapMsg . c r e a t e A t t a c h m e n t P a r t ( d a t a H a n d l e r ) ; F i l e v i d e o F i l e = new F i l e ( v i d e o l o c a t i o n ) ; S t r i n g f i l e N a m e = v i d e o F i l e . getName ( ) ; i n t i n d e x=f i l e N a m e . l a s t I n d e x O f ( . ) ; S t r i n g e x t=f i l e N a m e . s u b s t r i n g ( i n d e x +1); attachment4 . s e t C o n t e n t I d ( a t t a c h e d v i d e o +e x t ) ; soapMsg . addAttachmentPart ( attachment4 ) ; Message m = M es s ag e Tr an s fo r me r . SOAPMessageIntoJMSMessage ( soapMsg , s e s s i o n ) ; // p u b l i s h e r . p u b l i s h (m) ; p r o d u c e r . send (m) ; F i l e O u t p u t S t r e a m f=new F i l e O u t p u t S t r e a m ( MySOAPMessage . xml ) ; soapMsg . w r i t e T o ( f ) ; conn . 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 ( ) ) ; } System . out . p r i n t l n ( P u b l i s h e r f i n i s e d ) ; } }
j a v a x . jms . ; j a v a x . xml . soap . ; com . sun . m e s s a g i n g . xml . Me s sa g eT ra n sf o rm e r ; java . u t i l . I t e r a t o r ; java . io . ; j a v a . awt . ; n e t . s f . fmj . u t i l i t y . URLUtils ; n e t . s f . fmj . u i . FmjStudio ;
142
10 12 13 14 15 16 17 18 19 20 21 22 23 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
public c l a s s
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 , a t l a n t i s ) ; // 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) ; // Topic t=new com . sun . m e s s a g i n g . Topic ( Date ) ; D e s t i n a t i o n t=s e s s i o n . c r e a t e T o p i c ( Date ) ; T o p i c S u b s c r i b e r consumer=s e s s i o n . c r e a t e S u b s c r i b e r ( ( Topic ) t ) ; conn . s t a r t ( ) ; Message msg=n u l l ; Me ss ag eFa ct ory mf=Me ssa ge Fac to ry . n e w I n s t a n c e ( ) ; while ( ( msg=consumer . r e c e i v e ( ) ) ! = n u l l ) { SOAPMessage soapMsg = M es s ag e Tr an s fo rm e r . SOAPMessageFromJMSMessage ( msg , mf ) ; System . out . p r i n t l n ( Mesaj SOAP r e c e p t i o n a t ) ; // E x t r a g e r e a a t a s a m e n t e l o r I t e r a t o r i t e r a t o r = soapMsg . g e t A t t a c h m e n t s ( ) ; while ( i t e r a t o r . hasNext ( ) ) { AttachmentPart a t t a c h e d =(AttachmentPart ) i t e r a t o r . n e x t ( ) ; String id = attached . getContentId ( ) ; S t r i n g t y p e = a t t a c h e d . getContentType ( ) ; System . out . p r i n t l n ( Attachment + i d + has c o n t e n t t y p e + t y p e ) ; i f ( type . e q u a l s ( t e x t / p l a i n ) ) { S t r i n g content = ( S t r i n g ) attached . getContent ( ) ; System . out . p r i n t l n ( Attachment c o n t a i n s : \ n + c o n t e n t ) ; } i f ( t y p e . e q u a l s ( image / j p e g ) ) { Image image=(Image ) a t t a c h e d . g e t C o n t e n t ( ) ; ShowImage s=new ShowImage ( image ) ; s . show ( ) ; } i f ( t y p e . e q u a l s ( a u d i o /xwav ) ) { System . out . p r i n t l n ( Play MP3 ) ; MP3Player mp3Player=new MP3Player ( a t t a c h e d . getRawContent ( ) ) ; mp3Player . s t a r t ( ) ; } i f ( id . startsWith ( attached video )){ S t r i n g vi d e o Fi l e N a m e = v i d e o F i l e . +i d . s u b s t r i n g ( 1 4 ) ; InputStream i n p u t S t r e a m = a t t a c h e d . getRawContent ( ) ; F i l e f=new F i l e ( v i de o F i l eN a m e ) ; OutputStream out=new F i l e O u t p u t S t r e a m ( f ) ; byte b u f [ ] =new byte [ 1 0 2 4 ] ; int l e n ; while ( ( l e n=i n p u t S t r e a m . r e a d ( b u f )) >0) out . w r i t e ( buf , 0 , l e n ) ; out . c l o s e ( ) ; S t r i n g [ ] arguments = new S t r i n g [ 1 ] ; arguments [ 0 ] = URLUtils . c r e a t e U r l S t r ( f ) ; System . out . p r i n t l n ( P r e s s Enter t o c o n t i n u e ! ) ; System . i n . r e a d ( ) ; System . out . p r i n t l n ( Video show ) ;
143
68 69 70 71 72 73 74 75 76 77 78 79
import j a v a . u t i l . ; c l a s s MsgAttach { 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 f i l e l o c a t i o n =System . g e t P r o p e r t y ( f i l e l o c a t i o n ) ; S t r i n g i m a g e l o c a t i o n=System . g e t P r o p e r t y ( i m a g e l o c a t i o n ) ; S t r i n g m p 3 l o c a t i o n=System . g e t P r o p e r t y ( m p 3 l o c a t i o n ) ; S t r i n g v i d e o l o c a t i o n=System . g e t P r o p e r t y ( v i d e o l o c a t i o n ) ; MsgSOAPPublisher p u b l i s h e r=new MsgSOAPPublisher ( f i l e l o c a t i o n , image location , mp3 location , v i d e o l o c a t i o n ) ; MsgSOAPSubscriber s u b s c r i b e r=new MsgSOAPSubscriber ( ) ; publisher . start ( ) ; subscriber . start (); } }
i cu ierul build.xml s s
1 2 3 4 5 7 8 9 10 11 12 13
<?xml version= 1 . 0 e n c o d i n g=UTF8 ?> <p r o j e c t default= run b a s e d i r= . > <p r o p e r t y name=mq . home v a l u e= d : /mq /> <p r o p e r t y name= r e s o u r c e s . home l o c a t i o n= ${ b a s e d i r }/ r e s o u r c e s /> <p r o p e r t y name= fmj . home l o c a t i o n= d : /JavaApp/ fmj /> <path i d= c l a s s p a t h > <p a t h e l e m e n t path= b u i l d / c l a s s e s /> <p a t h e l e m e n t path= ${ fmj . home}/ fmj . j a r /> < f i l e s e t d i r= ${mq . home}/ l i b > <i n c l u d e name= . j a r /> </ f < i l e s e t> < f i l e s e t d i r= ${ fmj . home}/ l i b >
144
<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 > <mkdir d i r= b u i l d /> <mkdir d i r= b u i l d / c l a s s e s /> </ 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 s r c d i r= s r c c l a s s p a t h r e f= c l a s s p a t h d e s t d i r= b u i l d / c l a s s e s debug= y e s /> </ t a r g e t>
14 15 16 18 19 20 21 23 24 25 26 28 29 30 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 48
<t a r g e t name= s e r v e r > <e x e c e x e c u t a b l e= ${mq . home}/ b i n / imqbrokerd . e x e d i r= ${mq . home}/ b i n /> </ t a r g e t> <t a r g e t name= run depends= c o m p i l e > <j a v a c l a s s n a m e= MsgAttach c l a s s p a t h r e f= c l a s s p a t h f o r k= y e s f a i l o n e r r o r= y e s > <s y s p r o p e r t y key= f i l e l o c a t i o n v a l u e= ${ r e s o u r c e s . home}/ c a p i t o l . t x t /> <s y s p r o p e r t y key= i m a g e l o c a t i o n v a l u e= l o c a l h o s t /${ r e s o u r c e s . home}/ xmlp i c . j p g /> <s y s p r o p e r t y key= m p 3 l o c a t i o n v a l u e= l o c a l h o s t /${ r e s o u r c e s . home}/ Tomjones . mp3 /> <s y s p r o p e r t y key= v i d e o l o c a t i o n v a l u e= l o c a l h o s t /${ r e s o u r c e s . home}/ c l o c k . a v i /> <s y s p r o p e r t y key= j a v a . l i b r a r y . path v a l u e= ${ fmj . home}/ n a t i v e / win32x86 /> </ j a v a> </ t a r g e t> </ p r o j e c t>
im po rt im po rt im po rt im po rt im po rt im po rt
c l a s s MyCanvas e x t e n d s Canvas { Image image=n u l l ; MyCanvas ( Image image ) { t h i s . image=image ; } p u b l i c void paint ( Graphics g ){ g . drawImage ( image , 0 , 0 , t h i s ) ; } } p u b l i c c l a s s ShowImage{
5.6.
APACHE-QPID
145
21 23 24 25 27 28 29 30 31 32 33 34 35 36 37
MyCanvas mc=n u l l ; ShowImage ( Image image ) { mc=new MyCanvas ( image ) ; } p u b l i c v o i d show ( ) { // I n t e r f a t a swing JFrame j f r a m e = new JFrame ( The r e c e i v e d image ) ; jframe . addNotify ( ) ; j f r a m e . getContentPane ( ) . s e t L a y o u t ( new BorderLayout ( ) ) ; j f r a m e . getContentPane ( ) . add (mc , BorderLayout .CENTER) ; j f r a m e . s e t D e f a u l t C l o s e O p e r a t i o n ( JFrame . EXIT ON CLOSE ) ; jframe . s e t S i z e (200 ,200); jframe . s e t V i s i b l e ( true ) ; } }
Programul pentru redarea continutului unui ier mp3 necesit prezenta s a resursei jl1.0.jar din pachetul JLayer1.0, descrcabil din internet. Un program a de redare este
1 2 4 5 7 8 9 10 11 12 13 14 15 16 18 19 20 21 22 23 24 25 26 27
im po rt j a v a . i o . ; im po rt javazoom . j l . p l a y e r . P l a y e r ; p u b l i c c l a s s MP3Player e x t e n d s Thread { private Player player ; p u b l i c MP3Player ( InputStream i s ) { try { B u f f e r e d I n p u t S t r e a m b i s=new B u f f e r e d I n p u t S t r e a m ( i s ) ; p l a y e r=new P l a y e r ( b i s ) ; } catch ( Exception 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 ( 1 ) ; } } p u b l i c v o i d run ( ) { try { player . play ( ) ; } catch ( Exception e ){ System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ; } i f ( p l a y e r != n u l l ) p l a y e r . c l o s e ( ) ; } }
5.6
Apache-qpid
apache-qpid reprezint o implementare a protocolului AMQP care poate a folosit de clienti Java, C++, C#, Pyton, Ruby. Programele dezvoltate uti-
146
liznd Oracle-Open Message Queue sau apache-ActiveMQ prin JNDI ruleaz a a fr modicri. aa a Instalarea serviciului de mesagerie revine la 1. Dezarhivarea ierului descrcat; s a 2. Generarea unei semnturi. a Catalogul QPID HOME\bin contine ierul create-example-ssl-stores.bat, s care se adapteaz corespunztor iar semntura generat se depune cata a a a n alogul QPID HOME\etc. O adaptare a ierului create-example-ssl-stores.bat este dat urmtorul s a n a exemplu.
1 2 3 4 5 6 8 9 10 11 13 14 15 17 18 19 21 22
@REM C r e a t e Broker K e y s t o r e : k e y t o o l genkey a l i a s q p i d B r o k e r k e y a l g RSA v a l i d i t y 365 k e y s t o r e q p i d . k e y s t o r e s t o r e p a s s password k e y p a s s password dname CN=unitbv , OU =cs , O=Org , L=Bv , C=R @REM Export S e l f S i g n e d C e r t : k e y t o o l e x p o r t a l i a s q p i d B r o k e r k e y s t o r e q p i d . k e y s t o r e f i l e q p i d B r o k e r . c e r s t o r e p a s s password @REM Import Broker Cert I n t o MC T r u s t S t o r e : k e y t o o l im po rt a l i a s q p i d B r o k e r C e r t f i l e q p i d B r o k e r . c e r k e y s t o r e q p i d . t r u s t s t o r e s t o r e p a s s password noprompt @REM D e l e t e t h e c e r t del qpidBroker . cer
Lansnd executie acest ier de comenzi se creaz semntura dat de ierul a n s a a a s qpid.keystore. Eventual trebuie xat locatia ierului qpid.keystore elementul keyStorePath a s n din ierul QPID HOME\etc\config.xml. s Serviciul de mesagerie se lanseaz prin a
1 2 3 4
s e t JAVA HOME=. . . s e t QPID HOME=. . . s e t QPID WORK=. . . %QPID HOME%\b i n \ qpids e r v e r . bat
Catalogul QPID WORK este utilizat de serviciul de mesagerie pentru consemnarea (logging) evenimentelor, catalog ind prezent un ier de congn s urare log4j.xml.
147
5.7
Protocolul AMQP
Punem evidenta un alt model de aplicatie, specic protocolului AMQP. n Modelul prevede existenta a trei entiti: at exchange Dispecer de directionare ce primete mesaje de la un pro s ductor de mesaje i le distribuie unor cozi pe baza unui criteriu; a s message queue coad care se pstreaz mesaje pn ce acestea sunt a n a a a a consumate de o aplicatie client. Proprietile unei cozi sunt: at numele, alctuit din litere, cifre, caracterul de subliniere, cel mult a 255 de caractere. persistenta mesajului cazul n ncetrii functionrii serverului (durable a a message queue, temporary message queue). modul de tergere a mesajelor dup consumarea acestora (autos a delete). binding criteriul dup care un mesaj este distribuit de dispecerul de a directionare unei cozi. O coad comunic dispecerului de directionare o cheie denumit cheie de a a a legare (binding key) K, timp ce orice mesaj va contine o cheie de rutare n (routing key) R. AMPQ denete trei criterii de distribuire a mesajelor de ctre dispecerul s a de directionare: distribuirea direct realizeaz o distribuire 1:1 a mesajelor: a a 1. o coad se leag de dispecerul de directionare cu cheia de legare K; a a 2. un mesaj contine cheia de rutare R; 3. dispecerul de directionare trimite mesajul ctre toate cozile care a satisfac conditia R = K. distribuirea fanout realizeaz o distribuire 1:N a mesajelor: a 1. o coad se leag de dispecerul de directionare fr cheie de legare; a a aa 2. un mesaj nu contine cheie de rutare (eventual cheia de rutare este neglijat); a
148
3. dispecerul de directionare trimite neconditional mesajul ctre toate a cozile nregistrate. distribuirea publicare-abonare 1. o coad se leag de dispecerul de directionare cu cheia de legare K; a a 2. un mesaj contine cheia de rutare R; 3. dispecerul de directionare trimite mesajul ctre toate cozile a cror a a cheie de legare se potrivete cu cheia de rutare. s Cheia de legare este alctuit din mai multe cuvinte (token) sepaa a rate de caracterul . (punct). Cheia de rutare poate contine carac terele # - va presupune potrivirea cu un cuvnt sau nu. a * - va presupune potrivirea cu cel putin un cuvnt. a Astfel *.abc se potrivete cu x.abc dar nu se potrivete cu abc, s s n timp ce #.abc se potrivete cu x.abc i abc. s s Corespunztor celor trei criterii de distribuire a mesajelor, serverul AMQP a contine dispecerii de directionare amq.direct amq.fanout amq.topic Un mesaj este expediat de client ctre un dispecer de directionare aat pe a un server AMQP. Preluarea unui mesaj dintr-o coad de ctre un client are ca a a urmare tergerea mesajului coad. s n a Resursele necesare apartin pachetului org.apache.qpid.transport.
5.7.1
Crearea unei cozi const din a 1. Realizarea conexiunii cu serverul AMQP Connection con = new Connection(); con.connect(broker,port,login,passworg,clientId,false); 2. Instantierea sesiunii
149
Session session = con.createSession(0); 3. Declararea cozii session.queueDeclare(numeCoada, null, null); session.exchangeBind(numeCoada, dispecerulDeDirectionare, binding_key, null); 4. Ateptarea conrmrii actiunii de realizare a cozii s a session.sync(); 5. Inchiderea sesiunii i a conexiunii s session.close(); con.close(); Exemplul 5.7.1 Crearea unei cozi care s primeasc mesaje prin distribuire a a direct i fanout. as
1 3 4 5 6 7 8 9 10 11 12 13 14 16 17 18 20 21 23 24 25 27 28
import o r g . apache . q p i d . t r a n s p o r t . ; public c l a s s DeclareQueue { 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 <5){ System . out . p r i n t l n ( Usage j a v a DeclareQueue b r o k e r + p o r t queueName exchange bindingKey ) ; System . e x i t ( 1 ) ; } S t r i n g b r o k e r=a r g s [ 0 ] ; i n t p o r t=I n t e g e r . p a r s e I n t ( a r g s [ 1 ] ) ; S t r i n g queueName=a r g s [ 2 ] ; S t r i n g exchange=a r g s [ 3 ] ; S t r i n g bindingKey=a r g s [ 4 ] ; // Crearea c o n e x i u n i i C o n n e c t i o n con = new C o n n e c t i o n ( ) ; con . c o n n e c t ( b r o k e r , p o r t , t e s t , g u e s t , g u e s t , f a l s e ) ; // Crearea s e s i u n i i S e s s i o n s e s s i o n = con . c r e a t e S e s s i o n ( 0 ) ; // D e c l a r a r e a c o z i i s e s s i o n . q u e u e D e c l a r e ( queueName , null , n u l l ) ; s e s s i o n . exchangeBind ( queueName , exchange , bindingKey , n u l l ) ; // Confirmarea c r e e r i i c o z i i s e s s i o n . sync ( ) ;
150
30 31 32 33 34
5.7.2
Expedierea / publicarea unui mesaj const din a 1. Realizarea conexiunii cu serverul AMQP Connection con = new Connection(); con.connect(broker,port,login,passworg,clientId,false); 2. Instantierea sesiunii Session session = con.createSession(0); 3. Precizarea (dac este nevoie) a cheii de rutare a DeliveryProperties deliveryProps = new DeliveryProperties(); deliveryProps.setRoutingKey(routing_key); 4. Crearea i expedierea mesajului s session.messageTransfer(dispecerulDeDirectionare, MessageAcceptMode.EXPLICIT, MessageAcquireMode.PRE_ACQUIRED, new Header(deliveryProps), mesaj_text); 5. Ateptarea conrmrii receptiei mesajului dectre serverul AMQP s a a session.sync(); 6. Inchiderea sesiunii i a conexiunii s session.close(); con.close();
151
Exemplul 5.7.2 Expedierea unui numr de mesaje cu continut text, urmat a de un mesaj fr continut, fapt care marcheaz sfritul trimiterii de date. a a a a s
1 3 4 5 6 7 8 9 10 11 12 13 14 16 17 18 20 21 23 24 25 27 28 29 30 31 32 33 34 35 36 37 38 39 41 42 44 45 46 47 48
import o r g . apache . q p i d . t r a n s p o r t . ; public c l a s s Se nde r { 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 <5){ System . out . p r i n t l n ( Usage j a v a S en der b r o k e r p o r t + exchange r o u t i n g K e y messagesNumber ) ; System . e x i t ( 1 ) ; } S t r i n g b r o k e r=a r g s [ 0 ] ; i n t p o r t=I n t e g e r . p a r s e I n t ( a r g s [ 1 ] ) ; S t r i n g exchange=a r g s [ 2 ] ; S t r i n g r o u t i n g K e y=a r g s [ 3 ] ; i n t n=I n t e g e r . p a r s e I n t ( a r g s [ 4 ] ) ; // Crearea c o n e x i u n i i C o n n e c t i o n con = new C o n n e c t i o n ( ) ; con . c o n n e c t ( b r o k e r , p o r t , t e s t , g u e s t , g u e s t , f a l s e ) ; // Crearea s e s i u n i i S e s s i o n s e s s i o n = con . c r e a t e S e s s i o n ( 0 ) ; // P r e c i z a r e a ( daca e s t e n e v o i e ) a c h e i i de r u t a r e D e l i v e r y P r o p e r t i e s d e l i v e r y P r o p s = new D e l i v e r y P r o p e r t i e s ( ) ; d e l i v e r y P r o p s . s etR ou ti ngK ey ( r o u t i n g K e y ) ; // Formarea s i e x p e d i e r e a m e s a j e l o r f o r ( i n t i =0; i <n ; i ++){ s e s s i o n . m e s s a g e T r a n s f e r ( exchange , MessageAcceptMode . EXPLICIT , MessageAcquireMode . PRE ACQUIRED, new Header ( d e l i v e r y P r o p s ) , Message + i ) ; } s e s s i o n . m e s s a g e T r a n s f e r ( exchange , MessageAcceptMode . EXPLICIT , MessageAcquireMode . PRE ACQUIRED, new Header ( d e l i v e r y P r o p s ) , ) ; // Confirmarea r e c e p t i e i m e s a j e l o r s e s s i o n . sync ( ) ; // I n c h i d e r e a s e s i u n i i s i a c o n e x i u n i i session . close (); con . c l o s e ( ) ; } }
152
5.7.3
Receptionarea mesajelor
Mesaje se receptioneaz asincron, adic de o clas asculttoare care imple a a a a menteaz interfata SessionListener. a Interfata SessionListener declar metodele: a public public public public public void void void void void opened(Session session) resumed(Session session) message(Session session, MessageTransfer xfr) exception(Session session, SessionException e) closed(Session session)
Receptionarea de mesaje const din a 1. Realizarea conexiunii cu serverul AMQP Connection con = new Connection(); con.connect(broker,port,login,passworg,clientId,false); 2. Instantierea sesiunii Session session = con.createSession(0); 3. Precizarea asculttorului de mesaje (Fie Listener o clasa care implea menteaz interfata SessionListener) a Listener listener = new Listener(); session.setSessionListener(listener); 4. Crearea abonatului care urmeaz s receptioneaze mesaje. Asculttorul a a a va caracterizat de un nume - listener destination. session.messageSubscribe(numeCoada, "listener_destination", MessageAcceptMode.NONE, MessageAcquireMode.PRE_ACQUIRED, null, 0, null); session.messageFlow("listener_destination", MessageCreditUnit.BYTE, Session.UNLIMITED_CREDIT); session.messageFlow("listener_destination", MessageCreditUnit.MESSAGE, 11);
153
5. Ateptarea conrmrii trimiterii tuturor mesajelor disponibile de ctre s a a serverul AMQP session.sync(); 6. Oprirea asculttorului a session.messageCancel("listener_destination"); 7. Inchiderea sesiunii i a conexiunii s session.close(); con.close(); Exemplul 5.7.3 Receptia mesajelor expediate n clasa Sender, creata ante rior. Programul se va termina n momentul n care asculttorul primete un a s mesaj fr continut. a a
1 3 4 6 7 8 9 10 11 12 13 14 15 16 18 19 20 21 23 24 25 26 27 28 29 30 31
import o r g . apache . q p i d . t r a n s p o r t . ; c l a s s L i s t e n e r implements S e s s i o n L i s t e n e r { boolean s f a r s i t =f a l s e ; public void opened ( S e s s i o n s e s s i o n ) { } public void resumed ( S e s s i o n s e s s i o n ) { } public void message ( S e s s i o n s e s s i o n , M e s s a g e T r a n s f e r x f r ) { System . out . p r i n t l n ( Message : + x f r ) ; S t r i n g sMsg=x f r . t o S t r i n g ( ) ; i f ( sMsg . endsWith ( body=\\ ) ) s f a r s i t =true ; } public void e x c e p t i o n ( S e s s i o n ssn , S e s s i o n E x c e p t i o n e ) { System . out . p r i n t l n ( S e s s i o n L i s t e n e r E x c e p t i o n : +e . g e t M e s s a g e ( ) ) ; } public void c l o s e d ( S e s s i o n s e s s i o n ) {} public void run ( ) { while ( ! s f a r s i t ) ; } } public c l a s s R e c e i v e r { public s t a t i c void main ( S t r i n g [ ] a r g s ) throws I n t e r r u p t e d E x c e p t i o n { i f ( a r g s . l e n g t h <3){ System . out . p r i n t l n ( Usage j a v a S en der b r o k e r p o r t queueName ) ; System . e x i t ( 1 ) ; } S t r i n g b r o k e r=a r g s [ 0 ] ; i n t p o r t=I n t e g e r . p a r s e I n t ( a r g s [ 1 ] ) ; S t r i n g queueName=a r g s [ 2 ] ;
154
33 34 35 37 38 40 41 42 44 45 46 47 48 49 50 51 52 53 55 56 58 59 61 62 63 65 66 67 68 69
// Crearea c o n e x i u n i i C o n n e c t i o n con = new C o n n e c t i o n ( ) ; con . c o n n e c t ( b r o k e r , p o r t , t e s t , g u e s t , g u e s t , f a l s e ) ; // Crearea s e s i u n i i S e s s i o n s e s s i o n = con . c r e a t e S e s s i o n ( 0 ) ; // Generarea u n e i i n s t a n t e a a s c u l t a t o r u l u i L i s t e n e r l i s t e n e r = new L i s t e n e r ( ) ; session . setSessionListener ( listener ); // Crearea a b o n a t u l u i c a r e r e c e p t i o n e a z e m e s a j e l e s e s s i o n . m e s s a g e S u b s c r i b e ( queueName , listener destination , MessageAcceptMode .NONE, MessageAcquireMode . PRE ACQUIRED, null , 0 , n u l l ) ; s e s s i o n . messageFlow ( l i s t e n e r d e s t i n a t i o n , M e s s a g e C r e d i t U n i t .BYTE, S e s s i o n . UNLIMITED CREDIT ) ; s e s s i o n . messageFlow ( l i s t e n e r d e s t i n a t i o n , M e s s a g e C r e d i t U n i t .MESSAGE, 1 1 ) ; // Confirmarea t e r m i n a r i i t r a n s m i t e r i i m e s a j e l o r s e s s i o n . sync ( ) ; // A b o n a t u l a s t e a p t a r e c e p t i o n a r e a t u t u r o r m e s a j e l o l i s t e n e r . run ( ) ; // O p r i r e a a s c u l t a t o r u l u i System . out . p r i n t l n ( S h u t t i n g down l i s t e n e r f o r l i s t e n e r d e s t i n a t i o n ) ; s e s s i o n . messageCancel ( l i s t e n e r d e s t i n a t i o n ) ; // I n c h i d e r e a s e s i u n i i s i a c o n e x i u n i i session . close (); con . c l o s e ( ) ; } }
Utiliznd clasele prezentate mai sus, prin xarea convenabil a parametrilor a a i a ordinii de lansare a programelor se poate exemplica specicul celor trei s dispeceri de directionare: Codurile pentru executie prin ant sunt Distribuirea direct: a
<target name="run" depends="compile"> <java classname="DeclareQueue" fork="yes" maxmemory="100M"> <classpath refid="qpid.classpath" /> <arg line="localhost 5672 message_queue amq.direct routing_key"/> </java> <sleep seconds="15" /> <java classname="Sender" fork="yes" maxmemory="100M"> <classpath refid="qpid.classpath" /> <arg line="localhost 5672 amq.direct routing_key 5"/> </java> <sleep seconds="5" />
155
<java classname="Receiver" fork="yes" maxmemory="100M"> <classpath refid="qpid.classpath" /> <arg line="localhost 5672 message_queue"/> </java> </target>
Distribuirea fanout:
<target name="queue"> <java classname="DeclareQueue" fork="yes" <classpath refid="qpid.classpath" /> <arg line="localhost 5672 q1 amq.fanout </java> <java classname="DeclareQueue" fork="yes" <classpath refid="qpid.classpath" /> <arg line="localhost 5672 q2 amq.fanout </java> </target> maxmemory="100M"> xxx"/> maxmemory="100M"> yyy"/>
<target name="sender"> <java classname="Sender" fork="yes" maxmemory="100M"> <classpath refid="qpid.classpath" /> <arg line="localhost 5672 amq.fanout zzz 2"/> </java> </target> <target name="receiver"> <sleep seconds="5" /> <parallel> <java classname="Receiver" fork="yes" maxmemory="100M"> <classpath refid="qpid.classpath" /> <arg line="localhost 5672 q1"/> </java> <java classname="Receiver" fork="yes" maxmemory="100M"> <classpath refid="qpid.classpath" /> <arg line="localhost 5672 q2"/> </java> </parallel> </target>
156
<arg line="localhost 5672 q1"/> </java> <java classname="Receiver" fork="yes" maxmemory="100M"> <classpath refid="qpid.classpath" /> <arg line="localhost 5672 q2"/> </java> </parallel> </target> <target name="sender"> <java classname="Sender" fork="yes" maxmemory="100M"> <classpath refid="qpid.classpath" /> <arg line="localhost 5672 amq.topic unitbv.cs.topic 5"/> </java> </target>
cazul distribuirii fanout i a celei bazate pe publicare-abonare sunt lansate In s ordine dou cozi cu cte un receptor de mesaje (Receiver ) urmat de pron a a ductorul de mesaje (Sender ). a
157
6.1
Transactie http
Protocolul http este de tip client-server: Navigatoarele Google Chrome, Mozilla Firefox, Microsoft Internet Explorer, Opera, Apple Safari sunt aplicatii client uzuale. Informatiile sunt gzduite / generate de servere Web de ctre site-uri a a i servicii Web. Exemple de servere Web sunt apache HTTP Server, s Microsoft Internet Interchange Server. O categorie aparte - esential a pentru platforma Java - este dat de servere Web container de servlet i a s JSP (Java Server Pages). Clientul 159
160
1. stabilete o conexiune cu serverul Web; s 2. trimite o cerere ctre serverul Web; a 3. receptioneaz rspunsul dat de serverul Web; a a 4. nchide conexiunea. Acest ciclu de actiuni se numete tranzactie http. s Serverul nu retine informatii ntre dou tranzactii http. Acest comportaa ment se exprim prin terminologia: protocolul http este fr stare - stateless. a a a Transmisia datelor se realizeaz utiliznd de obicei protocolul TCP. a a Referintele resurselor se indic folosind URI / URL. a Cererile i rspunsurile sunt reprezentate ca linii de text separate de cars a acterul <CR><LF>, avnd structura a 1. preambul - format dintr-o linie; 2. antete (header ) - 0 sau mai multe atribute (nume:valoare); 3. o linie goal; a 4. corpul mesajului - optional. Preambulul unei cereri contine: 1. numele metodei {GET, POST, PUT, DELETE, HEAD, CONNECT, TRACE, OPTIONS}; 2. referinta resursei (URL); 3. Versiunea protocolului http. Preambulul unui rspuns contine: a 1. Versiunea protocolului http; 2. codul rspunsului: numr natural format din trei cifre cu semnicatiile a a Categoria 1** 2** 3** 4** 5** Indic a mesaj de informare mesaj de succes redirectare ctre alt URL a eroare in mesajul clientului eroare din partea serverului
161
3. String explicitnd codul rspunsului. a a Un antet (header ) este un atribut, adic o pereche (nume:valoare). Proa tocolul http denete o palet larg de atribute. Exemple de antete sunt date s a a in tabelul urmator: Antet Semnicatie Exemplu host Gazda i portul serverului Web s 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 limb pentru elegerea a a nt continutului 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 continutul este a imagine, cod binar, etc., atunci acesta este codicat text. n Codul Multipurpose Internet Mail Exchange (MIME) precizeaz natura a continutului unei resurse: text/plain text/html text/xml image/png image/jpg application/octet-stream application/x-www-form-urlencoded Ne prounem s punem evident mesajele http. a n a
162
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 ( ) ) ; } } }
Rezultatul cererii depinde de metoda GET sau POST utilizat formulaa n rul html folosit. Pentru metoda GET cererea http este
GET /apphello/hello?name=mk&tip=text%2Fhtml HTTP/1.1 Host: localhost:8080 Connection: keep-alive User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.106 Safari/535.2
163
<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
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 ;
164
8 10 11 12 13 14 15 16 17 18 19 20 21 22 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 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
import j a v a . u t i l . S c a n n e r ; 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 : keepa l i v e \ r \n+ UserAgent : 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+ AcceptEncoding : g z i p , d e f l a t e , sdch \ r \n+ AcceptLanguage : enUS , en ; q =0.8\ r \n+ AcceptC h a r s e t : ISO88591, 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 : keepa l i v e \ r \n+ ContentLength : 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+ UserAgent : 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+ ContentType : a p p l i c a t i o n /xwww formu 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+ AcceptEncoding : g z i p , d e f l a t e , sdch \ r \n+ AcceptLanguage : enUS , en ; q =0.8\ r \n+ AcceptC h a r s e t : ISO88591, 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 ) ; 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 ) ; }
165
67 68 69 70 71 72 73 74 75 76 77 78 79
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
prezent sunt disponibile mai multe servere Web care poate instalat In n un servlet i un ier JSP Java Server Pages. Despre un asemenea server Web s s se spune ca este container de servlet i JSP. Dintre produsele gratuite amintim s apache-tomcat jetty glasssh Acest server Web este utilizat Glassshv3 - o implementare JEE (Java n Enterprise Edition) de la Oracle. JBoss Geronimo, o alta implementare JEE dezvoltat de fundatia apache, poate a utiliza containerul apache-tomcat sau jetty. Serverul Apache HTTP Server i Windows Internet Information Server nu s sunt servere Web containere se servlet i JSP. s
166
6.3
continuare se va folosi serverul Web apache-tomcat, pe scurt tomcat. In Serverul Web tomcat este distribuit gratuit, putnd descrcat de la adresa a a www.apache.org. Instalarea serverului mediul Windows revine la dezarhivarea ierului n s descrcat apache-tomcat-***, a ntr-un catalog TOMCAT HOME. Utilizarea serverului necesit xarea a doi parametri sistem: a CATALINA HOME= calea la catalogul care s-a instalat produsul - TOMCAT HOME; n JAVA HOME=calea la distributia Java utilizat. a Pachetul contine cataloagele1 : bin, common, conf, logs, server, shared, temp, webapps, work. Serverul se lanseaz prin comanda a TOMCAT HOME\bin\startup i se oprete cu comanda s s TOMCAT HOME\bin\shutdown Din catalogul TOMCAT HOME, lansarea se poate obtine cu ajutorul ierului s de comenzi (*.bat) set CATALINA_HOME=. . . set JAVA_HOME=. . . bin\startup Optional se poate instala / activa managerul / administatorul serverului Web tomcat. Vericarea functionrii serverului Web tomcat se face apelnd dintr-un nav a a igator pagina http://host:port unde host este numele calculatorului pe care ruleaz tomcat; a Portul implicit este 8080. Reuita este ilustrat de imaginea motanului s a
168
Interfata grac, cazul extinderii clasei Applet, va utiliza controlurile a n apartinnd interfetei de programare AWT (Abstract Window Toolkit), iar a n cazul extinderii clasei JApplet se vor utiliza controluri Swing.
7.1
Clasa Applet
Structura unui applet este import java.applet.*; import java.awt.*; public classNumeClas extends Applet{ a public void init(){ Actiuni efectuate la instantierea clasei applet-ului. } public void start(){ Actiuni efectuate la lansarea applet-ului n executie sau la rentoarcerea n pagina applet-ului. } public void paint(Graphics g){ Actiuni efectuate ori de cte ori este necesar re a a desenarea ferestrei applet-ului. } public void stop(){ Actiuni efectuate la oprirea applet-ului, ca urmare a nchiderii ferestrei corespunztoare applet-ului. a } public void destroy(){ Actiuni efectuate la distrugerea applet-ului, ce au loc cnd navigatorul prsete documentul html din care s-a a a a s apelat applet-ul. } } Executarea applet-ului este controlat de programul navigator i revine la s apelarea metodelor init, start, stop. Acest fenomen se numete invers sarea controlului.
169
7.2
Prin desfurarea (deployment) unei aplicatii se elege realizarea strucas nt turilor de cataloage i iere dar i a operatiilor care trebuie s s s ntreprinse n vederea functionrii unei aplicatii distribuite. a Desfurarea unui applet se poate face mai multe feluri: as n Varianta 1 1. Arhivarea ierelor class ale applet-ului. s 2. Editarea ierului html de apelare a applet-ului. Sablonul specic apelrii s a applet-ului este
<BODY> . . . <script src="http://java.com/js/deployJava.js"></script> <script> var attributes={ code:numele_clasei_Applet, archive:numele_arhivei_jar,width:...,height:...}; var parameters={. . .}; var minimumVersion=1.6; deployJava.runApplet(attributes, parameters, minimumVersion); </script> . . . </BODY>
3. Cele dou iere se depun a s ntr-un catalog al unui server Web, asigurnd a vizibilitatea aplicatiei Internet. n Vericarea aplicatiei se poate face, dintr-un program navigator, prin sim pla apelare a ierului html. acest caz, calculatorul trebuie s e s In a conectat la internet. Dac dispunem de deployJava.js atunci acest ier se altur celorlalte a s a a dou resurse, iar atributul src al elementului script va src="deployJava.js". a Exemplul 7.2.1 Hello +nume. Numele se transmite miniaplicatiei ca parametru. Codul applet-ului este:
170
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 ) ; } }
< T L H M> < E D HA> <TITLE H e l l o </TITLE > > </H A > E D <O Y B D> <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> </B D > O Y </H M > T L
Varianta 2 Pe aceast cale se va edita un ier de congurare cu extensia jnlp. Rea s alizarea applet-ului const din: a 1. Arhivarea ierelor class ale applet-ului. s 2. Editarea unui ier de congurare jnlp. Structura acestui ier este s s <?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"
171
max-heap-size="128m" /> <jar href="numele_arhivei_jar" main="true" /> </resources> <applet-desc name="numele_simbolic_al_applet-ului" main-class="clasa_principala_a_applet-ului" width="latimea_ferestrei_applet-ului" height="inaltimea_ferestrei_applet-ului"> </applet-desc> </jnlp> 3. Editarea ierului html de apelare a applet-ului. Sablonul specic apelrii s a 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>
4. Cele trei iere (eventual patru cu deployJava.js) se depun s ntr-un catalog al unui server Web, asigurnd vizibilitatea aplicatiei Internet. a n Exemplul 7.2.2 Calculul celui mai mare divizor comun a dou naturale. a Introducerea datelor exterioare se face prin intermediul unei interfete grace. Applet-ul extinznd clasa Applet are codul a
1 2 3 5 6 8 9 10
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 ) ;
172
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
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 ) { . . . } }
import j a v a . awt . ; import j a v a x . swing . ; import j a v a . awt . e v e n t . ; public c l a s s VisualCmmdc extends JApplet implements A c t i o n L i s t e n e r { J 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 ( ) ; content . setBackground ( Color . yellow ) ; s e t L a y o u t (new GridLayout ( 3 , 2 , 3 0 , 2 0 ) ) ; J L a b e l lm=new J L a b e l ( Primul numar : ) ; c o n t e n t . add ( lm ) ; tm=new J T e x t F i e l d ( 1 , 5 ) ; c o n t e n t . add ( tm ) ; J L a b e l l n=new J L a b e l ( Al d o i l e a numar : ) ; c o n t e n t . add ( l n ) ; tn=new J T e x t F i e l d ( 1 , 5 ) ; c o n t e n t . add ( tn ) ; JButton compute=new JButton ( 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 ) ; c o n t e n t . add ( compute ) ; r e z=new J T e x t F i e l d ( 1 , 5 ) ; rez . setEditable ( false ) ;
173
25 26 27 29 30 31 32 33 34 35 36 38 39 40 42 43
c o n t e n t . add ( r e z ) ; s e t V i s i b l e ( true ) ; } 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 Lon g ( 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 ) { . . . } }
<?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 t t p : // l o c a l h o s t : 8 0 8 0 /cmmdc 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 maxheaps 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> <a p p l e t d e s c name=VisualCmmdc Applet mainc 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>
<html> <body b g c o l o r=# AAEEAA> <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= 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>
174
14
</ html>
<HTML > <BODY BGCOLOR =# AAEEAA> <CENTER > < ! <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> d e p l o y J a v a . l a u n c h ( cmmdc . j n l p ) ; </ s c r i p t> > <a h r e f= h t t p : // l o c a l h o s t : 8 0 8 0 /cmmdc/cmmdc . j n l p > App CMMDC </ a> </CENTER > </BODY > </HTML >
O alternativ (depit) la modurile de apelare al applet-ului descrise ana as a terior este prin utilizarea elementului html <applet>. Atributele obligatorii ale unui element applet sunt code Valoarea atributului este numele clasei applet-ului. width Valoarea atributului este limea ferestrei atribuit de navigator appletat a ului la aarea documentului html. s height Valoarea atributului este altimea ferestrei atribuit de navigator appletn a ului la aarea documentului html. s Atribute optionale sunt codebase Valoarea atributului este adresa URL ( Universal Resource Locator) sau calea la ierul cu clasa applet-ului. lipsa acestui parametru, cutarea s In a clasei are loc catalogul din care a fost arcat sursa html. n nc a vspace Valoarea atributului este lungimea, exprimat pixeli, care se las liber a n a a deasupra i dedesuptul ferestrei miniaplicatiei. s
175
hspace Valoarea parametrului este lungimea, exprimat pixeli, care se las a n a liber la stnga i la dreapta ferestrei applet-ului. a a s marcajul <applet> prin intermediul elementului <param> pot inIn clui parametri ce pot preluati de applet. Un parametru se denete prin s s atributele: name Valoarea atributului este numele variabilei recunoscut applet. a n value Valoarea atributului este valoarea receptionat de applet i este de tip a s String. Preluarea se realizeaz cu metoda a public String getParameter(String name) Documentul html de apelare al applet-ului Inceput este:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
< T L H M> < E D HA> <TITLE H e l l o > </H A > E D <O Y B D> < CENTER > < APPLET code = width = height = </APPLET > </CENTER > </B D > O Y </H M > T L
</TITLE >
Dac ierul class al applet-ului nu se a acelai catalog cu documentul a s a n s html atunci localizarea clasei se face cu valoarea atributului codebase = "file://host/calea ctre catalogul clasei applet-ului" a Pentru testare, locul navigatorului se poate folosi programul appletviewer.exe n din distributia jdk.
7.3
Se pot apela functii JavaScript denite documentul html din care se n apeleaz applet-ul. a
176
Prin intermediul unui obiect de tip netscape.javascript.JSObject, creat prin static JSObject getWindow(java.applet.Applet applet) se apeleaz metoda a call(String numeFunctieJavaScript, java.lang.Object[] args). Sablonul de utilizare este import netscape.javascript.*; public void init(){ . . . JSObject window=JSObject.getWindow(null); window.call("numeFunctieJavaScript",args); . . . } Pachetul netscape.javascript se a distributia jdk catalogul JAVA HOME\ a n n jre\lib\plugin.jar. Pentru compilare, variabila de sistem classpath trebuie s contin aceast referinta. a a a
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 un obiect URL legat de resursa specicat de spec, care trebuie s a a a e o referint URL valid. a a Metode InputStream openStream() throws IOException Returneaz uxul de intrare pentru citirea resursei. a URLConnection openConnection() throws IOException Returneaz o instanta a conexiunii cu obiectul denit de URL. a
1
177
178
Exemplul 8.1.1 Pe baza referintei ctre un ier html dintr-un catalog vizibil a s al unui server Web, s se aeze continutul ierului. a s s codul reprodus mai jos, ierul Hello.html se a pe serverul apacheIn s a tomcat, catalogul webapps\url. n
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
im po rt j a v a . n e t . ; im po rt j a v a . i o . ; 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 ( ) ) ; } } }
cazul care resursa - exemplul dat reprezentat de ierul Hello.html In n n s - este accesibil doar urma autenticrii basic sau digest (Cap. Servlet, n a Autenticare, 9.4.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()); } });
Nici acest caz nu putem vorbi de o aplicatie client-server. n Un exemplu privind utilizarea clasei java.net.HttpURLConnection este dat capitolul Servlet. n
Capitolul 9 Servlet
Printre aplicatiile distribuite de tip client-server, care comunicatiile se n bazeaz pe protocolul http, se disting a Aplicatii Web (site): Cererea adresat serverului este lansat de o per a a soan utiliznd un program navigator: Google Chrome, Mozilla Firefox, a a Microsoft InternetExplorer, Opera, Apple Safari, etc. Servicii Web: Cererea ctre server se face de un program. Aplicatia a server i client se programeaz utiliznd interfete de programare specice. s a a Un servlet este un program Java care se excut pe un server Web, compatibil; a gestionat de serverul Web; capabil s receptioneze i s rpund cererilor formulate de clienti. a s a a a De asemenea vom utiliza termenul servlet i pentru aplicatia Web corespunztoare. s a Pe platforma de programare Java, servlet-ul este componenta care st la a baza dezvoltrii aplicatiile i serviciile Web. a s Programarea i utilizarea unui servlet necesit: s a Cunoaterea marcajului html <form> pentru realizarea formularelor de s introducere a datelor; Utilizarea unui server Web, container de servleti. 179
180
CAPITOLUL 9. SERVLET
9.1
Marcajul <form>
Intr-un document html introducerea datelor se poate obtine utiliznd mar a cajul <form> ...</form> . Atribute ale marcajului <form> . Reamintim c atributele se prezint a a ca perechi (nume, valoare) i se scriu antetul marcajului sub forma nume = s n valoare. Nume action method Valoare adresa tip URL GET Semnicatia valorii Resursa care prelucreaz formularul. a Mesajul trimis serverului Web contine dup a adresa URL numele i valorile parametrilor s introdui. Adugarea se face potrivit sintaxei s a ?numeParam1=valoare&numeParam2=valoare. . . Lungimea mesajului nu poate depi 255 caractere. as Transmisia datelor se face uxuri de date. n Permite transferul unor iere de pe maina s s clientului pe maina serverului. s Parametru de identicare a formularului (optional). Nume atribuit formularului (optional). Metod JavaScript executat a a naintea apelrii a serverului Web (optional).
POST
id name onSubmit
continutul marcajului <form> putem include elemente de control In prin marcajele <input> <option> <select> <textarea> Atributele marcajului < input> sunt:
181
Nume type
Valoare Semnicatie text Se ateapt introducerea unui text s a password Se ateapt introducerea unei parole s a submit Se marcheaz sfritul completrii formularului a as a reset Se reinitializeaz formularul a file Permite selectarea unui ier s hidden Transmite mai departe un atribut fr vizualizarea lui aa name numele controlului value valoarea (initial) a controlului a size numrul caracterelor ataat controlului a s cazul marcajului < select> utilizarea este In <select name="nume"> <option value="valoare"> Valoare . . . . . . . . . . . . . . . . </select> Valoarea atributului nume este dat de valoarea selectat. a a
9.2
Interfata de programare (API) pentru servlet a ajuns la versiunea 3, versi une pe care o vom utiliza cele ce urmeaz. Aceast interfata de programare n a a nu face parte din JDK, ind implementat de ecare productor de server Web a container de servlet. Structura minimal a unui servlet este a catalogAppServlet |--> WEB-INF | |--> classes | | | *.class | |--> lib | | | *.jar | index.html Catalogul classes contine ierele class ale aplicatiei servlet. s Catalogul lib este optional i va contine resursele jar suplimentare cerute s de clasele servlet-ului. Prin intermediul ierului index.html se apeleaz aplicatia servlet. Adresa s a de apelare (URL - Universal Resource Locator ) a aplicatiei servlet este
182 http://host:port/catalogAppServlet
CAPITOLUL 9. SERVLET
Dac loc de index ierul html de apelare are alt nume, de exemplu xyz.html a n s atunci adresa de apelare va http://host:port/catalogAppServlet/xyz.html host este numele calculatorului pe care ruleaz serverul Web - gazda aplicatiei a servlet. Portul implicit utilizat de un server Web container de servlet este 8080. Catalogul aplicatiei este denumit context-ul servlet-ului. Apelarea servlet-ului se poate face: din meniul File/Open al unui navigator; ca referinta ntr-un document html <a href="URL-servlet">...</a> Din documentul html pomenit anterior, apelarea clasei servlet se face uzual prin intermediul atributului action a elementului form. Valoarea atributului este numele de apel al servlet-ului. Legtura cu clasa servlet-ului se poate realiza a programat prin adnotri codul servlet-ului; a n descriptiv catalogul WEB-INF se editeaz ierul web.xml. n a s versiunile anterioare ale interfetei de programare servlet aceasta a fost In unica optiune. Trebuie demarcat diferenta dintre apelarea / lansarea executie a clasei a n servlet de apelarea aplicatiei Web. Modul programat se bazeaz pe adnotarea javax.servlet.annotation.WebServlet a cu elementele: String name String[ ] urlPatterns @WebInitParams[ ] initParams boolean asyncSupported long asyncTimeout ierul web.xml apar elementele Modul descriptiv In s 1. <servlet> leag numele servlet-ului denit elementul <servlet-name> a n de clasa servlet-ului dat elementul <servlet-class> . n
183
2. <servlet-mapping> denete numele sub care servlet-ul identicat prin s <servlet-name>nume servlet< /servlet-name> se invoc din prograa mul navigator. Acest identicator - numeApel - se xeaz elementul a n <url-pattern> . Identicatorul are ca prex caracterul / (slash). Structura unui ier web.xml este s
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/XMLSchemai 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> pot corespunde mai multe elemente <servlet-mapping>, i prin utilizarea de numeApel diferite. Optional web.xml poate contine elementul
<welcome-file-list> <welcome-file> fisier.html sau jsp </welcome-file> </welcome-file-list>
cu precizarea ierelor html sau jsp care apeleaz aplicatia Web. Declaratia s a ierului index.html este implicit. s a Compilarea clasei servlet necesit completarea variabilei de mediu classpath a cu ierul TOMCAT HOME\lib\servlet-api.jar. s Odat completat structura de cataloage i iere ale aplicatiei servlet a a s s aceast structur trebuie copiat catalogul TOMCAT HOME\webapps. Aceast a a a n a operatie se numete desfurarea (deployment) sau instalarea servlet-ului. s as Copierea se poate executa i cu serverul Web pornit. s Pentru instalarea unui servlet exist mai multe alternative: a Din catalogul catalogAppServlet se realizeaz arhiva catalogAppServlet.war a
184
CAPITOLUL 9. SERVLET
jar cfv catAppServlet.war WEB-INF\ index.html care se copiaz catalogul TOMCAT HOME\webapps. a n Serverul Web tomcat va dezarhiveaza arhiva. Astfel servlet-ul este instalat. Aceast instalare se numete instalare dinamic - hot deployment. a s a Dac ierul war este creat, atunci locul copierii, instalarea se poate a s n face prin componenta manager a lui tomcat. O alt posibilitate de instalare a unui servlet serverul web tomcat a n este prin intermediul produsului apache-tomcat-deployer. apache-tomcatdeployer permite instalarea unui servlet de la distanta ct i instalarea a s comandat dintr-un program. a
apache-tomcat-*.*.*-deployer se instaleaz prin dezarhivarea ierului apache-tomcat-*.*.*-deployer. a s Posibilitile oferite de apache-tomcat-*.*.*-deployer se obtin rulnd ant cu un ierul build.xml at a s din distributia produsului. Obiectivele care pot atinse sunt compilarea unui servlet - compile instalarea unui servlet - deploy dezinstalarea unui servlet - undeploy prealabil trebuie completat ierul de proprieti deployer.properties cu In s at build=catalogul care va contine rezultatul compilrii i al arhivrii. a s a webapp=catalogul cu sursa servlet-ului. path=/catalog-ul servlet-ului. url=url-ul aplicatiei manager din Tomcat http://host:8080/manager username=numele de acces manager-ul din Tomcat. n password=parola pentru manager-ul din Tomcat.
9.2.1
Un servlet implementeaz interfata Servlet sau extinde una din clasele a GenericServlet sau HttpServlet. GenericServlet implementeaz interfata a Servlet, iar HttpServlet extinde clasa GenericServlet. Extinznd clasa a GenericServlet nu este nevoie de rescrierea tuturor metodelor abstracte ale intrefetei Servlet. Metodele interfetei Servlet sunt abstract public void init(ServletConfig cong) Se apeleaz o singur dat la lansarea servlet-ului. a a a
185
abstract public void service(ServletRequest req, ServletResponse res)throws ServletException,IOException Metoda este apelat de serverul Web pentru rezolvarea cererii unui client. a abstract public void destroy() Se apeleaz o singur dat la distrugerea servlet-ului. a a a public String getServletInfo() public ServletConfig getServletConfig() cele ce urmeaz o clasa servlet va o clas care extinde clasa HttpServlet. In a a locul metodei service(...), programatorul suprascrie metodele doGet(...) In sau doPost(...), functie de metoda utilizat de client la lansarea cererii. n a Practic, un servlet const din scrierea metodelor a void init(ServletConfig cong) Aceast metod este optional. a a a public void init(ServletConfig config) throws ServletException{ super.init(config); // cod de initializare } Obiectul cong are o metod String getInitParameter(String nua meParam) cu ajutorul creia se pot recupera parametri de initializare a asociati servlet-ului i care se dau e prin adnotarea WebInitParam prin s ablonul s import javax.servlet.annotation.WebInitParam; @WebServlet(urlPatterns = "/numeApel", initParams = { @WebInitParam(name = "numeParam", value = "valoareParam"), . . . } ) e ierul web.xml prin elementele n s
186
CAPITOLUL 9. SERVLET
<init-param> <param-name> NumeleParametrului </param-name> <param-value> Valoare </param-value> </init-param> cuprinse elementul <servlet>. n protected void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException Trateaz o cerere trimis cu metoda GET (vezi marcajul <form>). a a protected void doPost(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException Trateaz o cerere trimis cu metoda POST (vezi marcajul <form>). a a Activitile de at ntreprins ntr-o metod doGet() sau doPost() sunt a 1. Stabilirea naturii rspunsului: a res.setContentType(String tip) unde tip specic tipul MIME - Multipurpose Internet Mail Extensions a al rspunsului: a "text/html" - pagin html; a "text/xml" - document xml; "text/plain" - text; "image/jpg" - imagine gif; "image/gif" - imagine jpg. 2. Se obtine o referinta ctre un obiect care realizeaza transmisia datelor a ctre navigatorul clientului: a ServletOutputStream out = res.getOutputStream(); sau PrintWriter out=res.getWriter(); 3. Se preiau datele cererii cu una din metodele: String getParameter(String numeParapetru) java.util.Enumeration getParameterNames() 4. Rezolv cererea clientului; a
187
5. Formeaz i scrie rspunsul; as a 6. Inchide conexiunea obiectului prin care s-a realizat transmisia datelor ctre navigatorul clientului prin out.close(). a Un utilizator lanseaz o cerere ctre servlet. De obicei acest lucru se rea a alizeaz prin completarea unui formular al unui document html. Programul a navigator trimite cererea serverului Web prin intermediul cruia este lansat a servlet-ul actiune. n Ciclul de viat al unui servlet. Cnd un servlet este apelat prima a a dat de ctre serverul Web se execut metoda init. Dup aceasta, ecrei a a a a a cereri lansate de un utilizator i se asociaz un r de executie care se apea n leaz metoda service. Metoda service apeleaz apoi metodele doGet(), a a doPost(). Exemplul 9.2.1 Servlet-ul Hello: Clientul transmite numele servet-ului care rspunde cu mesajul de salut Hi + nume!. i a 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
<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 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 > </form> </ center> </body> </html>
@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> ) ;
188
CAPITOLUL 9. SERVLET
14 15 16 17 18 19 20 21 22 23 25 26 27 28 29
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> ) ; p r i n t l n ( <body> ) ; p r i n t l n ( <h1>H e l l o S e r v l e t </h1> ) ; p r i n t l n ( <p> ) ; p r i n t l n ( Hi + nume+ ! ) ; p r i n t l n ( </p> ) ; p r i n t l n ( </body> ) ; p r i n t l n ( </html> ) ; close ();
<?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/XMLSchemai 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 i arhivarea servlet-ului o vom realiza prin intermediul lui s acest scop se creaz structura: apache-ant. In a
hello | |---> src | | | HelloServlet.java | |---> lib | |---> web | | | web.xml | |---> web-files | | | index.html | build.xml
<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= . . . / apachetomcat . . /> <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 r o p e r t y name= d i s t . d i r v a l u e= d i s t /> <p r o p e r t y name= b u i l d . d i r v a l u e= b u i l d /> <path i d= m y c l a s s p a t h > < f i l e s e t d i r= 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 />
189
12 14 15 16 17 18 19 20 21 23 24 25 26 27 28 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
</ 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 } /> <mkdir d i r= ${ b u i l d . d i r } /> <mkdir d i r= ${ d i s t . d i r } /> <mkdir d i r= ${ b u i l d . d i r }/WEB INF /> <mkdir d i r= ${ b u i l d . d i r }/WEB INF/ c l a s s e s /> <mkdir d i r= ${ b u i l d . d i r }/WEB INF/ l i b /> </ 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= ${ b a s e d i r }/ s r c d e s t d i r= ${ b u i l d . d i r }/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> <t a r g e t name= g e n e r a t e . war depends= c o m p i l e > <copy t o d i r= ${ b u i l d . d i r } > < f i l e s e t d i r= ${ b a s e d i r }/web f i l e s > <i n c l u d e name= . html /> </ f i l e s e t> </ copy> <copy t o d i r= ${ b u i l d . d i r }/WEB INF f i l e = ${ b a s e d i r }/web/web . xml /> <copy t o d i r= ${ b u i l d . d i r }/WEB INF/ l i b > < f i l e s e t d i r= ${ b a s e d i r }/ l i b > <i n c l u d e name= . j a r /> </ f i l e s e t> </ copy> <j a r d e s t f i l e = ${ d i s t . d i r }/${ d i s t . name } . war b a s e d i r= ${ b u i l d . d i r } /> </ t a r g e t> </ p r o j e c t>
Observatie. Valoarea parametrului dist.name denete parametrul catalo s gAppServlet. Se lanseaz executie serverul Web tomcat, se a n ncarc servlet-ul serverul a n Web i dintr-un navigator se deschide pagina http://localhost:8080/apphello s Exemplul 9.2.2 Servlet pentru calculul celui mai mare divizor comun a dou a numere.
1 2 3 4 6 7 9 11 12 13
@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 ) 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 ) ;
190
CAPITOLUL 9. SERVLET
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 35 36 37 38 39
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 ) ; } }
<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 sm=document . cmmdc .m. value ; var sn=document . cmmdc . n . value ; i f (sm== ) { a l e r t ( L i p s e s t e p r i m u l numar ! ) ; return f a l s e ; } i f ( sn== ) { a l e r t ( L i p s e s t e a l d o i l e a numar ! ) ; return f a l s e ; } i f ( ! IsNumeric (sm ) ) { a l e r t ( Primul numar e s t e g r e s i t i n t r o d u s ! ) ; return f a l s e ; } i f ( ! IsNumeric ( sn ) ) { a l e r t ( Al d o i l e a numar e s t e g r e s i t i n t r o d u s ! ) ; return f a l s e ; } return true ; } f u n c t i o n IsNumeric ( s T e x t ) { // J e f f Anderson // A j a v a s c r i p t v a l i d a t i o n f u n c t i o n t o c h e c k w h e t h e r t h e d e t a i l s // e n t e r e d by a u s e r a r e numeric ( 2 0 0 2 )
191
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
ValidChars = 0123456789. ; IsNumber=t r u e ; Char ; ( i = 0 ; i < sText . l e n g t h && IsNumber == t r u e ; i ++){ Char = sText . charAt ( i ) ; i f ( V a l i d C h a r s . i n d e x O f ( Char ) == 1){ IsNumber = f a l s e ; }
} r e t u r n IsNumber ; } // > </ s c r i p t> < 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 name=cmmdc onSubmit= r e t u r n c h e c k I t ( ) > <p>Primul numar e s t e <input type= t e x t name=m 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 s i z e=5> <p><input type= submit value= C a l c u l e a z a > <input type= h id de n name= t i p value= t e x t / html > </form> </ center> </body> </html>
Pentru xarea naturii rspunsului text/html sau text/plain s-a introdus a variabila tip, care ierul de invocare index.html primete pe ascuns valoarea n s s cazul care vom apela servlet-ul dintr-un program, va text/html. In n avantajos s primim rspunsul ca text/plain. a a
9.3
Rezolvarea unei cereri adresat de un client unui servlet se execut de ctre a a serverul Web ntr-un r de executie. Aceast executie este sincron sensul a a n care trecerea la instructiunea urmtoare are loc doar la incheierea executiei n a instructiunii curente. Interfata de programare Servlet 3.0 ofer posibilitatea unui executii asin a crone. Acest mod de executie se indic prin adnotarea a @WebServlet(urlPaterns="/numeApel " ,asyncSupported=true) Suportul asincron necesit un context, obiect de tip AsyncContext a AsyncContext asyncCtx=req.startAsync(req,res); Activitile ce trebuie at ndeplinite pentru satisfacerea cererii clientului se lanseaz a ntr-un r de executie, obiect care este parte a unei familii gestionate de o clas ce implementeaz interfata Executor: a a
192
CAPITOLUL 9. SERVLET
public ScheduledThreadPoolExecutor(int corePoolSize) public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) Interfata AsyncListener permite noticarea evenimentelor void onComplete(AsyncEvent ae) void onTimeout(AsyncEvent ae) void onError(AsyncEvent ae) void onStartAsync(AsyncEvent ae) Obiectul de tip AsyncEvent este creat momentul satisfacerii cererii clientun lui, depirii timpului alocat sau producerii unei erori. as Exemplul 9.3.1 Varianta asincrona a servlet-ului de calcul a celui mare divizor comun.
1 2 3 4 5 6 7 9 10 11 12 13 14 15 16 17 18 19 21 22 23 24 25
package m y s e r v l e t ; 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 ; import j a v a . u t i l . c o n c u r r e n t . ; import j a v a . i o . IOException ; import l i s t e n e r s . ; @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 ThreadPoolExecutor ( 1 0 , 1 0 , 5 0 0 0 0 , TimeUnit . MILLISECONDS, new LinkedBlockingQueue<Runnable > ( 1 0 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 ) ; } }
193
1 2 3 4 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 34 35 36 38 39
package m y s e r v l e t ; 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 . i o . ; public c l a s s AsyncWebService implements Runnable { AsyncContext asyncCtx ; public AsyncWebService ( AsyncContext asyncCtx ) { t h i s . asyncCtx=asyncCtx ; } public void run ( ) { 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 ( ) ;
194
CAPITOLUL 9. SERVLET
18 19 20 22 23 24 25 26 28 29 30 31 32 33
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 ) ; 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
Apelarea unui servlet dintr-un program Java adic lansarea unei cereri i a s receptionarea rspunsului furnizat de servlet se poate obtine a sincron cu produsul httpcomponents-client, asincron cu produsul httpcomponents-asyncclient. Ambele produse sunt dezvoltat de apache. Caracterul sincron / asincron const faptul c receptia i prelucrarea a n a s rspunsului oferit de servlet are loc metoda din care s-a lansat cererea, a n respectiv ntr-un alt obiect. Intr-un asemenea caz, din punctul de vedere al clientului este mai avantajos ca rspunsul servlet-ului e text/plain, loc de text/html. a n Cazul sincron Catalogul lib din httpcomponents-client contine, printre altele, ierele s httpcore-*.jar, httpclient-*.jar, commons-logging-*.jar. Pentru compilare trebuie declarat variabila de sistem classpath referinta a n ctre httpclient-*.jar i httpcore-*.jar dar pentru executie este nevoie i de a s s referinta ctre commons-logging-*.jar. a Dezvoltarea unui client presupune: 1. Crearea unui obiect de tip org.apache.http.client.HttpClient:
195
HttpClient client=new DefaultHttpClient(); DefaultHttpClient apartine pachetului org.apache.http.impl.client. 2. Declararea metodei de transmitere a datelor get, post. GET HttpGet httpget = new HttpGet(uri); unde uri este String-ul de apelare a servlet-ului, de forma http://host:port/catalog/numeApel?numeParam=valParam&. . . , O solutie mai elegent este a 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(. . .){. . .}
196 cu uri=http://host:port/catalog/numeApel.
CAPITOLUL 9. SERVLET
Clasele HttpGet, HttpPost apartin pachetului org.apache.http.client.methods. 3. Lansarea cererii. HttpResponse response=httpclient.execute(httpget); respectiv HttpResponse response=httpclient.execute(httppost); 4. Preluarea rspunsului. a 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.4.1 Dezvoltm un program client pentru servlet-ul CmmdcServlet a (post).
1 2 3 5 6 7 8 9 10 11 12 14 16 17 19 20 21
import j a v a . u t i l . S c a n n e r ; import j a v a . u t i l . L i s t ; import j a v a . u t i l . A r r a y L i s t ; import import import import import import import import o r g . apache . h t t p . H t t p E n t i t y ; o r g . apache . h t t p . HttpResponse ; o r g . apache . h t t p . c l i e n t . 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 . impl . c l i e n t . D e f a u l t H t t p C l i e n t ; o r g . apache . h t t p . NameValuePair ; o r g . apache . h t t p . message . BasicNameValuePair ; 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 ) ; =
197
22 23 24 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
S t r i n g m canner . nextLine ( ) . trim ( ) ; =s 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 ( ) ; // C r e a t e an i n s t a n c e o f H t t p C l i e n t . H t t p C l i e n t h t t p c l i e n t = new D e f a u l t H t t p C l i e n t ( ) ; // C r e a t e a method i n s t a n c e . 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 ) ) ; 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 ) ; HttpResponse r e s p o n s e=h t t p c l i e n t . e x e c u t e ( h t t p p o s t ) ; 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 c a n n e r . nextLong ( ) ; =s 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 =+ +&n=+n+&t i p=t e x t / p l a i n ; m 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 ;
198
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 ( ) ;
CAPITOLUL 9. SERVLET
26 27 28 29 30 31 32 33 34 35 36 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
} 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 ; 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 ( ContentType , a p p l i c a t i o n /xwww formu 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 contine referentele ctre erele jar aate catalogul a s n lib din httpcomponent-asyncclient. Programarea const din a 1. Crearea unei instante a clasei org.apache.http.nio.client.HttpAsyncClient HttpAsyncClient httpclient = new DefaultHttpAsyncClient(); httpclient.start(); 2. Lansarea unei cereri apelnd o metod execute: a a <T> Future<T> execute(
199
org.apache.http.nio.protocol.HttpAsyncRequestProducer requestProducer, org.apache.http.nio.protocol.HttpAsyncResponseConsumer<T> responseConsumer, org.apache.http.concurrent.FutureCallback<T> callback ) O instanta de tip HttpAsyncRequestProducer se obtine prin HttpAsyncMethods.createGet(uri) Drept instanta a clasei HttpAsyncResponseConsumer poate o clas ce a extinde clasa org.apache.http.nio.client.methods.AsyncCharConsumer. Exemplul 9.4.2
1 3 4 5 6 7 8 9 11 12 13 15 16 18 19 20 21 22 23 24 26 27 28 29 30 31 32 33 34 35 36 37 38
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 . D e f a u l t 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 . n i o . c l i e n t . 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 . 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 . ; 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 ) ; = S t r i n g m canner . nextLine ( ) . trim ( ) ; =s 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 =+ +&n=+n+&t i p=t e x t / p l a i n ; m H t t p A s y n c C l i e n t h t t p c l i e n t = new D e f a u l t H t t p A s y n c C l i e n 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 ) ; }
200
CAPITOLUL 9. SERVLET
39 40 41 42 43 44 45 47 48 49 50 52 53 54 55 56 57 58 59 61 62 63 65 66 67 68 69 70
System . out . p r i n t l n ( S h u t t i n g down ) ; } finally { h t t p c l i e n t . shutdown ( ) ; } 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 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.4.2
Servlete antuite nl
Un servlet apeleaz la un moment dat alt servlet. Sablonul de lucru este a RequestDispatcher dispatcher= getServletContext().getRequestDispatcher("/url_pattern_servlet_apelat"); if(dispatcher!=null) dispatcher.include(request,response); Exemplul 9.4.3 Un servlet VerifServlet veric parametri cererii. Pentru a problema calculului celui mai mare divizor comun a dou numere, dac cei doi a a parametri sunt numere ntregi, atunci se apeleaz servlet-ul ComputeServlet, a altfel se formeaz un mesaj de eroare. a Codurile celor dou servlete sunt: a VerifServlet.java
201
1 2 3 4 5 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 52 54 55 56 57 58
package cmmdc ; 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 = / 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 ) 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 ) ; } }
202 ComputeServlet.java
1 2 3 4 5 7 8 10 12 13 14 15 16 17 18 20 21 22 23 24
CAPITOLUL 9. SERVLET
package cmmdc ; 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 = / 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.4.3
Sesiune de lucru
cazul protocolului HTTP, de ecare dat cnd un client deschide sau In a a revine la o pagin Web se deschide o nou conexiune cu serverul Web iar acesta a a nu retine informatiile referitoare la client pe perioada conexiunii respective. Perioada de timp ct un client este conexiune cu o pagin Web se numete a n a s sesiune. Exist posibilitatea pstrrii unor informatii pe durata unei sesiuni (prin a a a mecanismul denumit Session Tracking). Inaintea satisfacerii unei cereri, servlet-ul veric existenta unui obiect a HttpSession. Acest obiect se creaz la prima apelare de ctre un client a a a servlet-ului prin HttpSession sesiune=request.getSession(true); Un obiect HttpSession poate retine atribute, adic perechi de forma (nume, a valoare). Introducerea unui atribut se realizeaz prin a void setAttribute(String nume, Object valoare) iar extragerea valorii unui atribut se obtine prin Object getAttribute(String nume)
203
Metoda String nume[ ] getValueNames() returneaz numele tuturor a atributelor denite. Un atribut se elimin cu metoda void removeAttribute(String nume). a Exemplul 9.4.4 Exemplul urmtor numr de cte ori se apeleaz servleta a a a a ul ntr-o sesiune. Se denete un atribut noAcces, care la prima apelare este s initializat iar apoi este mrit cu cte o unitate la ecare nou apelare a servlet a a a ului.
1 2 3 4 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 33 34 35 36 37
@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 ) ; } }
<html> <head> < t i t l e> S e s i u n e </ t i t l e> </head> <body> <h1> Formular de a c c e s </h1>
204
CAPITOLUL 9. SERVLET
7 8 9 10 11 12
<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> </body> </html>
9.4.4
Cookie
Un Cookie este un ier de dimensiune mic trimis de ctre programul s a a server clientului ca parte a header-ului Http. Acesta contine informatii despre sesiunea curent care salvate pe disc vor a putea accesate sesiuni ulterioare. Cnd un navigator emite o cerere ctre n a a un server, cookie-urile anterioare primite de ctre client de la serverul respectiv a sunt trimise din nou serverului ca parte a cererii formulat de client. a Cookie-urile sunt sterse automat momentul expirrii. n a acest caz, clientul este Unii clienti nu permit memorarea cookie-urilor. In informat c acest fapt ar putea duce la imposibilitatea satisfacerii cereri sale a / accesrii paginii Web. Implicit, durata de viata a unui cookie este sesiunea a curent a navigatorului (pn se a a a nchide navigatorul). Clasa Cookie Contructor Cookie(String nume, String valoare) Metode void setDomain(String model ) Domeniul este o adres URL ce restrictioneaz accesul cookie-urilor la a a acel domeniu. model trebuie s contin cel putin dou caractere .. a a a void setMaxAge(int durat ) Fixeaz durata de existenta a cookie-ului a a - secunde. Valoarea implicit este -1, adic cookie-ul exist pn la n a a a a a nchiderea programului navigator. void setComment(String comentariu) void setSecure(boolean ag) Valoarea implicit este false. a
205
Trimiterea unui cookie clientului: public void HttpServletResponse.addCookie(Cookie cookie) Recunoaterea cookie-urilor de ctre servlet: s a Cookie [ ] cookies=request.getCookies(); if(cookies!=null){ for(int i=0;i<cookies.length;i++){ String name=cookies[i].getName(); String valoare=cookies[i].getValue(); . . . } Exemplul 9.4.5 In exemplul urmtor se numr de cte ori se apeleaz servleta a a a a ul pe durata de viat a cookie-ului. a
1 2 3 4 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 33 34 35
@WebServlet ( u r l P a t t e r n s = / a p e l a r i ) 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 , 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 ( ) ; Cookie myCookie=n u l l ; i n t c o n t o r =1; Cookie [ ] c o o k i e s=r e q . g e t C o o k i e s ( ) ; 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 ) ) { 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 ! ; } } } else { mesaj= S a l u t ! ; } 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 ( ) ) ; 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 ) ;
206
CAPITOLUL 9. SERVLET
36 37 38 40 41 42 43 44
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.4.5
Autenticare
Serverul Web apache-tomcat poate executa autenticrile basic i digest. a s Autenticarea se face pe baza perechii (nume utilizator, parola) (username,password). Aceste informatii sunt retinute serverul Web, ierul conf\tomcat-users.xml n n s 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 cerinta de autenticare solicitat a unui client se precizeaz ierul web.xml a n s
<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> <transport-guarantee>NONE</transport-guarantee> </user-data-constraint> </security-constraint> <login-config> <auth-method>BASIC</auth-method> <!-<realm-name>My realm name</realm-name> --> </login-config>
Optional poate denit un domeniu (realm). cazul apelrii dintr-un program Java a unui servlet, la care accesul preIn a supune autenticare, aceasta se realizeaz prin intermediul claselor pachetului a httpcomponents-client:
207
. . . 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); . . .
9.4.6
Folosind Anexa C considerm a Exemplul 9.4.6 Consultarea unei agende de adrese e-mail. Se utilizeaz o a baz de date AgendaEMail alctuit dintr-un singur tabel adrese (id int, nume a a a varchar(20), email varchar(30)). Utiliznd SGBD derby servlet-ul este a
1 2 3 4 5 6 8 9 10 11 13 14 15 16 17 18 20 21 22 23 24
@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 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 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 { 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 ) {
208
CAPITOLUL 9. SERVLET
25 26 27 28 29 30 31 32 33 35 36 37 38 39 40 41 42 44 45 46 47 48 50 51 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 79 80 81 82 83
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 ( ) ; 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 ) ; } }
209
<html> <body> <h1> Cautare i n baza de d a t e AgendaEMail</h1> <form method= g e t action= h t t p : / / l o c a l h o s t : 8 0 8 0 / agendae / a d r e s e > <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>
Testarea aplicatiei presupune: 1. Realizarea bazei de date: 2. Testarea servlet-ului: (a) Pornirea serverului bazei de date. (b) Se veric prezenta catalogul servlet-ului ...\WEB-INF\lib a a n ierului derbyclient.jar sau mysql-connector-java-*.*.*-bin.jar. s (c) Pornirea serverului tomcat sau re arcarea servlet-ului. nc (d) Apelarea servlet-ului din pagina Web.
9.4.7
Indicm dou modaliti prin care un client obtine o imagine furnizat de a a at a un servlet. Imaginea poate proveni dintr-un ier extern sau poate creat s a de servlet. Imaginea este transmis direct clientului uxul de ieire de tip a n s ServletOutputStream, tipul MIME al rspunsului ind a response.setContentType("image/ext"); ext {gif, jpg, png, . . .}. Textul surs al servlet-ului este: a
210
CAPITOLUL 9. SERVLET
1 2 3 4 6 7 8 9 10 11 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
@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 { r e s . setContentType ( image / g i f ) ; S e r v l e t O u t p u t S t r e a m out = r e s . getOutputStream ( ) ; // R e f e r i n t a l a f i s i e r u l g r a f i c String f = d : \ \ apachetomcat . . \ \ webapps \\ m y s e r v l e t \\WEB INF\\ + c l a s s e s \\ w a l k i n g s a n t a . g i f ; // T r a n f e r a r e a f i s i e r u l u i g r a f i c F i l e I n p u t S t r e a m f i s = new F i l e I n p u t S t r e a m ( f ) ; B u f f e r e d I n p u t S t r e a m b i s = new B u f f e r e d I n p u t S t r e a m ( f i s ) ; byte [ ] b y t e s = new byte [ b i s . a v a i l a b l e ( ) ] ; i n t nread = 0 ; while (1 != ( nread = b i s . r e a d ( b y t e s ) ) ) { out . w r i t e ( b y t e s , 0 , nread ) ; } bis . close ( ); f i s . close (); out . c l o s e ( ) ; } }
Pe calculatorul serverului Web, imaginea se salveaz a ntr-un ier grac, s dup care servlet-ul scrie uxul de ieire un document html cu o a n s legtur (link) ctre ierul cu imaginea creat anterior. Navigatorul a a a s a clientului va descrca i vizualiza imaginea. a s Dac tipul ierului grac este jpg sau png atunci textul surs al servleta s a ului este:
1 2 3 4 5 6 7 8 9 11 12 13 14 15
mport j a v a . i o . ; import j a v a . awt . ; 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 . i m a g e i o . ; import j a v a . awt . image . ; import j a v a x . i m a g e i o . stream . ; import j a v a . u t i l . ; 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 = / 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 { r e s . setContentType ( t e x t / html ) ;
211
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 34 35 36 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
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 f i l e R e f=d : \ \ apachetomcat 6 . 0 . 2 0 \ \ webapps \\ m y s e r v l e t \\ ; 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 ; 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 codarea, face parte din pachetul Acme.JPM.Encoders, a disponibil gratuit la adresa web http://www.acme.com.
9.4.8
Servlet cu RMI
Un servlet poate client al unei aplicatii RMI. Interfata la diatant se a depune catalogul WEB-INF\lib al servlet-ului. Apelarea programului server n RMI se face prin
212
CAPITOLUL 9. SERVLET
InterfataDistanta obj=(InterfataDistanta) Naming.lookup("//"+host+":"+port+"/NumeServiciuRMI"); Exemplul 9.4.7 Client servlet pentru aplicatia RMI de calcul al celui mai mare divizor comun a dou numere naturale. a
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 ) ; } }
213
9.4.9
Servlet cu JMS
De data aceasta cererea clientului se rezolva asincron: In prima faz se apeleaz un servlet care apeleaz un server JMS. Solutia a a a este retinut de furnizorul serviciului de mesagerie pe o destinatie cu un a subiect furnizat de client. Pentru regsirea rezultatului, servlet-ul creaz a a clientului un abonament durabil, functie de numele subiectului. faza a doua, clientul apeleaz un alt servlet, a crei functie este preIn a a luarea rezultatului. Clientul trebuie sa furnizeze subiectul destinatiei rezultatului. Exemplul 9.4.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
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 OracleSun 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 ) ;
214
CAPITOLUL 9. SERVLET
38 39 40 41 42 43 44 45 46 47 48 49 50 51 53 54 55 56 57
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 ( ) ) ; 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 ( ) ; S t r i n g m e q . g e t P a r a m e t e r ( m ) ; =r 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 OracleSun 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=
215
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 59 60 61 62 63
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= + +n+ +t o p i c ; m 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 OracleSun 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 ( ) ;
216
CAPITOLUL 9. SERVLET
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 54 55 56 57 58
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= 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 ) ; } }
catalogul lib al servlet-ului trebuie incluse ierele jar ale serviciului JMS In s folosit.
9.5
FileUpload
Deseori clientul trebuie s furnizeze unui servlet un volum mare de date, a depozitate ntr-un ier. Un produs care ne ajut s s a a ndeplinim acest obiectiv este commons-leupload - dezvoltat de apache. Commons-FileUpload - dezvoltat cadrul apache - este un produs care n simplic transferul unui ier de la un client la programul server (le upload). a s Interfata de programare a produsului se refer la partea de server - cazul de a n fata reprezentat prin servlet. Instalarea produsului const din dezarhivarea ierului descrcat din Ina s a ternet. plus este nevoie de In commons-io Fiierele s
9.5. FILEUPLOAD
217
commons-leupload-*.*.jar commons-io-*.*.jar se depun catalogul lib al servlet-ului. n Transferarea unui ier, din partea clientului nu ridic nici o problem. s a a In ierul html de apelare, se denete un formular s s <form action=. . . enctype="multipart/form-data" method="post"> iar un ier de arcat se xeaz prin intermediul marcajului s nc a <input type="file" name=. . . size=. . .> Programul navigator aeaz o fereastr de cutare, prin care clientul ses a a a lecteaz ierul pe care dorete s-l a s s a ncarce. Dac partea de client este un program, atunci se utilizeaz commonsa a httpclient, 9.4.1 De partea serverului, programarea arcrii revine la nc a 1. Crearea unei fabrici pentru manipularea ierelor pe disc s FileItemFactory factory = new DiskFileItemFactory(); 2. Crearea unei unelte de arcare nc ServletFileUpload upload = new ServletFileUpload(factory);
3. Analiza (parsarea) mesajului furnizat de client List fileItems = upload.parseRequest(req); Fiecare element al listei implementeaz interfata FileItem. a Se pot xa parametrii dimensiunea zonei de pe disc destinat datelor de arcat a nc DiskFileItemFactory factory = new DiskFileItemFactory(); factory.setSizeThreshold(maxMemorySize);
218
CAPITOLUL 9. SERVLET
catalogul temporar de retinere a datelor de arcat nc factory.setRepositoryPath(tempDirectory); sau direct DiskFileItemFactory factory = new DiskFileItemFactory( maxMemorySize, tempDirectory); dimensiunea maxim a unui ier a s upload.setSizeMax(maxRequestSize); 4. Prelucrarea elementelor arcate nc 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. cazul unui element care nu este de tip ier putem obtine numele i In s s valoarea atributului furnizat de client String name = item.getFieldName(); String value = item.getString(); 6. cazul unui ier putem aa numele cmpului input, numele ierului, In s a s dimensiunea ierului s String fieldName = item.getFieldName(); String fileName = item.getName(); long sizeInBytes = item.getSize(); 7. Dac dorim s salvm ierul pe calculatorul server atunci prelucrarea a a a s este
9.5. FILEUPLOAD
219
File uploadedFile = new File(...); item.write(uploadedFile); 8. Dac datele ierului se a s ncarc memoria calculatorului atunci prelua n crarea este InputStream in = item.getInputStream(); //preluarea datelor din fluxul in . . . in.close(); Alternativ, datele se pot retine ca un ir de octeti prin s byte[] data = item.get(); Exemplul 9.5.1 S se obtin n memoria serverului matricea continut ntra a a s un ier text. In ierul text, ecare linie contine o linie a matricei, iar eles mentele sunt separate prin spatii. Metoda getMatrix utilizat reface matricea din datele ierului. a s
1 2 3 4 5 6 7 8 9 11 12 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
package u pl oa d ; 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 . u t i l . ; import o r g . apache . commons . f i l e u p l o a d . d i s k . ; import o r g . apache . commons . f i l e u p l o a d . s e r v l e t . ; import o r g . apache . commons . f i l e u p l o a d . ; 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 = / u pl oa d ) 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 { boolean i s M u l t i p a r t = S e r v l e t F i l e U p l o a d . i s M u l t i p a r t C o n t e n t ( r e q ) ; 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 oad . 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 ) ;
220
CAPITOLUL 9. SERVLET
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 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 80 81 82 83 84 85 86 87 88
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 < i ++){ m; 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 ) ) ; } } } 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 < i ++){ m; 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 ;
221
89 90
} }
Pentru compilare se completeaz variabila de sistem classpath cu referinta a ctre ierul commons-fileupload-*.*.jar. a s 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 / formdata 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>
9.6
Considerm cazul: a Exemplul 9.6.1 Fiierul ales de client dintr-o lista disponibil este descrcat s a a ind transmis navigatorului.
1 2 3 4 6 7 8
222
CAPITOLUL 9. SERVLET
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 32 33 34 35 36
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 ) ; S t r i n g c a l e= webapps / download / r e s o u r c e s / ; try { F i l e I n p u t S t r e a m f i s = new F i l e I n p u t S t r e a m ( c a l e+ f i l e ) ; B u f f e r e d I n p u t S t r e a m b i s = new B u f f e r e d I n p u t S t r e a m ( f i s ) ; byte [ ] b y t e s = new byte [ b i s . a v a i l a b l e ( ) ] ; r e s . setContentType ( A p p l i c a t i o n / Octetstream ) ; r e s . addHeader ( ContentD i s p o s i t i o n , attachment ; f i l e n a m e=+ f i l e ) ; b i s . read ( bytes ) ; out . w r i t e ( b y t e s ) ; bis . close ( ); f i s . close (); out . c l o s e ( ) ; } 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 dv 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 ) ; } }
Rndul 18 are ca efect pstrarea numelui i a extensiei pentru ierul selectat a a s s a se descrca. a
9.7
Filtru
Un ltru se asemean unui servlet, dar activitatea a ntreprins vizeaz uzual a a contextul, adic ansamblul servletilor care fac parte din aplicatia Web. a Un ltru se declar ierul web.xml prin a n s <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> . . .
9.7. FILTRU
223
</web-app> Clasa ltrului implementeaz interfata Filter, adic metodele a a public void init(FilterConfig lterCong) throws ServletException public void destroy() public void doFilter(ServletRequest request, ServletResponse response, FilterChain lterChain) throws IOException, ServletException Exemplul 9.7.1 Contextul myservlet contine doi servleti HelloServlet i Cm s mdcServlet, apelabili respectiv din hello.html, cmmdc.html. S se programeze a un ltru care Redirecteaz solicitarea /myservlet/hello ctre /cmmdc.html. a a Dac se cere ca natura rspunsului s e text/xml atunci invalideaz a a a a cererea. Servletii HelloServlet i CmmdcServlet sunt cei dezvoltati la s nceputul acestui capitol. Filtrul are codul
1 2 3 5 6 8 9 10 12 13 14 16 17 18 19 20 21 22 23 24 25 26 27
import j a v a . i o . IOException ; 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 . ; 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 ( ) ; 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 ) ;
224
CAPITOLUL 9. SERVLET
28 29 30 31 32 33 34 35 36 37 38 39 40
<?xml version= 1 . 0 e n c o d i n g=ISO88591 ?> < !D C Y E webapp O T P 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> < 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
225
25 26 27 28 29 30 31 32 33 34 35 36 37
<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>
9.8
Intr-o clas Java se poate a ncorpora un server tomcat care pot instalate n una sau mai multi serveti. Resursele necesare sunt continute apache-tomcat n *-embedded, iar ierele jar continute trebuie declarate variabila de sistem s n classpath. Sablonul 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 ( ) ; } } }
226
CAPITOLUL 9. SERVLET
Tipul tehnologiei JSP este denumit procesare de abloane (template ens gine). JSP este o tehnologie similar cu PHP, ASP.NET, apache-velocity, etc. a 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 prin a meniul File/Open a unui navigator, cu http://host:port/cale/doc.jsp referinta html <a href="http://host:port/cale/doc.jsp"> valoare a atributului action ntr-un marcaj form <form action="http://host:port/cale/doc.jsp" ... >
Prin cale se elege calea de la catalogul webapps pn la catalogul ce nt a a contine ierul jsp. s Vom depozita ierele JSP s ntr-un catalog jsp din arborele webapps |--> JSPApp | |--> WEB-INF | | |--> classes | | | web.xml 227
doc.jsp
Hello.jsp i plasndu-l catalogul jsp se obtine acelai efect, dar prelun s a n s crarea paginilor / documentelor este diferit. Fiierul html este prelucrat doar a s de programul navigator i poate deschis ca ier, timp ce ierul JSP este s s n s prelucrat de serverul Web cu aarea prin intermediul navigatorului. Prelus crarea efectuat de serverul Web const din transformarea paginii / documena a tului JSP ntr-un servlet, care este compilat i lansat executie. Din aceastr s n a cauz prima invocare a paginii / documentului JSP dureaz mai mult dect a a a apelrile ulterioare. a Fiierul JSP poate construit pe un document xhtml, avnd preambulul s a <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> sau document html 5. acest caz preambulul este In <!doctype html> Apelarea paginii / documentului JSP se face prin http://localhost:8080/JSPApp/jsp/Hello.jsp Exist dou moduri de a include elemente JSP a a ntr-un text html: prin elemente specice JSP. Fiierul are extensia jsp i se numete pagin JSP. s s s a prin elemente xml apartinnd spatiului de nume a http://java.sun.com/JSP/Page Fiierul poate avea extensia jsp sau jspx i se numete document JSP. s s s Comentariile JSP se scriu de forma <%-- Comentariu --%>
229
Considerm urmtorul exemplu introductiv: a a Exemplul 10.1.1 Putem aa valoarea unei variabile Java (de exemplu data s calendaristic) prin a 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 se utilizeaz operatorul de aare = atunci dup expresia de aat a a s a s nu se pune ;. Variabila predenit out este de tip javax.servlet.jsp.JspWriter. a 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 inglobat ntr-un text html se numete scriptlet. Sintaxa utis lizat este a Varianta paginii JSP <% cod Java %>
<jsp:scriptlet> codJava </jsp:scriptlet> Domeniul de valabilitate. Domeniul de valabilitate denete intervalul s de timp, de existenta al unui obiect, ind denit prin valorile: Valoare page request Domeniu de valabilitate pagina curent a pagina curent, n a paginile incluse i n s paginile ctre care se face o redirectare n a session sesiunea curent n a application pe durata rulrii aplicatiei a orice pagin In a Variabila out request response session page pageContext application exception Astfel String request.getParameter(String numeParametru) furnizeaz valoarea parametrului numeParametru dintr-un formular html. a Exemplul 10.1.2 Pagina JSP Hello: Clientul transmite numele paginii care i rspunde cu mesajul de salut Hi + nume + !. a 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= h t t p : / / l o c a l h o s t : 8 0 8 0 / j s p h e l l o / j s p / h e l l o . j s p > <p> Numele : <input type= t e x t name=name s i z e =20> <p> <input type= submit > </form> </ center> </body> </html>
Compilarea i arhivarea servlet-ului o vom realiza prin intermediul lui s acest scop se creaz structura: apache-ant. In a
jsphello | |--> jsp | | | hello.jsp | |--> lib | |--> src | |--> web | | | web.xml | |--> web-files | | | index.html | build.xml
<?xml version= 1 . 0 e n c o d i n g=ISO88591 ?> < !D C Y E webapp O T P 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> <welcomef i l e l i s t> <welcome f i l e >i n d e x . html</ welcome f i l e > <welcome f i l e >i n d e x . j s p</ welcome f i l e > </ welcomef i l e l i s t> </webapp>
232
<project b a s e d i r= . d e f a u l t= g e n e r a t e . war > <property name= d i s t . name v a l u e= j s p h e l l o /> <property name= d i s t . d i r v a l u e= d i s t /> <property name= b u i l d . d i r v a l u e= b u i l d /> <path i d= m y c l a s s p a t h > < f i l e s e t d i r= l i b > <include name= . j a r /> </ f i l e s e t> </path> <target name= i n i t > <delete d i r= ${ d i s t . d i r } /> <mkdir d i r= ${ b u i l d . d i r } /> <mkdir d i r= ${ d i s t . d i r } /> <mkdir d i r= ${ b u i l d . d i r }/ j s p /> <mkdir d i r= ${ b u i l d . d i r }/WEB INF /> <mkdir d i r= ${ b u i l d . d i r }/WEB INF/ c l a s s e s /> <mkdir d i r= ${ b u i l d . d i r }/WEB INF/ l i b /> </ target> <target name= c o m p i l e depends= i n i t > <javac 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= ${ b a s e d i r }/ s r c i n c l u d e a n t r u n t i m e= f a l s e d e s t d i r= ${ b u i l d . d i r }/WEB INF/ c l a s s e s /> </ target> <target name= g e n e r a t e . war depends= c o m p i l e > <copy t o d i r= ${ b u i l d . d i r } > < f i l e s e t d i r= ${ b a s e d i r }/web f i l e s > <include name= . html /> </ f i l e s e t> </copy> <copy t o d i r= ${ b u i l d . d i r }/ j s p > < f i l e s e t d i r= ${ b a s e d i r }/ j s p > <include name= . j s p /> <include name= . j s p x /> </ f i l e s e t> </copy> <copy t o d i r= ${ b u i l d . d i r }/WEB INF f i l e = ${ b a s e d i r }/web/web . xml / > <copy t o d i r= ${ b u i l d . d i r }/WEB INF/ l i b > < f i l e s e t d i r= ${ b a s e d i r }/ l i b > <include name= . j a r /> </ f i l e s e t> </copy> <j a r d e s t f i l e = ${ d i s t . d i r }/${ d i s t . name } . war b a s e d i r= ${ b u i l d . d i r } /> </ target> </ project>
10.1.1
Declaratii JSP
Printr-o declaratie JSP, putem deni cmpuri(variabile) i metode Java ce a s pot apoi folosite, respectiv apelate documentul respectiv. O declaratie n
233
JSP se denete printr-un marcaj s <%! . . . %> sau, format XML n <jsp:declaration> . . . </jsp:declaration> Exemplul 10.1.3 Calculul celui mai mare divizor comun a dou numere nata urale cu metoda de calcul este denit ntr-o declaratie JSP. a Pagina JSP a aplicatiei 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>
<html> <body> <h1> C a l c u l u l Cmmdc </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 / JSPApp/ 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 dou metode jspInit() i jspDestroy() care dac sunt declarate a a s a de programator atunci sunt executate la nceputul i la sfritul ciclului de s as viata a paginii / documentului JSP.
234
Exemplul 10.1.4 Metoda jspInit initializeaz un numr cu 0 iar metoda a a jspDestroy aeaz numrul pe calculatorul serverului. Un client introduce s a a un numr care este adunat la cel retinut de pagina JSP. a Efectul metodei jspDestroy are loc urma opririi aplicatiei JSP. n 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>
10.1.2
Directive JSP
Directivele JSP xeaz informatii pentru tot documentul jsp. O directiv a a jsp se indic prin marcajul a <%@ directiv atribut1 atribut2 . . . %> a sau format XML n <jsp:directive.directiva atribut1 atribut2 . . . /> unde ecare atribut are sintaxa nume=valoare. Directivele pot : page, include, taglib. Directiva page. Mentionm atributele a
235
list de pachete separate prin , a text Informatia se poate regsi apelnd metoda a a getServletInfo() errorPage= adresa url a paginii ce trateaz exceptia a isErrorPage= "true | false" import= info= Directiva include permite includerea unor iere .html sau .jsp docus n ment <%@ include file=ier html, jsp %> s Includerea are loc locul care apare directiva. n n Referinta la ierul html sau jsp se face relativ la catalogul paginii JSP s initiale (adic cea care apare directiva). a n Directiva taglib indic bibliotecile de marcaje utilizate documentul a n jsp, avnd atributele a uri= uri - Universal Resource Identier - a bibliotecii de marcaje prefix= prexul marcajului
10.1.3
Un marcaj JSP denete o actiune care se execut timpul procesrii s a n a paginii jsp. Sintaxa marcajelor JSP seamn cu cea a marcajelor html sau a a xml <prefix : marcaj atribute />
Dintre marcajele JSP predenite adic cu prexul JSP amintim: a <jsp : <jsp : include page=numeFiier jsp sau html /> s forward page=numeFiier jsp sau html /> s
Prelucrarea care urmeaz va cea din ierul mentional. Diferenta dintre a s cele dou elemente const faptul c include prevede revenirea a a n a n pagina JSP initial iar forward nu. a Referinta la ierul html sau jsp se face relativ la catalogul paginii JSP s initiale.
236
cazul marcajelor <jsp: include>, <jsp: forward> se pot transIn mite parametri prin marcajele incluse <jsp:param name="nume" value=valoare "/> sau <jsp:params> <jsp:param name="nume" value=valoare "/> . . . . . . </jsp:params> <jsp : useBean id=numeComponentJava a class=numeClasa scope=domeniu />
unde domeniu precizeaz domeniul de valabilitate al componentei Java, a adic page, request, session, application. a Creaz un obiect numeComponentJava de tip numeClasa avnd a a a domeniul de valabilitate dat de domeniu. a <jsp : setProperty name=numeComponentJava a property=numeProp value=valoare/>
Acest marcaj este echivalent cu codul Java numeComponentJava.setNumeProp(valoare). a <jsp : setProperty name=numeComponentJava property="*" /> a vizeaz toate proprietile componentei Java, xarea valorilor fcndua at a a se cu datele unui formular. Numele parametrilor din formularele de introducere a datelor trebuie s coincid cu identicatorii cmpurilor din a a a componenta Java corespunztoare. a <jsp : getProperty name=numeComponentJava a property=numeProp/>
10.1.4
Clasa componentei Java care se va utiliza ntr-o pagin JSP trebuie inclus a a ntr-un pachet. Relum exemplul 10.1.2 cu o component Java corespunztoare numelui a a a din formularul index.html.
237
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 pagina JSP, bine eles tergndu-l n nt s a din ierul html: s
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
<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> <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>
238
Exemplul 10.1.6 Pagin JSP pentru calculul celui mai mare divizor comun a cu metoda de calcul denit ntr-o component Java. a a Utiliznd documentului html din Exemplul 10.1.3 se denete componenta a s 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 ) { . . . } }
Instantiem o componenta Java i xm proprietile (adic transmitem s i a at a i parametri problemei) dup care apelm metoda ce calculeaz rezultatul dorit a a a pagina JSP: n
1 2
<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= />
239
3 4 5 6 7 8 9 10
<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 ( ) % s i < > %=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 t i f a c u t a l e g e r e a c o r e c t a ) ; 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 apachetomcat 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>
apelate prin
240
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
<html> <body> <form method=p o s 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 / 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>
10.2
JSTL este o familie de biblioteci de marcaje ce ofer o serie de faciliti a at activitii de realizare a paginilor Web. JSTL ajut la separarea activitii de at a at programare de aceea a proiectare (design) a paginii Web. JSTL este alctuit din 5 biblioteci: a a 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 functii ajuttoare a Instalarea bibliotecilor. Bibliotecile sunt livrate mpreun cu apachea tomcat-* catalogul apache-tomcat-*\webapps\examples\WEB-INF\lib prin n ierele jstl.jar i standard.jar. s s Utilizarea bibliotecilor. vederea utilizrii, cele dou iere trebuie In a a s copiate catalogul lib al aplicatiei care utilizeaz bibliotecile. n a pagina / documentul JSP, o bibliotec utilizat trebuie declarat printrIn a a a o directiv taglib. a
241
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 o valoare a ntr-o variabil. a Atribute ale marcajului: Atribut Fel Descriere var obligatoriu Numele variabilei ce va stoca valoarea expresiei. value optional Expresia care va evaluat i atribuit as a variabilei scope optional Domeniul de valabilitate al variabilei. Unul din valorile: page, request, session, application. Referirea la o variabil se face prin sintaxa ${numeVariabil } a a Referirea la valoarea unui cmp dintr-un formular se face prin a ${param.numeCmp} a Alturi de obiectul param, alte obiecte predenite sunt cookie, header, a initParam, pageContext. Se pot deni variabile cu acelai nume dar avnd domenii de valabilitate s a diferit. Referirea se face prin ${pageScope.numeVariabil }, a a ${requestScope.numeVariabil }, ${sessionScope.numeVariabil }, a a ${applicationScope.numeVariabil }. a Plasnd clauza empty a naintea unei variabile, ${empty numeVariabil }, a se obtine false sau true dup cum variabila are sau nu atribuit o a a valoare. c:remove Sterge o variabil. a Atribute ale marcajului: Atribut Fel Descriere var obligatoriu Numele variabilei ce se terge. s scope optional Domeniul de valabilitate al variabilei. Unul din valorile: page, request, session, application.
242 c:out Aeaz o valoare. s a Atribute ale marcajului: Atribut value default
Fel Descriere obligatoriu Valoarea ce se evalueaz i se aeaz. as s a optional Cea ce se aeaz cazul care s a n n expresia nu poate evaluat. a escapeXml optional true / false. Valoarea implicit este true. a Pe false interpreteaz caracterele din value a ca i cod html. s c:if Test, vericarea unei conditii. Atribute ale marcajului: Atribut Fel Descriere test obligatoriu Conditia de test. var optional Numele variabilei ce va stoca valoarea testului. scope optional Domeniul de valabilitate al variabilei denit anterior. a cazul care conditia are valoarea true se prelucreaz corpul marcaIn n a jului, caz contrar, acesta este ignorat. n Exemplul 10.2.1 Preluarea datelor unui formular cu cmpurile de ina trare nume, prenume i email se face prin pagina JSP s
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
< T L H M> <% 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 % @ > <O Y B D> <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 >
243
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 D > O Y </H M > T L
c:choose Marcajul de selectie poate contine oricte marcaje c:when a i cel mult un marcaj c:otherwise. Fiecare marcaj c:when contine s obligatoriu atributul test. Dac a ntr-un marcaj c:when conditia are valoarea true, atunci se prelucreaz corpul acelui marcaj. cazul care a In n toate marcajele c:when au fost evaluate cu false atunci se va prelucra marcajul c:otherwise (marcaj fr atribute). aa c:forEach Ciclu. Atribute ale marcajului: Atribut items var Fel Descriere optional Colectia care se parcurge. optional Numele variabilei care se stocheaz n a valoarea elementului curent. begin optional Valoarea initial a variabilei var. a end optional Valoarea nal a variabilei var. a step optional Valoarea pasului de iterare. Implicit este 1. varStatus optional Informatii despre elementul curent. Variabila varStatus are cmpurile: a index valoarea curent a elementului dup care se realizeaz cia a a clarea; count numrul iteratiei curente; a first are valoarea true dac este primul element al ciclului; a last are valoarea true dac este ultimul element al ciclului; a Exemplul 10.2.2 Lista parametrilor formularului de apelare a exemplului anterior se aeaz prin: s a
<h2> Lista parametrilor din formular </h2> <ul> <c:forEach items="${param}" var="p"> <li> <c:out value="${p}" />
244
<h2> Lista campurilor din antet </h2> <ul> <c:forEach items="${header}" var="h"> <li> <c:out value="${h}" /> </li> </c:forEach> </ul>
Exemplul 10.2.4 Evidentierea 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 aceai functionalitate ca i clasei java.util.String a s s Tokenizer. Atribute ale marcajului: Atribut value Fel Descriere obligatoriu Valoarea ce se evalueaz i se aeaz. as s a expresiei. default optional Cea ce se aeaz cazul care s a n n expresia nu poate evaluat. a escapeXml optional true / false. Valoarea implicit este true. a Pe false interpreteaz caracterele din value a ca i cod html. s c:import Permite includerea altor pagini JSP pagina curent. n a Atribute ale marcajului:
245
Atribut Fel Descriere url obligatoriu Adresa documentului importat. context optional Context-ul paginii / documentului importat. Simbolul /, urmat de numele unei aplicatii de pe acelai server. s var optional Numele variabilei care va stocat n documentul importat. scope optional 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 atribute name i value. Acesti parametri se a s transmit cu metoda get. c:redirect Redirectarea activitatea ctre o alt pagin. a a a Atribute ale marcajului: Atribut Fel Descriere url obligatoriu Adresa paginii ctre care se face redirectarea. a context optional Context-ul paginii ctre care se face redirectarea. a Simbolul /, urmat de numele unei aplicatii de pe acelai server. s Prin redirectare, parametrii nu sunt retransmii automat mai departe. s c:url Retine adrese URL. Atribute ale marcajului: Atribut Fel Descriere value obligatoriu Adresa documentului de retinut. context optional Context-ul documentului. Simbolul /, urmat de numele unei aplicatii de pe acelai server. s var optional Numele variabilei care va stocat n a adresa documentului. scope optional Domeniul de valabilitate al variabilei var. Unul din valorile: page, request, session, application.
246
10.2.2
<%@taglib uri="http://java.sun.com/jsp/jstl/sql" prefix="sql" %> Marcaje din biblioteca de baz: a sql:setDataSource Fixeaz referinta la baza de date. a Atribute ale marcajului: Atribut dataSource driver url username password var scope Fel optional optional optional optional optional optional optional Descriere Referinta 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 referinta 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 optional optional optional obligatoriu optional Descriere Fraza sql Referinta la baza de date Linia de la care se ncepe interogarea Numrul maxim de rezultate acceptate a Variabila cu rezultatele interogrii a 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 optional Referinta la baza de date Exemplul 10.2.5 S se aeze lista din agenda de adrese e-mail creat n a s a exemplul din Cap. Servlet.
247
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
< T L H M> <% 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 % @ > <O Y B D> <p> <s q l : s e t D a t a S o u r c e 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 D > O Y </H M > T L
10.3
Programatorul poate crea marcaje JSP proprii care se grupeaz colectii a n numite biblioteci de marcaje. O bibliotec de marcaje este reprezentat de o a identicator dat sub forma unui URI (Universal Resource Identier ).
10.3.1
Pentru a crea unui asemenea marcaj JSP propriu este necesar denirea a a patru componente: 1. O clas de denitie a comportamentului marcajului JSP (tag handler a class).
248
2. Descriptorul de bibliotec de marcaje JSP, care leag clasa de denitie a a a marcajului cu identicatorul bibliotecii de marcaje. 3. Marcajul taglib a ierului web.xml, care permite serverului Web s s a gseasc descriptorul bibliotecii de marcaje. a a 4. Fiierul JSP ce utilizeaz marcajul JSP (clientul). s a Exemplicm acest tehnologie prin a a Exemplul 10.3.1 S se realizeze un marcaj dateTag, a crui efect s e a a a aarea datei calendaristice. s 1. Clasa de denitie a comportamentului marcajului. Programul const a din: (a) Importul pachetelor import javax.servlet.jsp.*; import javax.servlet.jsp.tagext.*; Aceste pachete se gsesc ierul jsp-api.jar. a n s (b) Un marcaj fr atribute i fr corp trebuie s extind clasa TagSupport aa s aa a a i s suprascrie metoda doStartTag, care denete activitatea ins a s treprins cnd este alnit marcajul a a nt ntr-un document jsp. Metoda trebuie s returneze constanta SKIP BODY. a public class NumeClasa extends TagSupport{ public int doStartTag(){ . . . return SKIP_BODY; } } (c) Scrierea uxul de ieire se face cu un obiect JspWriter, care se n s obtine cu pageContext.getOut(). Metoda print a clasei JspWriter poate genera o exceptie IOException. Textul surs al clasei de denitie a comportamentului marcajului dateTag a este:
249
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 . ; import j a v a x . s e r v l e t . j s p . t a g e x t . ; import j a v a . i o . ; import j a v a . u t i l . ; 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 de marcaje JSP este dependent de versiunea a tomcat folosit. Acest ier trebuie s aib extensia tld (Taglib Lana s a a guage Denition). Localizarea acestui ier este denit elementul s a n taglib din web.xml. cazul unei distributii apache-tomcat-5.*, In acest ier este (mylibtag.tld): s
<?xml version= 1 . 0 e n c o d i n g=ISO88591 ?> < !D C Y E t a g l i b O T P 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 /webj 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> <tagc l a s s> j s p . DateTag </ tagc 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 contine identicatorul bibliotecii de marcaje, cs.unitbv.ro/mytaglib. Pentru ecare marcaj propriu se completeaz un marcaj tag. Pentru un a marcaj propriu fr atribute elementele acestui marcaj sunt aa (a) name Numele simbolic al marcajului.
250
(b) tag-class Referinta la ierul class al clasei de denitie a compor s tamentului marcajului propriu. Referinta se face relativ la catalogul ...\WEB-INF\classes (c) description Descrierea marcajului propriu. (d) body-content cazul nostru are valoarea EMPTY. cazul unui In In marcaj cu corp se d valoarea JSP. a 3. Marcajul taglib din ierul web.xml s
<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 Locatia ierului descriptor de bibliotec de mar s a caje (numele calicat al ierului, adic alctuit din cale plus numele s a a ierului). s Astfel elementele constitutive se vor gsi a n: webapps |--> mytag | |--> WEB-INF | | |--> classes | | | |--> jsp | | | | |--> DateTag.class | | | web.xml | | | mylibtag.tld | |--> jsp | | | dateTag.jsp 4. Marcajele proprii se utilizeaz cu sintaxa a <prex : NumeMarcaj />
251
Referinta la catalogul cu toate componentele necesare marcajului i pre s xul se xeaz directiva taglib. a n Un ier jsp care utilizeaz marcajul realizat este (dateTag.jsp): s a
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>
10.3.2
Realizm un marcaj ziuaTag cu un atribut ziua care va aat momentul a s n prelucrrii marcajului. a 1. Pentru ecare atribut clasa ce denete actiunea marcajului trebuie s s a contin o metod a a public void setNumeAtribut(String value){...} care preia valoarea atributului dat de parametrul value. a Exemplul 10.3.2 Pentru exemplul enuntat aceast clas este a a
1 2 3 4 6 7 9
package j s p ; import j a v a x . s e r v l e t . j s p . ; import j a v a x . s e r v l e t . j s p . t a g e x t . ; import j a v a . i o . ; 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 ) {
252
10 11 13 14 15 16 17 18 19 20 21 22 23
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. descriptorul bibliotecii de marcaje pentru ecare atribut se denete In s un marcaj <attribute>...< /attribute> avnd incluse marcajele a Nume marcaj Semnicatie name numele atributului required true | false dup cum atributul e a obligatoriu sau nu rtexprvalue true | false dup cum atributul a se poate utiliza ntr-o expresie < %= numeAtribut % > Fel obligatoriu obligatoriu optional
1 2 3 4 5 6 7
<html> <body> <form method= g e t action= h t t p : / / l o c a l h o s t : 8 0 8 0 / mytag/ j s p / ziuaTag . j s p > <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
253
8 9 10 11 12 13 14 15 16 17 18
<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 at a > 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.
metoda doStartTag valoarea returnat trebuie s e EVAL BODY INCLUDE, In a a loc de SKIP BODY. n descriptorul bibliotecii de marcaje apare In <body-content> JSP </body-content> loc de EMPTY. n Dac se dorete ca marcajul s execute actiuni dup interpretarea corpului, a s a a atunci acele activiti sunt denite metoda doEndTag. Aceast metod at n a a returneaz valoarea EVAL PAGE sau SKIP PAGE dup cum se dorete sau nu a a s continuarea procesrii paginii jsp. a Exemplul 10.3.3 Fie marcajul modTag care modica un text n caractere mari sau mici dup valoarea atributului trans. Acest marcaj poate include ale a elemente.
254
package j s p ; import j a v a x . s e r v l e t . j s p . ; import j a v a x . s e r v l e t . j s p . t a g e x t . ; import j a v a . i o . ; 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 ; } }
<html>
255
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
<body> <form method= g e t action= h t t p : / / l o c a l h o s t : 8 0 8 0 / mytag/ j s p / modtextTag . j s p > 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 cu modtextTag.jsp a
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>
256
258
mport 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 H e s s i a n S e r v l e t { 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 ) ; 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 , s e r v l e t N a m e , new MyServiceImpl ( ) ) ; c t x t . a d d S e r v l e t M a p p i n g ( /numeApel , s e r v l e t N a m e ) ; 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 ( ) ; } } }
259
String url = "http://host:port/numeApel"; HessianProxyFactory factory = new HessianProxyFactory(); MyService myService = (MyService) factory.create(MyService.class, url); . . . apelarea metodelor interfetei MyService Metoda POST este utilizat pentru transmiterea datelor. a Exemplul 11.1.1 Aplicatie Web bazat pe protocolul Hessian pentru metodele sayHello i pentru calculul celui mai mare divizor comun a dou numere nats a urale. Implementarea interfetei
1 3 4 5 6
package h e s s i a n a p p ; public i n t e r f a c e MyService { String sayHello ( String str ) ; long cmmdc( long m, long n ) ; }
este clasa
1 2 4 5 6 7 8 9 10 11 12 13 14 15 16 18 19 20 21
package h e s s i a n a p p ; import com . caucho . h e s s i a n . s e r v e r . H e s s i a n S e r v l e t ; public c l a s s MyServiceImpl extends H e s s i a n S e r v l e t implements MyService { public long cmmdc( long m, long n ) { long r , c ; do{ c=n ; r= %n ; m m ; =n n=r ; } while ( r ! = 0 ) ; return c ; } public S t r i n g s a y H e l l o ( S t r i n g s t r ) { return Hi + s t r+ ! ; } }
260
8 9 10 11 13 14 15 16 17 18 19 20 21 22 23 24 25
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 t r i n g u r l = http :// l o c a l h o s t :9090/ h e s s i a n s e r v i c e ; H e s s i a n P r o x y F a c t o r y f a c t o r y = new H e s s i a n P r o x y F a c t o r y ( ) ; MyService m y S e r v i c e = ( MyService ) f a c t o r y . c r e a t e ( MyService . c l a s s , u r 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 ) ; System . out . p r i n t l n ( A p e l a r e a m e t o d e i s a y H e l l o \n ) ; System . out . p r i n t l n ( I n t r o d u c e t i numele : ) ; S t r i n g nume=s c a n n e r . n e x t ( ) ; System . out . p r i n t l n ( Raspuns : +m y S e r v i c e . s a y H e l l o ( nume ) ) ; System . out . p r i n t l n ( A p e l a r e a m e t o d e i cmmdc\n ) ; System . out . p r i n t l n ( m ) ; = long m c a n n e r . nextLong ( ) ; =s System . out . p r i n t l n ( n= ) ; long n=s c a n n e r . nextLong ( ) ; System . out . p r i n t l n ( Raspuns : +m y S e r v i c e . cmmdc(m, n ) ) ; } }
11.2
Prezentm o modalitate de desfurare a unei aplicatii Web a as ntr-un produs sau platform de cloud computing. a Dintre produsele de cloud computing disponibile prezent amintim: n Amazons Elastic Compute Cloud -(EC2) produs de referint, dar coma ercial; Google App Engine; Microsoft Azure; cele urmeaz se va utiliza Google App Engine. In a GAE permite: arcarea unei aplicatii Web pe un simulator local al platformei de Cloud nc Computing; arcarea unei aplicatii Web pe platforma Google de Cloud Computing. nc prezent, pe platforma GAE se pot arca aplicatii realizate Java, In nc n Python i Go, alturi de care care pot aprea iere http, css, js. Exist cte s a a s a a o distributie distinct pentru ecare din aceste limbaje de programare. a Prezentm numai arcarea pe simulatorul local al platformei GAE, a nc n versiunea Java construit peste serverul Web jetty.
261
Instalarea produsului const din dezarhivarea ierului appengine-javaa s sdk-*. Utilizarea. vederea arcrii unui servlet pe simulatorul local se creaz In nc a a structura de cataloage i iere s s
www |--> | | | | | | | WEB-INF |--> classes | | *.class |--> lib | | *.jar | web.xml | appengine-web.xml index.html
<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 ierului web.xml corespund servlet-ului, iar prin ierul index.html se s s apeleaz aplicatia Web. Parametrul action al elementului form are forma sima plicat action=/numeApel, unde numeApel coincide cu valoarea atributului a urlPattern. Dac aplicatia se a ncarc pe platforma Google de Cloud Computing atunci a trebuie completat elementul <application>. Lansarea simulatorului i arcarea se poate face prin comenzile s nc
set GAE\_HOME=. . .\appengine-java-sdk-* %GAE\_HOME%\bin\dev_appserver www
lansate ntr-o fereast DOS, catalogul care-l contine pe www. Aplicatia a n se apeleaz prin http://localhost:8080. Dac loc de index.html se utia a n lizeaz alt nume, atunci apelarea aplicatiei este http://localhost:8080/fiier.html. a s O aplicatie JSP se trateaz asemntor. a a a Distributia GAE pentru Java contine ablonul unei aplicatii s mpreun cu a un ier build.xml (appengine-java-sdk-*\demos\new project template) s prin intermediul cruia, cu ajutorul lui ant, se construiete catalogul www a s descris anterior. Exemplul 11.2.1 Servlet-ul CmmdcServlet instalat n platforma Google App Engine de Cloud Computing.
262
Sablonul se copiaz zona de lucru sub numele appcmmdc i se com a n s pleteaz cu ierele servlet-ului (CmmdcServlet.java, cmmdc.html ) rezultnd: a s a
appcmmdc |--> html | | cmmdc.html |--> src | |--> WEB-INF | | | appengine-web.xml | | | web.xml | | CmmdcServlet.java | build.xml
Se execut cu ant obiectivul implicit din build.xml, urmat de lansarea simua latorului din interiorul catalogului appcmmdc. Deoarece numele ierului html s difer de index, aplicatia se apeleaz prin a a http://localhost:8080/cmmdc.html. Alternativ, aplicatia se poate construi cu Eclipse folosind o component a (plug-in) specic. a
Serviciul UserService
Serviciul permite utilizarea autenticrii i autorizrii Google. Aplicatia va a s a contine catalogul www\WEB-INF\lib ierul appengine-api-1.0-sdk-*.jar. n s Sablonul de utilizare const din a . . . import com.google.appengine.api.users.User; import com.google.appengine.api.users.UserService; import com.google.appengine.api.users.UserServiceFactory; public class XXX extends HttpServlet{ public void doGet(HttpServletRequest req,HttpServletResponse res) throws ServletException,IOException{ UserService userService = UserServiceFactory.getUserService(); User user = userService.getCurrentUser(); if (user != null) { String param=req.getParameter("param"); if(tip==null){ res.sendRedirect("/index.html"); } else{ . . . }
263
} else{ res.sendRedirect(userService.createLoginURL(req.getRequestURI())); } } } Exemplul 11.2.2 Aplicatia de calcul a celui mai mare divizor comun are co dul:
1 2 3 4 5 6 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
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 ) throws S e r v l e t E x c e p t i o n , IOException { UserService userService = UserServiceFactory . getUserService ( ) ; User u s e r = u s e r S e r v i c e . g e t C u r r e n t U s e r ( ) ; i f ( u s e r != n u l l ) { 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==n u l l ) { r e s . s e n d R e d i r e c t ( /cmmdc . html ) ; } else { 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=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 =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 ( <p/> ) ; out . p r i n t l n ( <a h r e f =\/cmmdc . html\> R e l u a r e </a> ) ; out . p r i n t l n ( <p/> ) ; S t r i n g s i gn Ou t=u s e r S e r v i c e . createLogoutURL ( r e q . getRequestURI ( ) ) ; out . p r i n t l n ( <a h r e f =\+si g nO u t+\> S i g n out </a> ) ; 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 ( ) ;
264
45 46 47 48 49 50 52 53 54 55 56
} } else { r e s . s e n d R e d i r e c t ( u s e r S e r v i c e . createLoginURL ( r e q . getRequestURI ( ) ) ) ; } } 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 ) ; } }
contentType= t e x t / html ; c h a r s e t=UTF8 l a n g u a g e= j a v a % > imp ort=com . g o o g l e . a p p e n g i n e . a p i . u s e r s . User % > imp ort=com . g o o g l e . a p p e n g i n e . a p i . u s e r s . U s e r S e r v i c e % > imp ort=com . g o o g l e . a p p e n g i n e . a p i . u s e r s . U s e r S e r v i c e F a c t o r y % >
% >
<% UserService userService = UserServiceFactory . getUserService ( ) ; User u s e r = u s e r S e r v i c e . g e t C u r r e n t U s e r ( ) ; i f ( u s e r != n u l l ) { % > <h1> C a l c u l u l CMMDC </h1> <p> I n t r o d u c e ţ i : <form method= p o s t > <table border= 1 > <tr> <td> Primul numă r </td> <td><input type= t e x t name=m s i z e= 20 value= 1 /><td> </ tr> <tr> <td> Al d o i l e a numă r </td> <td><input type= t e x t name=n s i z e= 20 value= 1 /><td> </ tr> <tr> <td> <input type= submit value= C a l c u l e a z a /></td> <% String sm=r e q u e s t . g e t P a r a m e t e r ( m ) , sn=r e q u e s t . g e t P a r a m e t e r ( n ) ; l o n g x =0; i f ( sm==n u l l ) { sm= 1 ; sn= 1 ; } long m =Long . pa rse Lo ng ( sm ) , n=Long . pa rse Lo ng ( sn ) ; x=cmmdc(m, n ) ; % > <td> (< %=sm% ,< > %=sn% >)=< %=x% </td> > </ tr> </ table> </form>
265
45 46 47 48 49 50 51 52 53 54 55 56 57 58
<p> <a href=<%= u s e r S e r v i c e . createLogoutURL ( r e q u e s t . getRequestURI ( ) ) % >> S i g n out</a> <% } else{ % > <a href=<%= u s e r S e r v i c e . createLoginURL ( r e q u e s t . getRequestURI ( ) ) % >> S i g n i n</a> <% } % > </body> </html>
266
Capitolul 12 Portlet
Prezentarea termenului de portlet se face mpreun cu cea de portal. Pora talul ca i portletul sunt aplicatii Web. Practic, un portal accesat aeaz s s a portlete ferestre distincte, portletele ind aplicatii pe care clientul le poate n folosi (Fig. 12.1, Fig. 12.2).
Figure 12.1: Portal - Portlet. O aplicatie portlet ndeplinete standardele JSR (Java Specication Res quest) 168 i JSR 286. s Portalul este o aplicatie Web cu functionalitile: at Container de portleti. Containerul este responsabil de initializarea i dis s trugerea portletilor, de transmiterea cererilor ctre portleti i de colectarea a s rspunsurilor. a Agregarea continuturilor (Content aggregator). Permite aarea i ges s s tionarea mai multor portlete. 267
268
Asigur servicii dintre care amintim: a acces la portal pe baz de autenticare i autorizare. Odat autora s a izat, un client are acces la orice portlet. posibilitatea personalizrii portletelor de ctre clienti. a a Varietatea serviciilor variaz de la un portal la altul. a Portletul este o aplicatie Web care se aseamn cu servletul prin: a a Se instaleaz a ntr-un container. Genereaz continut dinamic. a Ciclul de viat este gestionat de container. a Interactioneaz cu clientul prin modelul request/reply. a Deosebirile unui portlet fata de un servlet sunt: Portletul posed mai multe variante de tratare a cererilor. a
12.1. APACHE-PLUTO
269
Prin conceptul de mod (mode) se specic variante distincte prin care a portletul reactioneaz. Sunt denite modurile VIEW, EDIT, HELP. a Actiunile corespunztoare sunt denite metodele doView, doEdit, a n doHelp. Prin WindowState se xeaz spatiul utilizat de portlet. Valorile varia abilei WindowState sunt NORMAL, MAXIMIZED, MINIMIZED. varianta In MAXIMIZED portletul ocup a ntreaga fereastr, timp ce varianta a n n MINIMIZED portletul apare ntr-o bar de titluri. a
12.1
Apache-pluto
Pentru dezvoltarea unui portlet vom folosi produsul Apache-pluto care genereaz un portal care se pot instala / dezinstala uor portlete. a n s Instalarea produsului. Dac se descarc varianta a a ncorporat serverul a n Web apache-tomcat, denumit pluto-bundle, atunci instalarea la dezarhivarea a ierului descrcat. s a Utilizarea produsului. Dintr-un navigator, portalul se apeleaz prin a http://host:8080/pluto/portal Accesul se face cu User name = password = pluto. Instalarea unui portlet se face 2 pai: n s 1. Desfurarea portlet-ului: Fiierul arhivat al portletului, avnd extenas s a sia war, se depune catalogul PlutoDomain. Apelnd managerul lui n a apache-tomcat din componenta Pluto admin se obtine instalarea portle tului. Alternativ, desfurarea portlet-lui se va obtine cu apache-ant cu utias lizarea unui ier build.xml dedicat. s 2. Publicarea portlet-ului se face prin componenta Pluto admin.
12.2
Compilarea i arhivarea unui portlet vederea desfurrii se va face s n as a rulnd ant cu ierul build.xml: a s
270
1 2 4 5 6 7 8 9 10 12 13 14 15 16 17 18 19 20 21 22 23 25 26 27 28 29 31 32 33 34 35 36 37 39 40 41 42 43 44 45 46 47 48 49 50 51 53 54 55 56 57 58
<?xml version= 1 . 0 e n c o d i n g=UTF8 ?> <p r o j e c t name= p o r t l e t b u i l d default= d e p l o y b a s e d i r= . > <p r o p e r t y e n v i ro n m e nt= env /> < ! S e t CATALINA HOME or u s e D p l u t o . home=/p a t h / t o / tomcatw i t h p l u t o on command l i n e > <p r o p e r t y name= p l u t o . home v a l u e= ${ env .CATALINA HOME} /> <p r o p e r t y f i l e = b u i l d . p r o p e r t i e s /> < ! A l l j a r s used by your p o r t l e t need t o be i n l i b i n a d d i t i o n t o t h e p l u t o antt a s k s j a r > <path i d= p r o j e c t . c l a s s p a t h > < f i l e s e t d i r= l i b > <i n c l u d e name= . j a r /> </ f i l e s e t> < f i l e s e t d i r= ${ p l u t o . home}/ l i b > <i n c l u d e name= . j a r /> </ f i l e s e t> </ path> <t a s k d e f name= a s s e m b l e c l a s s n a m e= o r g . apache . p l u t o . ant . AssembleTask c l a s s p a t h r e f= p r o j e c t . c l a s s p a t h /> <t a r g e t name= a s s e m b l e > <a s s e m b l e webxml= ${webi n f . d i r }/web . xml p o r t l e t x m l= ${webi n f . d i r }/ p o r t l e t . xml d e s t f i l e = ${ b u i l d . d i r }/web . xml /> </ t a r g e t> <t a r g e t name= i n i t d e s c r i p t i o n= C r e a t e s b u i l d d i r s > <echo message=Ant v e r s i o n = ${ ant . v e r s i o n } /> <mkdir d e s c r i p t i o n= C r e a t e s b u i l d d i r e c t o r y i f needed d i r= ${ b u i l d . d i r } /> <mkdir d e s c r i p t i o n= C r e a t e s war d i r e c t o r y i f needed d i r= ${ w e b b u i l d . d i r } /> <mkdir d e s c r i p t i o n= C r e a t e s WEB INF d i r e c t o r y i f needed d i r= ${ w e b b u i l d . d i r }/WEB INF /> <mkdir d e s c r i p t i o n= C r e a t e s WEB INF/ c l a s s e s d i r e c t o r y i f needed d i r= ${ c l a s s b u i l d . d i r } /> <mkdir d e s c r i p t i o n= C r e a t e s WEB INF/ l i b d i r e c t o r y i f needed d i r= ${ w e b b u i l d . d i r }/WEB INF/ l i b /> </ 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 d e s c r i p t i o n= Compiles s o u r c e > <j a v a c c l a s s p a t h r e f= p r o j e c t . c l a s s p a t h f o r k= y e s debug= t r u e d e b u g l e v e l= l i n e s , v a r s , s o u r c e d e s t d i r= ${ c l a s s b u i l d . d i r }
271
59 60 62 63 64 65 66 68 69 70 71 72 73 74 75 76 77 78 80 82 83 84 85 86 88 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 113 115 116 117
s r c d i r= ${ j a v a . s r c . d i r } /> </ t a r g e t> <t a r g e t name= war depends= c o m p i l e > < ! Move web f i l e s e x c l u d i n g web . xml > <copy t o d i r= ${ w e b b u i l d . d i r }/ > < f i l e s e t d i r= ${web . d i r } e x c l u d e s= / web . xml /> </ copy> < ! Move o t h e r n e c c e s s a r y l i b r a r i e s > <copy t o d i r= ${ w e b b u i l d . d i r }/WEB INF/ l i b / > < f i l e s e t d i r= ${ l i b . d i r } > <i n c l u d e name= / . j a r /> <e x c l u d e name= c a s t o r . j a r /> <e x c l u d e name= p l u t o . j a r /> <e x c l u d e name= p o r t l e t . j a r /> <e x c l u d e name= s e r v l e t . j a r /> <e x c l u d e name= j u n i t . j a r /> </ f i l e s e t> </ copy> < a n t c a l l t a r g e t= a s s e m b l e /> < ! C r e a t e war i n d e p l o y m e n t d i r e c t o r y > <war b a s e d i r= ${ w e b b u i l d . d i r } update= f a l s e w a r f i l e= ${ app . name } . war webxml= ${ b u i l d . d i r }/web . xml /> </ t a r g e t> <t a r g e t name= b u i l d depends= c l e a n , war /> <t a r g e t name= d e p l o y depends= b u i l d > <echo message= D e p l o y i n g t o p l u t o . home=${ p l u t o . home} /> < ! Remove former d e p l o y m e n t b e c a u s e sometimes tomcat d o e s n o t f u l l y r e d e p l o y a war > <d e l e t e d i r= ${ p l u t o . home}/ webapps /${ app . name} f a i l o n e r r o r= t r u e /> < ! Deploy war f i l e > <copy f i l e = ${ app . name } . war t o d i r= ${ p l u t o . home}/ PlutoDomain o v e r w r i t e= t r u e /> < ! Deploy c o n t e x t d e p l o y m e n t d e s c r i p t o r f o r Tomcat > <copy f i l e = ${ c o n f . d i r }/${ app . name } . xml t o d i r= ${ p l u t o . home}/ c o n f / C a t a l i n a / l o c a l h o s t o v e r w r i t e= f a l s e /> </ t a r g e t> <t a r g e t name= c l e a n d e s c r i p t i o n= C l e a n s b u i l d > <d e l e t e d i r= ${ b u i l d . d i r } f a i l o n e r r o r= f a l s e /> </ t a r g e t>
272
119
</ p r o j e c t>
#b u i l d . p r o p e r t i e s #Standard p r o p e r t i e s f o r Ant b u i l d o f a P l u t o 1 . 1 p o r t l e t #module name app . name=NumePortlet #D i r e c t o r y t h a t h o l d s s o u r c e code s r c . d i r = s r c / main j a v a . s r c . d i r = ${ s r c . d i r }/ j a v a #D i r e c t o r y t h a t h o l d s documentation doc . d i r = d o c s #D i r e c t o r y t h a t h o l d s f i l e s t o be b u i l t i n t o a j a r , war o r e a r build . dir = build w e b b u i l d . d i r = ${ b u i l d . d i r }/ webapp c l a s s b u i l d . d i r = ${ w e b b u i l d . d i r }/WEB INF/ c l a s s e s #D i r e c t o r y t h a t h o l d s c o n f i g u r a t i o n c o n f . d i r = ${ s r c . d i r }/ r e s o u r c e files
#D i r e c t o r y t h a t h o l d s l i b r a r i e s r e q u i r e d t o b u i l d and run t h e c l a s s e s lib . dir = lib #D i r e c t o r y t h a t h o l d s webapp f i l e s web . d i r = ${ s r c . d i r }/ webapp # WEB INF d i r e c t o r y webi n f . d i r = ${web . d i r }/WEB INF
32 33
#D i r e c t o r y t h a t h o l d s f i l e s t o b u i l d d i s t r i b u t i o n d i s t . d i r = ${ b u i l d . d i r }/ d i s t
Pentru utilizarea acestui build.xml este nevoie de structura urmtoare de a cataloage NumePortlet |--> lib | | castor-1.1.1.jar | | commons-logging-1.0.4.jar | | pluto-ant-tasks-2.0.*.jar | | pluto-descriptor-api-1.1.6.jar | | pluto-descriptor-impl-1.1.6.jar | | pluto-util-2.0.*.jar | | pluto-container-2.0.0.jar | | jaxb-api-2.1.jar | | jaxb-impl-2.1.9.jar
273
|--> | | | | | | | | | | |
src |--> | | | | | | | | | |
java |--> pachetul portletului resource | NumePortlet.xml webapp |--> jsp | | fisierele jsp ale portletului |--> WEB-INF | | portlet.xml | | web.xml
Fiierele castor.1.1.1.jar, pluto-descriptor-api-*.jar, pluto-descriptor-impl-*.jar, s portlet-container-*.jar se copiaz din catalogul PLUTO HOME\shared\lib. a Fiierul web.xml de mai sus este s
2 4 5 6 7 8 10
<?xml version= 1 . 0 e n c o d i n g=UTF8 ?> <webapp xmlns= h t t p : // j a v a . sun . com/xml/ ns / j 2 e e x m l n s : x s i= h t t p : //www. w3 . o r g /2001/XMLSchemai 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 : // j a v a . sun . com/xml/ ns / j 2 e e h t t p : // j a v a . sun . com/xml/ ns / j 2 e e /weba p p 2 4 . xsd version= 2 . 4 > </webapp>
Continutul nal al acestui ier rezult urma obiectivului ant assemple, s a n care se preiau date din ierul de congurare al portletului portlet.xml. n s Editarea ierului portlet.xml este sarcina programatorului. s Fiierul NumePortlet.xml este utilizat la desfurarea aplicatie, ind copiat s as catalogul conf\Catalina\localhost al lui apache-tomcat sau Apache-pluto. n Acest ier are continutul: s
1 2
12.3
Elemente de programare
Orice portlet implementeaz interfata Portlet. Interfata Portlet declar a a 4 metode public interface Portlet{
274
public void init(PortletConfig config) throws PortletException; public void processAction(ActionRequest request, ActionResponse response) throws PortletException, java.io.IOException; public void render(RenderRequest request, RenderResponse response) throws PortletException, java.io.IOException; public void destroy(); } Metoda processAction prelucreaz cererea emis de containerul de portlete. a a La solicitarea containerului, metoda render regenereaz continutul unui porta let. Clasa GenericPortlet este implementarea initial a interfetei Portlet. a Extinznd clasa GenericPortlet, sarcina programatorului este s suprascrie a a metodele doView pentru tratarea modului VIEW; protected void doView(RenderRequest req,RenderResponse res) throws PortletException, IOException doEdit pentru tratarea modului EDIT; protected void doEdit(RenderRequest req,RenderResponse res) throws PortletException, IOException doHelp pentru tratarea modului HELP; protected void doHelp(RenderRequest req,RenderResponse res) throws PortletException, IOException init, destroy pentru initializarea, respectiv oprirea portletului. void init() throws PortletException void init(PortletConfig cong) throws PortletException void destroy() i eventual, s deneasc continutul metodei s a a public void processAction(ActionRequest request,ActionResponse response) throws PortletException, java.io.IOException;
275
Metoda processAction este apelat containerul portlet-ului vederea satisa n facerii unei actiuni (redirectare, schimbarea modului, a spatiului alocat portlet ului, etc.). Exemplul 12.3.1 Portletul HelloWorld.
1 2 3 5 6 7 8 9 10 12 13 14 15 16 17 18 19 20 21 22 23
package h e l l o ; import j a v a . i o . ; import j a v a x . p o r t l e t . ; public c l a s s H e l l o W o r l d P o r t l e t extends G e n e r i c P o r t l e t { protected void doView ( RenderRequest r e q u e s t , RenderResponse r e s p o n s e ) throws P o r t l e t E x c e p t i o n , IOException { r e s p o n s e . setContentType ( t e x t / html ) ; r e s p o n s e . g e t W r i t e r ( ) . p r i n t l n ( H e l l o World ! ) ; } // A l t a v a r i a n t a de programare / p u b l i c v o i d doView ( RenderRequest req , RenderResponse r e s ) t h r o w s P o r t l e t E x c e p t i o n , IOException { r e s . s e t C o n t e n t T y p e ( t e x t / html ) ; P r i n t W r i t e r o u t=r e s . g e t W r i t e r ( ) ; o u t . p r i n t l n (<h2 >); o u t . p r i n t l n ( H e l l o World ! ) ; o u t . p r i n t l n (</h2 >); } / }
<?xml version= 1 . 0 e n c o d i n g=UTF8 ?> <p o r t l e t app xmlns= h t t p : // j a v a . sun . com/xml/ ns / p o r t l e t / p o r t l e t a p p 2 0 . xsd version= 1 . 0 x m l n s : x s i= h t t p : //www. w3 . o r g /2001/XMLSchemai 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 : // j a v a . sun . com/xml/ ns / p o r t l e t / p o r t l e t a p p 1 0 . xsd h t t p : // j a v a . sun . com/xml/ ns / p o r t l e t / p o r t l e t a p p 1 0 . xsd > < p o r t l e t> <d e s c r i p t i o n>H e l l o World a s a p o r t l e t app</ d e s c r i p t i o n> <p o r t l e t name>H e l l o W o r l d P o r t l e t</ p o r t l e t name> <d i s p l a y name>H e l l o World P o r t l e t</ d i s p l a y name> <p o r t l e t c l a s s> h e l l o . H e l l o W o r l d P o r t l e t</ p o r t l e t c l a s s> <s u p p o r t s> <mimet y p e>t e x t / html</mimet y p e> <p o r t l e t mode>VIEW p o r t l e t mode> </ </ s u p p o r t s> <p o r t l e t i n f o> < t i t l e>H e l l o World P o r t l e t</ t i t l e> </ p o r t l e t i n f o> </ p o r t l e t> </ p o r t l e t app>
276
1 2 3 5 6 7 8 9 10 11 13 14 15 16 17 18 20 21 22 23 24 25 26
package h e l l o p l u t o ; import j a v a . i o . ; import j a v a x . p o r t l e t . ; public c l a s s H e l l o P l u t o P o r t l e t extends G e n e r i c P o r t l e t { public void doView ( RenderRequest req , RenderResponse r e s ) throws P o r t l e t E x c e p t i o n , IOException { r e s . setContentType ( t e x t / html ) ; W r i t e r out=r e s . g e t W r i t e r ( ) ; out . w r i t e ( <s t r o n g >H e l l o P l u t o i n view mode</s t r o n g > ) ; } public void doEdit ( RenderRequest req , RenderResponse r e s ) throws P o r t l e t E x c e p t i o n , IOException { r e s . setContentType ( t e x t / html ) ; W r i t e r out=r e s . g e t W r i t e r ( ) ; out . w r i t e ( <i >H e l l o P l u t o i n e d i t mode</i > ) ; } public void doHelp ( RenderRequest req , RenderResponse r e s ) throws P o r t l e t E x c e p t i o n , IOException { r e s . setContentType ( t e x t / html ) ; W r i t e r out=r e s . g e t W r i t e r ( ) ; out . w r i t e ( <u>H e l l o P l u t o i n h e l p mode</u> ) ; } }
<?xml v e r s i o n= 1 . 0 e n c o d i n g=UTF8?> <p o r t l e t app xmlns= h t t p : / / j a v a . sun . com/xml/ ns / p o r t l e t / p o r t l e t a p p 2 0 . xsd v e r s i o n= 1 . 0 xmlns : x s i= h t t p : / /www. w3 . o r g /2001/XMLSchemai 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 : / / j a v a . sun . com/xml/ ns / p o r t l e t / p o r t l e t a p p 1 0 . xsd h t t p : / / j a v a . sun . com/xml/ ns / p o r t l e t / p o r t l e t a p p 1 0 . xsd > <p o r t l e t > <d e s c r i p t i o n >H e l l o P l u t o a s a p o r t l e t app</ d e s c r i p t i o n > <p o r t l e t name>H e l l o P l u t o P o r t l e t </ p o r t l e t name> <d i s p l a y name>H e l l o Pluto </ d i s p l a y name> <p o r t l e t c l a s s >h e l l o p l u t o . H e l l o P l u t o P o r t l e t </ p o r t l e t c l a s s > <s u p p o r t s > <mimetype>t e x t / html</mimetype> <p o r t l e t mode>VIEW</ p o r t l e t mode> <p o r t l e t mode>EDIT</ p o r t l e t mode> <p o r t l e t mode>HELP</ p o r t l e t mode> </s u p p o r t s > <p o r t l e t i n f o > < t i t l e >H e l l o P l u t o P o r t l e t </ t i t l e > </ p o r t l e t i n f o > </ p o r t l e t > </ p o r t l e t app>
277
Exemplul 12.3.3 Portletul Hello. Portletul aeaz o zon text de introducs a a ere a unui nume i un buton. Odat introdus numele, la apsarea butonului se s a a aaez textul Hello nume i un buton de reluare. s a s
1 3 4 5 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 34 35 36 37 38 39 40 41 42 43 44
package h e l l o n a m e ; import j a v a . i o . ; import j a v a x . p o r t l e t . ; import j a v a . u t i l . Enumeration ; public c l a s s H e l l o N a m e P o r t l e t extends G e n e r i c P o r t l e t { public void doView ( RenderRequest req , RenderResponse r e s ) throws P o r t 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 nume=( S t r i n g ) r e q . g e t P a r a m e t e r ( name ) ; P o r t l e t R e q u e s t D i s p a t c h e r prd=n u l l ; i f ( nume==n u l l ) { prd=g e t P o r t l e t C o n t e x t ( ) . g e t R e q u e s t D i s p a t c h e r ( / j s p / i n p u t . j s p ) ; prd . i n c l u d e ( req , r e s ) ; } else { // V a r i a n t a cu a f i s a r e p r i n View / Writer o u t=r e s . g e t W r i t e r ( ) ; o u t . w r i t e ( H e l l o + nume ) ; PortletURL renderURL=r e s . createRenderURL ( ) ; renderURL . s e t P o r t l e t M o d e ( P o r t l e t M o d e .VIEW) ; renderURL . setWindowState ( WindowState .NORMAL) ; o u t . w r i t e (<p><a h r e f =\+renderURL . t o S t r i n g ()+\> R e l u a r e </a >); / // V a r i a n t a cu a f i s a r e p r i n t r un f i s i e r j s p prd=g e t P o r t l e t C o n t e x t ( ) . g e t R e q u e s t D i s p a t c h e r ( / j s p / ou tp ut . j s p ) ; prd . i n c l u d e ( req , r e s ) ; } } public void p r o c e s s A c t i o n ( A c t i o n R e q u e s t req , A c t i o n R e s p o n s e r e s ) throws IOException , P o r t l e t E x c e p t i o n { // P r e i a p a r a m e t r i i s i l e t r i m i t e c e l u i c a r e a emis c e r e r e a Enumeration params=r e q . getParameterNames ( ) ; while ( params . hasMoreElements ( ) ) { S t r i n g parameterName = ( S t r i n g ) params . nextElement ( ) ; S t r i n g p a r a m e t e r V a l u e=r e q . g e t P a r a m e t e r ( parameterName ) ; r e s . s e t R e n d e r P a r a m e t e r ( parameterName , p a r a m e t e r V a l u e ) ; } } }
<% t a g l i b u r i= h t t p : / / j a v a . sun . com/ p o r t l e t p r e f i x= p o r t l e t % @ > < p o r t l e t : d e f i n e O b j e c t s /> <div a l i g n= c e n t e r > I n t r o d u c e ţ i numele : <br/> <form action=< p o r t l e t : actionURL />
278
7 8 9 10 11 12 13
method=POST> <br> <input type= t e x t name=name /> <br> <input type= submit name= submitButton value=Apasama /> </form> </ div>
i respectiv s
1 2 3 4 5 6 7 8 9 10
<% t a g l i b u r i= h t t p : // j a v a . sun . com/ p o r t l e t p r e f i x= p o r t l e t % @ > < p o r t l e t : d e f i n e O b j e c t s /> <p> <% S t r i n g r e s u l t= H e l l o +r e n d e r R e q u e s t . g e t P a r a m e t e r ( name)+ ! ; out . p r i n t l n ( r e s u l t ) ; % > <p><a h r e f=<p o r t l e t : r e n d e r U R L p o r t l e t M o d e= view windowState= normal />> Reluare </ a> .
Exemplul 12.3.4 Cel mai mare divizor comun a dou numere naturale ntra un portlet. Variant care calculul este programat portlet. a n n
1 3 4 5 7 9 10 11 12 13 14 15 16 17 18 19 20 21 22 24 25 26 27 28 29 30 31
package cmmdc ; import j a v a . i o . ; import j a v a x . p o r t l e t . ; import j a v a . u t i l . Enumeration ; public c l a s s CmmdcPortlet extends G e n e r i c P o r t l e t { public void doView ( RenderRequest req , RenderResponse r e s ) throws P o r t l e t E x c e p t i o n , IOException { r e s . setContentType ( t e x t / html ) ; P o r t l e t R e q u e s t D i s p a t c h e r prd=n u l l ; S t r i n g r e z=r e q . g e t P a r a m e t e r ( r e z ) ; i f ( r e z==n u l l ) { prd=g e t P o r t l e t C o n t e x t ( ) . g e t R e q u e s t D i s p a t c h e r ( / j s p / i n p u t . j s p ) ; prd . i n c l u d e ( req , r e s ) ; } else { prd=g e t P o r t l e t C o n t e x t ( ) . g e t R e q u e s t D i s p a t c h e r ( / j s p / ou tp ut . j s p ) ; prd . i n c l u d e ( req , r e s ) ; } } public void p r o c e s s A c t i o n ( A c t i o n R e q u e s t req , A c t i o n R e s p o n s e r e s ) throws IOException , P o r t l e t E x c e p t i o n { // P r e i a p a r a m e t r i i s i l e t r i m i t e c e l u i c a r e a emis c e r e r e a 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 ) ; long n=Long . p ars eL ong ( sn ) ; long c=cmmdc(m, n ) ;
279
32 33 35 37
<% t a g l i b u r i= h t t p : / / j a v a . sun . com/ p o r t l e t p r e f i x= p o r t l e t % @ > < p o r t l e t : d e f i n e O b j e c t s /> <div a l i g n= c e n t e r > <form action=< p o r t l e t : actionURL /> method=POST> <table border= 1 > <tr> <td> Primul numă r </td> <td> <input type= t e x t name=m /> </td> </ tr> <tr> <td> Al d o i l e a numă r </td> <td> <input type= t e x t name=n /> </td> </ tr> <tr> <td> <input type= submit name= submitButton value= C a l c u l e a z a /> </td> </ tr> </ table> </form> </ div>
i respectiv s
1 2 4 5 6 7 8 10 11 12 13
<% t a g l i b u r i= h t t p : / / j a v a . sun . com/ p o r t l e t p r e f i x= p o r t l e t % @ > < p o r t l e t : d e f i n e O b j e c t s /> <P > <% String r e s u l t=Cmmdc +r e n d e r R e q u e s t . g e t P a r a m e t e r ( r e z )+ ! ; out . p r i n t l n ( r e s u l t ) ; % > <P > <a href=< p o r t l e t : renderURL p o r t l e t M o d e= view windowState= normal />> Reluare </a>
Variant care calculul este programat a n ntr-o component Java a (bean) i care este apelat pagina jsp de aare a rezultatului. s n s
1 3 4 5 7
280
9 10 11 12 13 14 15 16 17 18 19 20 21 22 24 25 26 27 28 29 30 31 32 33 34 35 36
public void doView ( RenderRequest req , RenderResponse r e s ) throws P o r t l e t E x c e p t i o n , IOException { r e s . setContentType ( t e x t / html ) ; P o r t l e t R e q u e s t D i s p a t c h e r prd=n u l l ; S t r i n g sb=r e q . g e t P a r a m e t e r ( submitButton ) ; i f ( sb==n u l l ) { prd=g e t P o r t l e t C o n t e x t ( ) . g e t R e q u e s t D i s p a t c h e r ( / j s p /inputCmmdc . j s p ) ; prd . i n c l u d e ( req , r e s ) ; } else { prd=g e t P o r t l e t C o n t e x t ( ) . g e t R e q u e s t D i s p a t c h e r ( / j s p /outputCmmdc . j s p ) ; prd . i n c l u d e ( req , r e s ) ; } } public void p r o c e s s A c t i o n ( A c t i o n R e q u e s t req , A c t i o n R e s p o n s e r e s ) throws IOException , P o r t l e t E x c e p t i o n { // P r e i a p a r a m e t r i i s i l e t r i m i t e c e l u i c a r e a emis c e r e r e a Enumeration params=r e q . getParameterNames ( ) ; while ( params . hasMoreElements ( ) ) { S t r i n g parameterName = ( S t r i n g ) params . nextElement ( ) ; S t r i n g p a r a m e t e r V a l u e=r e q . g e t P a r a m e t e r ( parameterName ) ; System . out . p r i n t l n ( >> parameterName = + parameterName + <=> p a r a m e t e r V a l u e = + p a r a m e t e r V a l u e ) ; r e s . s e t R e n d e r P a r a m e t e r ( parameterName , p a r a m e t e r V a l u e ) ; } } }
public c l a s s CmmdcBean{ private S t r i n g m ; = private S t r i n g n= ; 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 cmmdc ( ) { long m0=Long . pa rs eL ong (m) ; long n0=Long . pa rse Lo ng ( n ) ; long c , r ; do{ c=n0 ; r=m0%n0 ; m0=n0 ; n0=r ; }
281
28 29 30 31
Pagina outputCmmdc.jsp
1 2 3 5 7 8 9 10 11 12 13 14 15
<% t a g l i b u r i= h t t p : / / j a v a . sun . com/ p o r t l e t p r e f i x= p o r t l e t % @ > <j s p : useBean id=myCmmdcBean c l a s s=cmmdc . CmmdcBean scope= s e s s i o n /> <j s p : s e t P r o p e r t y name=myCmmdcBean p r o p e r t y= /> < p o r t l e t : d e f i n e O b j e c t s /> <P > <% String r e s u l t=Cmmdc +myCmmdcBean . cmmdc ( ) ; out . p r i n t l n ( r e s u l t ) ; % > <P > <a href=< p o r t l e t : renderURL p o r t l e t M o d e= view windowState= normal />> Reluare </a>
Variant care care calculul este programat a n ntr-un servlet. Servletul utilizat este cel prezentat capitolul Servlet, (9.2.2), dar inclus pachetul n n portlet-ului. Fiierul inputCmmdc.jsp are plus linia s n
<input type="hidden" name="tip" value="text/html"/>
apare
prd=getPortletContext().getRequestDispatcher("/cmmdc");
adic locul invocrii paginii JSP, dispecerul apeleaz servletul. servlet a n a a In este esential furnizarea rezultatului format html. Pagina html generat se a n a ncarc fereastra portlet-ului. a n Fiierul web.xml, s naintea completrii prin ant, este a
1 3 4 5 6 7 9 10 11 12 14 15 16 17 18
<?xml version= 1 . 0 e n c o d i n g=UTF8 ?> <webapp xmlns= h t t p : // j a v a . sun . com/xml/ ns / j 2 e e x m l n s : x s i= h t t p : //www. w3 . o r g /2001/XMLSchemai 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 : // j a v a . sun . com/xml/ ns / j 2 e e h t t p : // j a v a . sun . com/xml/ ns / j 2 e e /weba p p 2 4 . xsd version= 2 . 4 > < s e r v l e t> <s e r v l e t name>CmmdcServlet</ s e r v l e t name> <s e r v l e t c l a s s>cmmdc . CmmdcServlet</ s e r v l e t c l a s s> </ s e r v l e t> <s e r v l e t mapping> <s e r v l e t name>CmmdcServlet</ s e r v l e t name> <u r l p a t t e r n>/cmmdc</ u r l p a t t e r n> </ s e r v l e t mapping> </webapp>
282
Interfata PortletPreferences
Atribute, adic perechi de tip String (nume,valoare) denite ierul a n s portlet.xml prin <portlet-preferences> <preference> <name>nume_atribut</name> <value>valoare_atribut</value> <read-only>true|false</read-only> </preference> . . . </portlet-preferences> se transmit metodelor doView, doEdit i doHelp. Suportul este oferit prin s interfata PortletPreferences. Metode String getValue(String key, String def ) Returneaz valoarea primului atribut avnd numele key. lipsa atribua a In tului sau a valorii returneaz valoarea def. a String[] getValues(String key, String[] def ) Returneaz toate valorile atributului key. a Enumeration<String> getNames() Suport pentru acces la numele atributelor care au valoare. Map<String,String[]> getMap() Suport pentru acces la atribute. Un obiect care implementeaz interfata PortletPreferences se obtine a prin metoda getPreferences() a clasei RenderRequest. Exemplul 12.3.5 Portlet n care se preiau i se aeaz valori ale atributelor. s s a Codul portletului este
283
1 3 4 6 8 9 10 11 12 13 14 15 16 17
package p r e f ; import j a v a . i o . ; import j a v a x . p o r t l e t . ; public c l a s s P r e f P o r t l e t extends G e n e r i c P o r t l e t { public void doView ( RenderRequest req , RenderResponse r e s ) throws P o r t l e t E x c e p t i o n , IOException { P o r t l e t P r e f e r e n c e s p r e f s = req . g e tP r e f e re n c e s ( ) ; S t r i n g a t t r 1 = p r e f s . g e t V a l u e ( ATTR1 , a t t r 1 ) ; S t r i n g a t t r 2 = p r e f s . g e t V a l u e ( ATTR2 , a t t r 2 ) ; r e s . setContentType ( t e x t / html ) ; W r i t e r out=r e s . g e t W r i t e r ( ) ; out . w r i t e ( <s t r o n g >+a t t r 1+ <> +a t t r 2+</s t r o n g > ) ; } }
Al doilea atribut nu are valoare.Portletul aeaz textul Programare distribuita s a <> attr2.
12.4
Produse Portal
Termenul portal va desemna aplicatia informatic prin care o institutie comunic cu lumea exterioar a a a produsul informatic care realizeaz aplicatia amintit la pct. anterior a a cele ce urmeaz ne vom referi doar la produse portal care sunt containere In a de portlete. Dezvoltarea unui portal al unei organizatii se face pe produse specializate acestui scop. Dintre asemenea produsele gratuite amintim:
care vor prezentate continuare. apache-pluto este ideal pentru testarea n portlet-elor.
12.4.1
uPortal
uPortal este un portal cadru, dezvoltat de JA-SIG (Java Architecture Special Interest Group) i a fost utilizat de mai multe universiti ca suport s at n constructia portalului specic. Instalarea produsului. Distributia produsului se face dou variante n a uPortal-*.*.* - uPortal-only; uPortal-*.*.*-quick-start care nglobeaz toate resursele necesare functionrii a a (apache-ant, apache-tomcat, apache-maven, HypersonicSQLDB). cele ce urmeaz utilizm varianta uPortal-quick-start. Instalarea produsului In a a revine la dezarhivarea ierului descrcat. s a urma dezarhivrii, catalogul uPortal HOME Lansarea portalului. In a n se gsete un ier build.xml, ale crei obiective asigur lansarea portalului1 . a s s a a Se completeaz ierul ant.bat cu referinta set JAVA HOME=... a s Lansarea portalului const executarea comenzii a n ant start De fapt se pornete SGBD HypersonicSQLDB i serverul Web apache-tomcat. s s Oprirea portalului se face prin executarea comenzii ant stop Dintr-un navigator, portalul se acceseaz prin a http://host:8080/uPortal
La prima executare a unei operatii asupra portalului, calculatorul trebuie s e conectat a la internet, deoarece mai multe resurse sunt descrcate prin apache-maven. Aceste resurse a se depun c:\Documents and Settings\adminName\.m2\repository. n
1
285
Accesarea portalului se poate face doar de detintorii unui cont (User a Name, Password). Administratorul (UserName=Password=admin) poate crea conturi noi. Instalarea unui portlet const desfurarea i publicarea lui. a n as s Compilarea i arhivarea portletului se poate face cu apache-ant acest s In scop se creaz structura a
|--> | |--> | | | | | | | | lib | portlet-api-1.0.jar pachetul portlet-ului |--> jsp | | *.jsp |--> WEB-INF | |--> classes | | | *.java | | web.xml | | portlet.xml build.xml
cu ierele *.java, *.jsp i portlet.xml corespunztoare portletului iar web.xml s s a este generic
1 2 3 4 5 6
<?xml version= 1 . 0 e n c o d i n g=ISO88591 ?> < !D C Y E webapp PUBLIC O T P //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> </webapp>
<p r o j e c t name= p o r t l e t b u i l d default= war b a s e d i r= . > <p r o p e r t y name= package v a l u e= h e l l o /> <p r o p e r t y name= p o r t l e t . name v a l u e= H e l l o N a m e P o r t l e t /> <p r o p e r t y name= b u i l d . d i r v a l u e= b u i l d /> <path i d= p r o j e c t . c l a s s p a t h > < f i l e s e t d i r= 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= ${ package }/${ b u i l d . d i r } /> <mkdir d i r= ${ package }/${ b u i l d . d i r } /> <mkdir d i r= ${ package }/${ b u i l d . d i r }/ j s p /> <mkdir d i r= ${ package }/${ b u i l d . d i r }/WEB INF /> <mkdir d i r= ${ package }/${ b u i l d . d i r }/WEB INF/ c l a s s e s /> </ 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 d e s c r i p t i o n= Compiles s o u r c e > <j a v a c c l a s s p a t h r e f= p r o j e c t . c l a s s p a t h d e s t d i r= ${ package }/${ b u i l d . d i r }/WEB INF/ c l a s s e s s r c d i r= ${ package }/WEB INF/ c l a s s e s /> </ t a r g e t>
286
27 28 29 30 31 32 33 34 36 37 38 39 41 43 44 45 47
<t a r g e t name= war depends= c o m p i l e > <copy t o d i r= ${ package }/${ b u i l d . d i r }/WEB INF/ f i l e = ${ package }/WEB INF/ p o r t l e t . xml /> <copy t o d i r= ${ package }/${ b u i l d . d i r }/ j s p > < f i l e s e t d i r= ${ package }/ j s p > <i n c l u d e name= . j s p /> </ f i l e s e t> </ copy> <war b a s e d i r= ${ package }/${ b u i l d . d i r } update= f a l s e w a r f i l e= ${ p o r t l e t . name } . war webxml= ${ package }/WEB INF/web . xml /> </ t a r g e t> <t a r g e t name= b u i l d depends= c l e a n , war /> <t a r g e t name= c l e a n d e s c r i p t i o n= C l e a n s b u i l d > <d e l e t e d i r= ${ b u i l d . d i r } f a i l o n e r r o r= f a l s e /> </ t a r g e t> </ p r o j e c t>
Desfurarea portlet-ului se face cu apache-ant utiliznd ierul build.xml as a s din uPortal HOME\uPortal-*.*.* prin ant deployPortletApp -DportletApp=arhiva portlet-ului.war urma acestei operatii, portlet-ul se dezarhiveaz uPortal HOME\apacheIn a n tomcat-*.*.*\webapps iar ierul web.xml este actualizat. s Publicarea portlet-ului se face cu rolul de administrator. Dup conectare a la uPortal 1. Clic Portlet Manager. 2. Click Register New Portlet. 3. Se selecteaz Portlet, clic Next. a 4. Se selecteaz portlet-ul care se dorete publicat. a s 5. Se completeaz Channel Functional Name. a 6. Din meniul Select Categories se alege cel putin o categorie. 7. Din meniul Select People and Groups se alege cel putin un membru. Astfel se xeaz cine are dreptul s utilizeze portletul. Portal System a a corespunde administratorului. 8. Din meniul Lifecycle Management se alege Published.
287
9. Clic Save. Un membru/grup selectat aeaz portlet-ul prin clic pe butonul Add Content s a urmat de selectarea categoriei i a portlet-ului. s Administratorul aeaz portletul prin s a 1. Clic pe butonul Customize 2. Clic pe un buton Add Channel corespunztor locului unde vrem s e a a pozitionat portlet-ul. 3. Steps for adding a new channel se selecteaz categoria, portletul i In a s este urmat de clic pe butonul Add Channel. Un client elimin un portlet prin clic pe butonul Remove din fereastra a portlet-ului. Administratorul portalului ntrerupe publicarea unui portlet prin clic pe butonul Portlet Manager, urmat de selectarea portletului i clic pe Removes Portlet.
12.4.2
Jetspeed-2
Jetspeed-2 este un portal cadru dezvoltat de apache. Instalarea se execut rulnd distributia jetspeed-installer-2.*.jar, cu Ina a stalation Type: Demo i Pipeline Type: JetUI. s Versiunea instalat a platformei jetspeed este construit peste o distributie a a apache-tomcat-*. Astfel, lansarea se face apelnd bin\startup.bat. a Portalul se acceseaz, dintr-un navigator, prin a http://localhost:8080/jetspeed Desfurarea unui portlet const copierea arhivei war corespunztoare, as a n a realizat 12.4.1, catalogul n n Jetspeed HOME \webapps\jetspeed\WEB-INF\deploy Pe rol de admin (acces cu valorile initiale username=password=admin), publicarea portlet-ului presupune 1. Clic pe icon-ul butonului Portlets. 2. Se caut portlet-ul dup numele declarat elementul <display-name> a a n din portlet.xml; 3. Clic pe butonul Add. Pentru a terge un portlet se apas butonul de s a nchidere al portlet-ului.
288
O aplicatie Java destinat a utilizat pe un calculator poate valoricat a a a i s ntr-o retea, pe baza protocolului Java Network Launching Protocol - JNLP. Tehnologia poart numele de Java Web Start. a Aplicatia Java trebuie s satisfac o serie de restrictii: a a Aplicatia trebuie arhivat cu jar; a Eventualele date necesare aplicatiei se introduc prin intermediul unei interfete grace (swing, SWT, apache-pivot); Acces limitat la proprietile i resursele sistemului client. at s Aplicatiei i se ataeaz un ier xml, dar cu extensia jnlp, care se va apela s a s dintr-un navigator. Pentru acest ier folosim terminologia de ier jnlp. s s Fiierul jnlp xeaz: s a referinta URL a aplicatie (prin atributul codebase); arhivele jar utilizate (prin atributul href); clasa cu metoda main (prin atributul main-class). Ansamblul de resurse formeaz o aplicatie Web care poate desfurat a as a ntr-un server Web (Microsoft Internet Information Service (IIS), Apache) sau poate incorporat ntr-un servlet, caz care desfurarea va n as ntr-un server Web container de servlet. Artm activitile care trebuie aa at ntreprinse cazul unui exemplu simplu n dat de clasa VisualCmmdc.java. 289
290
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 ;
291
<?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 /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> <a p p l i c a t i o n d e s c mainc l a s s=VisualCmmdc /> </ j n l p>
host se nlocuiete cu numele calculatorului care gzduiete serverul Web. s a s 3. Se creaz ier de apelare a aplicatiei (cmmdc.html ) a s
1 2 3 4 5 6 7 8 9
<html> <body bgcolor=# AAEEAA> <center> <h3>V i s u a l Cmmdc A p p l i c a t i o n </h3> <a href= h t t p : / / h o s t /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>
4. Ansamblul
cmmdc | cmmdc.jar | cmmdc.html | launch.jnlp
se copiaz serverul Web1 ( cazul IIS acest loc este catalogul a n n InetPub\wwwroot, iar cazul serverului Web Apache catalogul este n Apache Software Foundation\Apache*\htdocs).
1
292
Fiierul jnlp-servlet.jar se preia din distributia JDK, din catalogul s sample/jnlp/servlet. Fiierul web.xml este s
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
? xml v e r s i o n= 1 . 0 e n c o d i n g= i s o 88591?> < !D C Y E webapp O T P 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 ) > <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. Continutul catalogului de lucru se arhiveaz a ntr-un ier war. s jar cfv cmmdc.war app/* WEB-INF/* cmmdc.html
293
6. Utiliznd apache-tomcat sau jetty, de exemplu, ierul war se copiaz a s a n catalogul webapps al serverului web. Dintr-un navigator, apelarea aplicatiei se obtine prin http://host:8080/cmmdc/cmmdc.html. Dac aplicatia Java utilizeaz imagini grace acestea trebuie arhivate a a mpreun a cu aplicatia, de exemplu ntr-un catalog images. arcarea i aarea unei imagini programndu-se prin Inc s s a ClassLoader cl=this.getClass().getClassLoader(); URL file=cl.getResource("images/pic1.jpg"); Image img=Toolkit.getDefaultToolkit().getImage(file); graphics.drawImage(img,x,y,this); Dac aplicatia Java utilizeaz resurse externe date prin iere jar atunci: a a s 1. Toate ierele jar se certic. s a Certicarea resurselor se realizeaz rulnd succesiv a a (a) keytool -genkey -keystore myKeystore -alias myself (b) keytool -selfcert -alias myself -keystore myKeystore (c) jarsigner -keystore myKeystore resource.jar myself keytool.exe i jarsigner.exe se gsesc distributia jdk. s a n Primele dou actiuni au ca rezultat obtinerea certicatului myKeystore a iar ultima actiune reprezint a nglobarea certicrii arhiva resource.jar. a n Toate ierele jar trebuie s poarte aceai certicare. s a s 2. Fiierele jar certicate se depun catalogul app\lib. s n 3. ierul jnlp, elementul resources, pentru ecare ier jar utilizat In s n s se introduce declaratia <jar href=lib/resource.jar/> 4. plus, ierul jnlp ataat aplicatiei contine elementele In s s <security> <all-permissions /> </security>
294
Dac arhiva jar a aplicatiei Java este executabil atunci, ierul jnlp, a a n s elementul application-desc poate lipsi. Intr-o arhiv jar executabil, ierul MANIFEST.MF indic clasa cu metoda a a s a main i eventualele resurse externe utilizate (iere jar) prin proprietile s s at
Main-class: numeClasa Class-path: lib/resursa1.jar lib/resursa2.jar . . .
Pentru a obtine ierul MANIFEST.MF cu aceste proprieti se editeaz un s at a ier text cu continutul de mai sus, denumit de exemplu myManifest.mf, i s s se arhiveaz prin a
jar cfvm numeArhiva.jar myManifest.mf *.class lib
package agendae ; import j a v a . s q l . ; public c l a s s GuiCmmdc extends j a v a x . swing . JFrame { Statement s t a t e m e n t=n u l l ; public GuiCmmdc ( ) { initComponents ( ) ; S t r i n g d r i v e r= o r g . apache . derby . j d b c . EmbeddedDriver ; S t r i n g dbName= a g e n d a e m a i l ; S t r i n g connURL ; C o n n e c t i o n conn=n u l l ; try { C l a s s . forName ( d r i v e r ) ; connURL= j d b c : derby : +dbName+ ; c r e a t e=t r u e ; conn=DriverManager . g e t C o n n e c t i o n ( connURL ) ; s t a t e m e n t=conn . c r e a t e S t a t e m e n t ( ) ; S t r i n g createDB= c r e a t e t a b l e 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 a s i d e n t i t y + ( s t a r t with 1 , i n c r e m e n t by 1 ) primary key , + nume c h a r ( 2 0 ) not n u l l , + e m a i l c h a r ( 3 0 ) not n u l l ) ; s t a t e m e n t . e x e c u t e ( createDB ) ;
295
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 55 56 57 58 59 60 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
S t r i n g i n s e r t D B= i n s e r t i n t o a d r e s e ( nume , e m a i l ) v a l u e s + ( aaa , aaa@yahoo . com ) , + ( bbb , bbb@gmail . com ) , + ( c c c , c cc@u nit bv . r o ) , + ( aaa , xyz@unitbv . r o ) ; statement . executeUpdate ( insertDB ) ; } catch ( ClassNotFoundException e ) { System . out . p r i n t l n ( ClassNotFoundException : +e . g e t M e s s a g e ( ) ) ; System . e x i t ( 1 ) ; } catch ( SQLException e ) { connURL= j d b c : derby : +dbName ; try { conn=DriverManager . g e t C o n n e c t i o n ( connURL ) ; s t a t e m e n t=conn . c r e a t e S t a t e m e n t ( ) ; } catch ( E x c e p t i o n ex ) { System . out . p r i n t l n ( E x c e p t i o n : +ex . g e t M e s s a g e ( ) ) ; System . e x i t ( 1 ) ; } } 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 . e x i t ( 1 ) ; } } @SuppressWarnings ( unchecked ) 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 p e n t r u i n t e r f a t a g r a f i c a . . . } private void jBu ttonE xecMo useCl icke d ( j a v a . awt . e v e n t . MouseEvent e v t ) { i n t p r e l=jComboBoxTip . g e t S e l e c t e d I n d e x ( ) ; S t r i n g e n t i t= \ +j T e x t F i e l d E n t i t . g e t T e x t ( ) . t r i m ()+ \ ; String sql ; R e s u l t S e t r s=n u l l ; jTextAreaDB . s e t T e x t ( ) ; 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 ( 1 0 0 ) ; try { switch ( p r e l ) { case 0 : s q l= s e l e c t from a d r e s e where nume=+e n t i t ; r s=s t a t e m e n t . e x e c u t e Q u e r y ( s q l ) ; i f ( r s != n u l l ) { while ( r s . n e x t ( ) ) { sb . append ( 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 )+ \n ) ; } } else { sb . append ( Fara a d r e s a de em a i l ! ) ; } break ; case 1 : s q l= s e l e c t from a d r e s e where e m a i l=+e n t i t ;
296
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 103 104 105 106 107 108 110 111 112 113 114 115 116 117 118 119 120 121 122
r s=s t a t e m e n t . e x e c u t e Q u e r y ( s q l ) ; i f ( r s != n u l l ) { while ( r s . n e x t ( ) ) { sb . append ( 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 )+ \n ) ; } } } } catch ( SQLException e ) { System . out . p r i n t l n ( Query DB 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 ( 1 ) ; } jTextAreaDB . i n s e r t ( sb . t o S t r i n g ( ) , 0 ) ; jTextAreaDB . s e t V i s i b l e ( true ) ; } private void formWindowClosed ( j a v a . awt . e v e n t . WindowEvent e v t ) { try { DriverManager . g e t C o n n e c t i o n ( j d b c : derby : ; shutdown=t r u e ) ; } catch ( SQLException e ) { } } public s t a t i c void main ( S t r i n g a r g s [ ] ) { j a v a . awt . EventQueue . i n v o k e L a t e r (new Runnable ( ) { public void run ( ) { new GuiCmmdc ( ) . s e t V i s i b l e ( true ) ; } }); } private j a v a x . swing . JButton jButtonExec ; private j a v a x . swing . JComboBox jComboBoxTip ; private j a v a x . swing . J S c r o l l P a n e j S c r o l l P a n e 1 ; private j a v a x . swing . JTextArea jTextAreaDB ; private j a v a x . swing . J T e x t F i e l d j T e x t F i e l d E n t i t ; }
<?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 : // l o c a l h o s t : 8 0 8 0 / agendae / app > <i n f o r m a t i o n> < t i t l e>AgendaEMail</ t i t l e> <vendor> xyz </ vendor> <d e s c r i p t i o n>Derby DB d e s c r i p t i o n> </ </ i n f o r m a t i o n> <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> <r e s o u r c e s> <j 2 s e version= 1.2+ /> <j a r h r e f= agendae . j a r /> <j a r h r e f= l i b / derby . j a r /> </ r e s o u r c e s> <a p p l i c a t i o n d e s c mainc l a s s= agendae . GuiCmmdc /> </ j n l p>
298
Terminologia server MBean se justic prin faptul c poate invocat de un a a aceast ipostaz, serverul MBean are rolul unui container program client. In a a de MBean-uri i de gestionare i executie a apelurilor clientilor. s s Structura unei aplicatii JMX contine dou nivele: a componentele MBean; agentul (serverul MBean).
14.1
14.1.1
Standard MBean
Crearea unui Standard MBean
O component MBean este alctuit dintr-o interfat i o clas care implea a a a s a menteaz interfata satisfcnd urmtoarele restrictii: a a a a 1. interfata are numele clasei care o implementeaz avnd plus suxul a a n MBean; 2. Interfata i clasa care o implementeaz apartin aceluiai pachet; s a s 3. constructorii i metodele expuse trebuie s e publice. s a continuare cmpurile i metodele destinate expunerii se vor denumi In a s atribute, respectiv operatii. Fiecrui atribut xxx i se ataeaz cel putin una a s a din metodele public void setXxx(tip xxx){ this.xxx=xxx; } i / sau s public tip getXxx(){ return xxx; } Un atribut se precizeaz doar prin aceste metode, fr denirea / declararea a aa cmpului corespunztor. Cmpul se denete clasa ce implementeaz interfata a a a s n a MBean-ului. Astfel, un MBean este caracterizat de
299
atribute care pot consultate (citite), modicate (scrise) sau cu ambele optiuni. operatii noticri a cu evidenta modicrilor suferite de atribute. a Exemplul 14.1.1 Construim un MBean cu atributele label ce poate numai citit; cursEuro care poate consultat i modicat; s operatiile public String sayHello() aeaz un mesaj; s a public long cmmdc(long m, long n); de calcul a celui mai mare divizor comun a dou numere naturale. a Interfata 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 // reado n l y public S t r i n g g e t L a b e l ( ) ; // readw 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 ) ; }
300
1 2 4 6 7 8 10 11 12 14 15 16 18 19 20 22 23 24 25 26 27 29 30
package b a s i c ; import j a v a x . management . ; 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 = 3 . 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 ) { . . . } }
14.1.2
Un agent sau MBean server implementeaz interfata MBeanServer. Un a asemenea obiect se obtine printr-una din metodele statice static MBeanServer ManagementFactory.getPlatformMBeanServer() Utilitarul jconsole permite conectarea la serverul MBean. static MBeanServer MBeanServerFactory.createMBeanServer() agent se In nregistreaz componente MBean. Un obiect MBean este cara acterizat de un nume, un obiect de tip ObjectName. Inregistrarea i / sau s crearea unei componente MBean necesit denirea prealabil a acestui nume. a n Structura unei nume este domeniu : numeAtribut=valAtribut ,numeAtribut=valAtribut . . . unde
301
domeniu este un nume simbolic (String). Dac domeniul este stringul vid atunci a se consider valoarea implicit DefaultDomain. a a atribute uzuale: type=numele MBean-ului index=numr de identicare a MBean-ului a Cel putin un atribut este obligatoriu. Clasa ObjectName Constructori ObjectName(String nume) Parametrul nume are structura descris mai sus. a ObjectName(String domeniu, Hashtable<String,String> tabel ) ObjectName(String domeniu, String numeAtribut, String valAtribut) Metode static ObjectName getInstance(String nume) Inregistrarea i utilizarea MBean-ului face apel la metodele interfetei MBeanServer. s ObjectInstance Un obiect de tip ObjectInstance este folosit pentru reprezentarea ansamblului alctuit de un obiect ObjectName asociat unui MBean i numele clasei a s corespunztoare. a Interfata MBeanServer Metode ObjectInstance registerMBean(Object obj , ObjectName nume) Inregistreaz pe platform, instanta obj a unui MBean avnd numele a a a nume.
302
void unregister(ObjectName nume) ObjectInstance createMBean(String numeClas , ObjectName nume) a Creaz i a s nregistreaz un MBean de clas numeClas i de nume nume. a a as ObjectInstance createMBean(String numeClas , ObjectName nume, a Object[] param, String[] sign) plus, irul param contine parametri constructorului, de tip, respectiv In s sign. String getDefaultDomain() Object invoke(ObjectName mbeanName, String operationName, Object[] param, String[] paramTip) Se invoc operatia operationName a MBean-ului mbeanName. Parametri a necesari operatiei mpreun cu tipurile corespunztoare sunt dati varia a n abilele param i respectiv paramTip. s Object getAttribute(ObjectName mbeanName,String atribut) Returneaz valoarea atributului atribut a mbean-ului mbeanName. a void setAttribute(ObjectName mbeanName,Attribute atribut) Fixeaz valoarea atributului atribut a MBean-ului mbeanName. Retinem a doar constructorul clasei Attribute prin Attribute(String nume, Object valoare) MBeanInfo getMBeanInfo(ObjectName mbeanName) Returneaz un obiect de tip MBeanInfo util inspectrii resurselor unui a a MBean. Exist mai multe abloane de programare a a s nregistrrii unei componente a MBean. Exemplul 14.1.2 Se creaz dou componente MBean de tip Intro care vor a a inspectate prin intermediul utilitarului jconsole1 - distributia jdk . Utilitarul jconsole permite apelarea operatiilor, modicarea atributelor i s semnaleaz noticrile. a a
In acest caz, este nevoie ca variabilele de tip clas acoperitoare Double, Long s e a a nlocuite prin tipuri predenite.
1
303
1 2 3 5 6 7 8 9 10 11 13 14 15 16 18 19 21 22 24 25 26 28 29 30 31 32 33 34 35 36
package b a s i c ; import j a v a . l a n g . management . ; import j a v a x . management . ; 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 MBeanu l u i ObjectName mbeanObjectName = new ObjectName ( domeniu+ : t y p e=I n t r o , i n d e x=1 ) ; // Crearea MBeanu 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 MBeanu 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 aplicatiei revine la 1. Intr-o fereastr DOS se lanseaz agentul Main prin a a java -Dcom.sun.manager.jmxremote basic.Main 2. Intr-o alt fereastr DOS se lanseaz a a a jconsole pornind utilitarul jconsole. 3. fereastra de dialog jconsole:Connect to Agent se d clic pe Connect. In a 4. panoul Tree gsim domeniul dat. Prin clic pe domeniu apar MBeanIn a urile de indice 1 i 2. s 5. Prin clic pe unul din aceste MBean-uri, panoul central avem acces la n atributele i la operatiile lor. s
304
14.1.3
Noticri a
Pentru implementarea retinerii de ctre un agent MBean a noticrilor, a a clasa ce implementeaz interfata MBean-ului trebuie s extind clasa Notificationa a a BroadcasterSupport. Modicrile unui atribut se retin a ntr-un obiect de tip Notification i este s transmis prin metoda sendNotification(Notification notication)
305
a clasei NotificationBroadcasterSupport. Suplimentar se denete metoda s public MBeanNotificationInfo[] getNotificationInfo() care se precizeaz n a tipul noticrii - (constant denit de clasa AttributeChangeNotification); a a a clasa care s-a generat noticarea n String name = AttributeChangeNotification.class.getName(); o descriere a modicrii. a Astfel, introducerea noticrilor presupune familiarizarea cu clasele a 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()
306
AttributeChangeNotication extends Notication Constructori AttributeChangeNotification(Object source, long sequenceNumber , long timeStamp, String msg, String attributeName, String attributeType, Object oldValue, Object newValuE ) Cmpuri a static String ATTRIBUTE CHANGE Semnaleaz schimbarea atributului a Exemplul 14.1.3 Extinderea MBean-ului Intro cu noticarea modicrilor a atributelor n jconsole. Implementarea noticrilor clasa Intro presupune modicarea metodei a n setCursEuro. Totodat se adaug metoda getNoticationInfo, ce furnizeaz a a a informatii referitoare la modicarea aprut. Codul clasei care implementeaz a a a interfata devine
1 2 4 5 6 8 9 10 12 14 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
package ag e nt n ; import j a v a x . management . ; 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 = 3 . 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 ) ; sendNotification (n ) ; }
307
32 33 34 35 36 37 38 39 40 41 43 44 46 47
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 ) { . . . } }
14.1.4
Agent MBean
exemplelele anterioare resursele unui MBean au fost utilizate prin jconIn sole. Valoricarea resurselor unui MBean Intro, dintr-un MBeanServer (agent) se programeaz prin a Exemplul 14.1.4
1 2 3 4 5 7 8 9 10 11 13 14 15 16 17 18 20 21 22 23 25 26 27
package a g e n t ; import j a v a . i o . IOException ; import j a v a x . management . ; import j a v a x . management . remote . ; 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 MBeanu 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 ; 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 ) ;
308
28 29 30 31 32 33 34 35 37 38 39 41 42 43 44 45 46 47 48 49 50 51 52
System . out . p r i n t l n ( Primul numar : ) ; long m c a n n e r . nextLong ( ) ; =s 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 ( ) ) ; } } }
14.1.5
Invocarea la distant a
Din punct de vedere al programrii distribuite, cazul interesant este cel a care clasa ce implementeaz MBean-ul i clientul (agentul MBean) care o n a s utilizeaz se a pe calculatoare diferite. a a acest caz: In Este nevoie de o clasa server (agent) al crui rol este a Instantierea unui MBeanServer Instantiarea unui server de conexiune, obiect de tip MBeanServerConnection. Bazat pe tehnologia RMI sau RMI-IIOP, acest obiect gestioneaz a comunicatia dintre un client i serverul MBeanServer. Serverul de s conexiune i serverul MBeanServer apartin aceleiai clase. s s cazul utilizrii tehnologiei RMI rmiregistry i serverul MBeanServer In a s trebuie s ruleze pe acelai calculator. a s Utiliznd tehnologia RMI-IIOP, orbd serverul MBeanServer pot a s rula pe calculatoare distincte. Lansarea executie a serverului de conexiune. n Clientul dispune de interfata MBean-ului.
309
Interfata MBeanServerConnection este implementat de clasa MBeanServer a Sablonul de programare pentru instantierea obiectului de tip MBeanServerConnection i lansarea sa executie poate : s n
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 ctre a client. Lansarea executie a serverului este precedat de pornirea registrului n a rmiregistry, respectiv orbd. Exemplul 14.1.5
1 2 3 4 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 23 24 25 26 27 28 29
package s e r v e r ; import j a v a . i o . IOException ; import j a v a x . management . ; import j a v a x . management . remote . ; 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 ( ) ; // 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=
310
30 32 33 34 35 36 37 38 39 40 41 42 43
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 rndul lui, este nevoit s creeze un conector ctre server (agent), a a a prin intermediul cruia obtine un obiect ce implementeaz interfata MBeanServerConnection. a a Prin acest obiect, clientul va putea crea MBean-uri - agent - i le va putea n s utiliza resursele. Sablonul 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 interfetei MBeanServerConnection. crearea unui reprezentant local al MBean-ului prin metoda static a mbeanClass proxy = (mbeanClass)MBeanServerInvocationHandler.newProxyInstance( mbeanServerConnection,mbeanObjectName,mbeanClass.class,true); nal, MBean-ul se terge din serverul de conexiune, prin In s cs.unregisterMBean(mbeanObjectName). Exemplul 14.1.6 Client ce utilizeaz un MBean Intro, denit n Exemplul a 14.1.1
311
1 2 3 4 5 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 30 31 32 33 34 35 37 38 39 41 42 43 44 45 47 48 50 51 52 53 54 55 56 57 58
package c l i e n t ; import j a v a . i o . IOException ; import j a v a . u t i l . ; import j a v a x . management . ; import j a v a x . management . remote . ; 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 MBeanu 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 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 ) ;
312
60 61 62 64 65 66 67 68 69 70 72 73 74 75 76 77 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 95 96 97 99 100 101 102 103 104 105 106 107 108 109 110 111
// 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 c a n n e r . nextLong ( ) ; =s 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 c a n n e r . nextLong ( ) ; =s 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 ( ) ) ; } } }
Inspectarea i valoricarea resurselor unei componente MBean se s poate face i prin intermediul metodei s
1 2
313
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
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 metod poate inserat oricare din programele agent sau client. a a a n
Noticarea la distant a
Noticarea la distanta presupune utilizarea unui MBean posednd aceast a a facilitate. Pe partea de client trebuie implementat interfata NotificationListener
public void handleNotification(Notification notication, Object handback ) Ataarea i disponibilizarea clasei ce implementeaz interfata Notification s s a Listener se obtin prin metodele interfetei 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 14.1.7 Folosind exemplul 14.1.6 - dar cu MBean-ul creat pentru 14.1.3 se creaz un client cu noticare, care sesiseaz modicarea valoarii a a atributului cursEuro a MBean-ului IntroN. Implementarea interfetei 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 . i o . IOException ; import j a v a x . management . ; import j a v a x . management . remote . ; 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){
315
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 28 29 30 31 33 34 36 37 38 39 40 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 59 61
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 MBeanu 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 ( ) ; } } private s t a t i c void getMBeanResources ( MBeanInfo i n f o ) { . . . } }
Clasa Client care creaz MBean-ul trebuie lansat a a naintea clasei ClientNotif. Aceste dou clase pot rula pe calculatoare distincte. a Exemplul 14.1.8 O aplicatie servlet ntretine un cont. Actiunile ce pot ntreprinse sunt: depunerea unei sume, extragerea unei sume n limita soldului
316
i consultarea contului. Contul este implementat ca un MBean standard. Se s cere urmrirea la distanta a modicrilor suferite de cont. a a Interfata contului (a MBean-ului) este
1 2 3 4 5 6
implementat prin
1 3 4 5 6 8 9 10 12 13 14 15 16 17 18 19 20 21 22 23 24 25 27 28 29 30 31 32 33 34 35 36 37
import j a v a x . management . ; 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 }; 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 } ; } }
317
6 7 9 10 11 12 13 14 15 16 17 18 19 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
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 x . s e r v l e t . a n n o t a t i o n . WebInitParam ; @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 ) ; } } 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 r r o r : +e . g e t M e s s a g e ( ) ; 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 ;
318
65 66 67 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 96 97 98 99 100 101 102 103 104 106 107 108 109 110
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 r r o r : +e . g e t M e s s a g e ( ) ; 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 r r o r : +e . g e t M e s s a g e ( ) ; 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> ) ; out . p r i n t l n ( message ) ; out . p r i n t l n ( </p> ) ; 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> <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 :
319
11 12 13 14 15 16 17 18 19 20 21 22 23
<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 j a v a . i o . IOException ; import j a v a x . management . ; import j a v a x . management . remote . ; 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 ==0){ 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 . 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 ( DefaultDomain : +domain ) ; // Crearea o b i e c t u l u i OBjectName a t a s a t MBeanu 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 ! ) ;
320
44 45 46 47 48 49 50 51 52 53 54 55 56 58 59 61 62 63 64 65 66 67 68 69 70 71 72
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 ( ) ) ; System . out . p r i n t l n ( S o l d c u r e n t : + myNotif . getNewValue ( ) . t o S t r i n g ( ) ) ; } }
Serverul MBean este cel prezentat Exemplul 14.1.5. n Serverul MBean este plasat servlet ( catalogul WEB-INF/classes al n n aplicatiei) iar clientul care urmrete de la distanta se poate aa oriunde. a s Dup instalarea servlet-ului se lanseaz pe maina acestuia server-ul MBean. a a s Deoarece noticarea presupune existenta MBean-ului, iar acesta se instanteaz a prin metoda init a servlet-ului este nevoie de apelarea servlet-ului, depunnd a 0 uniti. Dup aceast operatie se lanseaz executie programul ClientNotif. at a a a n
321
A.1
XML
EXtensible Markup Language (XML) reprezint un limbaj pentru denirea a marcajelor de semantic, care a mpart un document prti identicabile n a n document. Din 1998, XML este un standard World Wide Web Consortium (W3C). Totodat XML este un meta-limbaj pentru denirea sintaxei de utilizat a n alte domenii. XML descrie structura i semantica i nu formatarea. s s Structura unui document XML este <?xml version="1.0" encoding="tip_codare" [standalone="yes"]?> corpul documentului alcatuit din elemente Prima linie - preambulul - reprezint declaratia de document XML. Tipul a codrii poate utf-8, iso-8859-1. a Corpul documentului este alctuit din elemente. a Inceputul unui element este indicat printr-un marcaj. Textul marcajului constituie denumirea elementului. Elementele pot cu corp, alctuit din alte elemente, avnd sintaxa a a <marcaj> corpul elementului </marcaj> 323
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 un singur element rdcin. Elementele unui document XML formeaz a a a a a un arbore. Fiecrui marcaj de a nceput al unui element trebuie s-i corespund a a un marcaj de sfrit. Caracterele mari i mici din denumirea unui element sunt as s distincte (case sensitive). Elementele ncuibrite (nested )- incluse a ntr-un alt element - nu se pot amesteca, adic un marcaj de sfrit corespunde ultimului marcaj de a as nceput. Un comentariu se indic prin a <!-Text comentariu --> Exemplul A.1.1 Fiier XML - denumirile elementelor i continutul lor permit s s ntelegerea simpl a semanticii introduse n document. a
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> <fonddetimp> <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> </ fonddetimp> </ 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> <fonddetimp> <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> </ fonddetimp> </ 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
325
20 21 22 23 24 25 26 27
<nume> S o f t matematic </nume> <fonddetimp> <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> </ fonddetimp> </ 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 preambul; a ecare element este nchis sau corespunde un marcaj de inchidere; i marcajele ncuibrite nu se amestec. a a Un document XML este valid dac a este bine formatat; cazul c exist o referinta ctre XML Schema atunci documentul XML n a a a este conform schemei. Un produs informatic accesibil gratuit, care permite vericarea bine formatrii i a validitii unui document xml, este XML Copy Editor. a s at Pentru validare, dac ierul XML Schema se a alt catalog dect cel al a s a n a erului xml atunci acestuia i se asociaz XML Schema prin XML Associate s a XML Schema. . . Prelucrarea unui document XML Java se poate face pe baza interfetelor n de programare: Document Object Model - DOM; Simple API for XML - SAX; Stream API for XML - StAX; Java Architecture for XML Binding - JAXB. Se recomand utilizarea interfetelor de programare StAX i JAXB. a s Amintim faptul c reprezentarea obiectelor matematice prin elemente XML a constituie subiectul a dou proiecte MathML i OpenMath. Obiectivul limbajua s lui MathML este reprezentarea unui text matematic ntr-un document HTML, timp ce obiectivul proiectului OpenMath este reprezentarea semantic a n a datelor matematice pentru realizarea de aplicatii cooperante ntre sisteme de calcul simbolic - CAS (Computer Algebra System).
326
A.2
apache-ant
Utilitarul apache-ant asigur executarea unui ir de comenzi de operare. a s Aceste comenzi se nregistreaz a ntr-un ier de tip xml, cu denumirea build.xml. s Astfel, apache-ant se substituie unui ier de comenzi bat Windows sau unui s n script shell din Linux/Unix. Avantajul obtinut const independenta fata de a n platforma de calcul (Windows, Linux). Instalarea const dezarhivarea ierului descrcat din Internet. a n s a Lansarea executie necesit xarea variabilei de mediu JAVA HOME, ce n a contine calea la distributia Java. Lansarea se poate face prin urmtorul ier a s de comenzi set JAVA_HOME=. . . set ANT_HOME=. . . %ANT_HOME%\bin\ant.bat %1 Parametrul %1 acestui ier de comenzi reprezint obiectivul care se dorete s a s a atins. Dac se modic denumirea sau locatia ierului build.xml atunci a a s ierul de comenzi se invoc cu optiunea -buildfile. s a Un ier build.xml corespunde unui proiect (project), alctuit din unul s a sau mai multe obiective (target). Atingerea ecarrui obiectiv const din a a ndeplinirea uneia sau mai multor sarcini (task). Apache-ant contine o familie predenit de sarcini. Programatorul are datoria xrii atributelor sarcinilor. a a Manualul din documentatia produsului contine descrierea atributelor ct i a s exemple. general, o sarcin reprezint o operatie executat uzual linia In a a a n de comand. a Atributele se dau, respectnd sintaxa XML a 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
327
Dac la apelarea lui Apache-ant lipsete parametrul optional atunci se va a s executa obiectivul default. Intr-un proiect se pot deni variabile prin marcajul <property name=numeVariabila value=valoareVariabila /> O variabil denit se va utiliza cu sintaxa ${numeVariabila}. a a Exemplul A.2.1 Fiierul build pentru executia programelor din 1.2. s
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 toate resursele utilizate, cuprinse a uzual iere cu extensia jar (j ava ar hive) sunt disponibile pe calculatorul n s local. Dac calculatorul este conectat la Internet, atunci resursele publice a pot descrcate a mpreun cu toate dependintele i utilizate prin apache-ant, a s folosind suplimentar apache-ivy 1 . In vederea utilizrii lui apache-ivy se copiaz ierul ivy-*.jar din distributia a a s apache-ivy ANT HOME\lib. n Fiierul build.xml contine plus s n
1
328
<project name="Proiect" basedir="." default="obiectiv_final" xmlns:ivy="antlib:org.apache.ivy.ant"> . . . <!-- ================================= target: resolve ================================= --> <target name="resolve" depends="init" description="--> retreive dependencies with ivy"> <ivy:retrieve/> </target> <!-- ================================= target: report ================================= --> <target name="report" depends="resolve" description="--> generates a report of dependencies"> <ivy:report todir="${report.dir}"/> </target> . . . </project> la care se adaug un ier ivy.xml, cu dependintele necesare aplicatiei care a s urmeaz a preluate dintr-unul din depozitele ivy - local, shared, public a
<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 i gestiune a proiectelor s (Project management framework). Calculatorul pe care se dezvolt proiectul a / aplicatia trebuie s e conectat la internet. Resursele necesare a ndeplinitii diferitelor sarcini (maven artifacts) sunt preluate din internet i depuse s ntr prezent sunt un depozit local maven (local repository). In ntretinute depozite
2
A.3. APACHE-MAVEN
329
publice de resurse soft necesare dezvoltrii de aplicatii cu maven 3 iar deza voltatorii de instrumente soft au posibilitatea de a-i promova produsele prin s depunerea ntr-un depozit maven. Dintr-un asemenea depozit public resursele necesare sunt descrcate depozitul local. a n
De exemplu repo1.maven.org/maven2.
330
Sablonul se specic parametrul -DarchetypeArtifactId al comenzii a n mvn archetype:create. Indeplinirea diferitelor obiective (generarea unui proiect, compilare, arhivare, testare, etc) se obtin prin comenzi maven. Comenzile maven sunt de dou tipuri: a
Comenzi pentru gestiunea ciclului de viat al unui proiect (lifecycle coma mands):
Semnicatia aeaz versiunea maven s a (util pentru vericarea functionrii lui maven) a a mvn clean terge ierele maven generate s s mvn compile compilarea sursele Java mvn test-compile compileaz sursele Java care a realizeaz testele junit a mvn test execut testul junit a mvn package creaz o arhiv jar sau war a a mvn install depune arhiva jar sau war depozitul local n
A.3. APACHE-MAVEN
genereaz structura de cataloage a proiectului a ablonul se alege dintr-o list s a clean:clean terge ierele generate urma compilrii s s n a compiler:compile compilarea sursele Java surefire:test execut testul junit a jar:jar creaz o arhiv jar a a install:install-file depune o arhiv jar depozitul local a n
mvn install:install-file \ -Dfile=numeFiier \ s -DgroupId=numePachet \ -DartifactId=numeProiect \ -Dversion=versiunea \ -Dpackaging=tipArhiv a
mvn exec:java
Astfel comanda
mvn archetype:create -DgroupId=unitbv.cs.calcul -DartifactId=hello
genereaz arborescenta a
hello |--> src | |--> main | | |--> | | | | | | | | | | | | | |--> test | | |--> | | | | | | | | | | | | | pom.xml
332
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/XMLSchemai 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 /mavenv 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 aplicatiei, din catalogul hello se execut comenzile a
mvn compile mvn test
Sarcina programatorul este acela de a nlocui aceste programe cu cele care rezolv sarcinile proiectului. Pentru orice prelucrare toate dependintele trebuie a s se gseasc depozitul local maven. a a a n Exemplul A.3.1 Dezvoltarea aplicatiei de calcul al celui mai mare divizor comun a dou numere naturale utiliznd maven. a a Generm proiectul maven a
mvn archetype:create -DgroupId=unitbv.proiect.mycmmdc -DartifactId=cmmdc
package u n i t b v . p r o i e c t . mycmmdc ; 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 ( ) { . . . } }
i s
A.3. APACHE-MAVEN
333
1 2 4 5 6 7 8 9 10 11 12 13 14
package u n i t b v . p r o i e c t . mycmmdc ; 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 c a n n e r . nextLong ( ) ; =s 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 u n i t b v . p r o i e c t . mycmmdc ; 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 ) ; } }
Intruct vom folosi versiunea 4.8.2 a produsului junit modicm ierul a a n s pom.xml versiunea acestui produs i precizm versiunea distributiei jdk utis a lizat, care trebuie s e cel putin 1.5 (restrictie impus de junit-4.8.2). a a a
1 2 3 4 5 6 7
<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/XMLSchemai 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 /mavenv 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 . 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>
334
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
<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 . 8 . 2</ 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> <p l u g i n s> <p l u g i n> <g r o u p I d>o r g . apache . maven . p l u g i n s</ g r o u p I d> < a r t i f a c t I d>mavenc o m p i l e r p l u g i n</ a r t i f a c t I d> <version>2 . 0</ version> <c o n f i g u r a t i o n> <s o u r c e>1 . 7</ s o u r c e> <t a r g e t>1 . 7</ t a r g e t> </ c o n f i g u r a t i o n> </ 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>
Operarea poate
mvn archetype:create -DgroupId=unitbv.proiect.mycmmdc -DartifactId=cmmdc cd cmmdc mvn compile mvn test mvn exec:java -Dexec.mainClass="unitbv.proiect.mycmmdc.MyCmmdc"
maven cu ant
maven se pot integra sarcini apache-ant pentru orice etap al evolutiei In a unei aplicatii. Utilizarea const completarea ierului pom.xml cu a n s
<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"/>
A.3. APACHE-MAVEN
335
<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> </goals> </execution> </executions> </plugin> </plugins> </build> ${compile_classpath}"/> ${runtime_classpath}"/> ${test_classpath}"/> ${plugin_classpath}"/>
elementul <tasks> se denesc sarcinile ant care se doresc executate la In comanda corespunztoare prelucrrii etapei din evolutia proiectului maven a a compile, package, install, test, etc. Mai precis, elementele <echo> se nlocuiesc cu sarcinile ant care se doresc efectuate. Proprietile se denesc elementul at n
<properties> <nume.proprietate>valoare</nume.proprietate> . . . </properties>
336
3.
4.
mvn compile
6.
A.3. APACHE-MAVEN
337
4.
338
java |--> | | | |
s |--> | | |
<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/XMLSchemai 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 /mavenv 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>s . i i o p . cmmdc</ g r o u p I d> < a r t i f a c t I d>cmmdciiopimpl</ 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>cmmdciiopimpl</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> <dependency> <g r o u p I d> i . cmmdc</ g r o u p I d> < a r t i f a c t I d>icmmdc</ a r t i f a c t I d> <version>1.0 SNAPSHOT version> </ </ dependency> </ d e p e n d e n c i e s> <b u i l d> <p l u g i n s> <p l u g i n> <g r o u p I d>o r g . apache . maven . p l u g i n s</ g r o u p I d> < a r t i f a c t I d>mavenantrunp l u g i n</ a r t i f a c t I d> <d e p e n d e n c i e s> <dependency> <g r o u p I d>sun</ g r o u p I d> < a r t i f a c t I d> t o o l s</ a r t i f a c t I d> <version>1 . 0</ version> <s c o p e>system</ s c o p e> <systemPath>${ j a v a . home } / . . / l i b / t o o l s . j a r</ systemPath> </ dependency> </ d e p e n d e n c i e s> <e x e c u t i o n s> <e x e c u t i o n> <i d>c o m p i l e</ i d> <phase>c o m p i l e</ phase> <c o n f i g u r a t i o n> <t a s k s> <p r o p e r t y name= c o m p i l e c l a s s p a t h r e f i d=maven . c o m p i l e . c l a s s p a t h />
A.3. APACHE-MAVEN
339
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
<rmic c l a s s n a m e= s . i i o p . cmmdc . CmmdcImpl s o u r c e b a s e= s r c i i o p= y e s b a s e= t a r g e t \ c l a s s e s c l a s s p a t h= ${ c o m p i l e c l a s s p a t h } /> <j a r b a s e d i r= t a r g e t \ c l a s s e s d e s t f i l e = cmmdciiopstub . j a r e x c l u d e s= s / /> </ t a s k s> </ c o n f i g u r a t i o n> <g o a l s> <g o a l>run</ g o a l> </ g o a l s> </ e x e c u t i o n> </ e x e c u t i o n s> </ 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>
4.
mvn compile
6. Instalarea ierului i.cmmdc. ICmmdc Stub.class arhivat cu jar des n pozitul maven local
mvn install:install-file -Dfile=cmmdciiopstub.jar -DgroupId=i.cmmdc -DartifactId=cmmdciiopstub -Dversion=1.0-SNAPSHOT -Dpackaging=jar
7.
java |--> | | |
340
<dependency> <groupId>i.cmmdc</groupId> <artifactId>icmmdc</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <dependency> <groupId>i.cmmdc</groupId> <artifactId>cmmdciiopstub</artifactId> <version>1.0-SNAPSHOT</version> </dependency>
4.
<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/XMLSchemai 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 /mavenv 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.3. APACHE-MAVEN
341
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
< 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 capitolul Servlet din cursul de n Programare distribuit. a Fiierul web.xml este completat cu elementele specice servlet-ului s (servlet i servlet-mapping). s
1 2 3 5 6 7 8 9 10 11 12 13 14 15
< !D C Y E webapp PUBLIC O T P //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>
342
Fiierul index.jsp se s nlocuiete cu ierul index.html utilizat la s s 5 servletul mentionat anterior . Fiierul pom.xml se completeaz cu s a Referintele la resursele javax.servlet.servlet-api, nece sare compilrii. a
<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/XMLSchemai 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 /mavenv 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> <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>mavenj 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>
Atentie la parametri de apelare a servlet-ului, care eventual trebuie adaptati. Contextul aplicatiei coincide cu parametrul artifactId
A.3. APACHE-MAVEN
343
33 34 35
Clauza provided din elementul <scope> implic ne includerea a 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 oprete cu Ctrl+C. s (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. desfurm arhiva war: mvn tomcat:deploy as a 2. lansm serverul Web lucru: mvn tomcat:run a n Serverul se oprete cu Ctrl+C. s
Se nlocuiete clasa App.java cu clasa CmmdcBean (curs Programare s distribuit). a (b) Prelucrarea const din a i. mvn compile
344 ii. mvn package iii. mvn install 2. Realizarea aplicatiei JSP. (a) Generarea cadrului:
(b) Dezvoltarea aplicatiei: i. Se completeaz aplicatia cu ierele cmmdc.jsp i index.html a s s din cursul Programare distribuit, desfurarea ind a as
cmmdcjsp |--> src | |--> main | | |--> | | |--> | | | | | | | | | | | | | pom.xml
346
static void assertEquals(Tip ateptat, Tip actual ) s unde Tip poate double, int, long, Object. static void assertEquals(double ateptat, double actual, double s delta) Testul reuete dac |ateptat-actual | < delta. s s a s static void assertArrayEquals(Tip[ ] ateptat, Tip[ ] actual ) s unde Tip poate byte, char, int, long, short, Object. static void assertTrue(boolean conditie) static void assertFalse(boolean conditie) static void assertNull(Object object) static void assertNotNull(Object object) cazul exemplului In
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 obtine
JUnit version 4.5 . Time: 0.03 OK (1 test)
347
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 ) ; } }
348
349
350
Anexa D Adnotri a
O adnotare este o completare, o not sau o a nsemnare care explic sau a ntregete un text. s O metadat este o adnotare a unei date. a Java o adnotare (annotation) este o metadata a unui element de cod In (identicator al unei entiti din codul Java). at O adnotare poate s-i fac efectul: as a asupra codului surs, a naintea compilrii; a asupra codului obiect, dup compilare, dar a naintea executrii; a timpul executiei codului. n Din punctul de vedere al sintaxei intereseaz a denirea unei adnotri; a declararea unei adnotri; a procesarea unei adnotri. a
D.1
Sintaxa utilizat este a import java.lang.annotation.*; modicator @interface NumeAdnotare{ declarare Element 1 351
352 declarare Element 2 . . . } unde declarare Element poate : tip numeElement(); tip numeElement() default valoare; iar tip poate
ANEXA D. ADNOTARI
predenit (int, short, long, byte, char, float, double, boolean); String Class enum adnotare tablou ale crei elemente sunt de un tip precizat anterior a Adnotarea se salveaz ca ier text, sub numele NumeAdnotare.java. a s Dup numrul elementelor declarate a a ntr-o adnotare, acesta poate 0 - caz care adnotarea este de tip marker; n 1 sau mai multe elemente (single-element / multi-value annotation).
D.2
O adnotare se poate referi la un pachet, clas, interfata, metod, cmp. a a a Inaintea declarrii elementului asupra cruia actioneaz, adnotarea se ina a a dic prin a @NumeAdnotare(numeElement 1=valoare,numeElement 2=valoare,. . . )
353
D.3
Adnotarea Override
Adnotarea Override precizeaz faptul c se suprascrie un element al clasei a a printe. a
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 locul liniei 9 se pune Date d=new Date(); atunci nu mai apare a n mesajul TestOverride.
Adnotarea Deprecated
Adnotarea Deprecated are ca efect aarea unui mesaj de avertisment s n momentul compilrii. a Exemplicm cu clasele a
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 D. ADNOTARI
Comentnd linia adnotrii are ca efect la o nou compilare disparitia mesajelor a a a de avertisment.
Adnotarea SuppressWarnings
Adnotarea SuppressWarnings inhib aarea mesajelor de avertisment. a s Relum exemplul anterior schimbnd clasa Test. urma compilrii nu mai a a In a apar mesajele de avertisment mentionate mai sus.
1 2 4 5 6 7 8
Adnotarea Target
Adnotarea Target precizeaz elementul asupra creia actioneaz: a a a ElementType.TYPE ElementType.FIELD ElementType.METHOD ElementType.PARAMETER ElementType.CONSTRUCTOR ElementType.LOCAL VARIABLE ElementType.ANNOTATION TYPE
Adnotarea Retention
Adnotarea Retention precizeaz momentul actiunii adnotrii: a a RetentionPolicy.SOURCE RetentionPolicy.CLASS RetentionPolicy.RUNTIME
355
Adnotarea Documented
Adnotarea Documented are ca efect mentionarea adnotrii documentul a n obtinut prin javadoc. Fie clasele
1 3 4
i s
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 adnotri se refer primul rnd la regsirea momentul a a n a a n executiei a valorilor elementelor adnotrii. functie de valorile regsite se pot a In a implementa actiuni specice. Procesarea unei adnotri se bazeaz pe metodele interfetei AnnotationElement, a a implementat de clasele Class, Constructor, Field, Method, Package: a <T extends Annotation> T getAnnotation(Class<T> annotationClass) Annotation[] getAnnotations() Annotation[] getDeclaredAnnotations() boolean isAnnotationPresent(Class<? notationClass) Considerm adnotarea a
1 2 3 4 5 6 7
import j a v a . l a n g . a n n o t a t i o n . ; @Retention ( R e t e n t i o n P o l i c y .RUNTIME) @Target ( ElementType .METHOD) public @ i n t e r f a c e MyAnnotation { S t r i n g doAction ( ) default ; i n t i n d e x ( ) default 0 ; }
ANEXA D. ADNOTARI
import j a v a . l a n g . a n n o t a t i o n . ; import j a v a . l a n g . r e f l e c t . ; 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 l . getMethod ( v e r i f , =c 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= g e t A n n o t a t i o n ( MyAnnotation . c l a s s ) ; m. 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 ( ) ) ; } } }
E.1
Derby / Javadb
Instalarea produsului const dezarhivarea ierului descrcat. a n s a Utilizarea produsului. Va utilizat varianta de retea bazat pe un a a server al SGBD care utilizeaz implicit portul 1527. a Se ntreprind urmtoarele operatii: a 1. Lansarea serverului Derby / Javadb:
set JAVA_HOME=. . . set DB_HOME=. . . set PATH=%DB_HOME%\bin;%PATH% startNetworkServer.bat
2. Crearea bazei de date se va face utiliznd utilitarul ij din distributia a Derby / Javadb. Acesta se lanseaz prin: a
set JAVA_HOME=. . . set DB_HOME=. . . set PATH=%DB_HOME%\bin;%PATH% ij.bat
358
Baza de date AgendaEMail se creaz executnd a a run CreateAgendaE.sql; unde ierul CreateAgendaE.sql este s
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 ) ;
Putem crea tabele i le arca cu valori prin ant. acest caz, prealabil s nc In n trebuie creat baza de date prin intermediul utilitarului ij: a
connect jdbc:derby:AgendaEMail;create=true;
E.2. MYSQL
359
url="${db.url}" userid="${db.user}" password="${db.pw}" onerror="continue"> <classpath refid="master-classpath"/> DROP TABLE adrese; </sql> </target> <target name="loadData"> <echo message="LOAD DATA USING: ${db.driver} ${db.url}"/> <sql driver="${db.driver}" url="${db.url}" userid="${db.user}" password="${db.pw}" onerror="continue" src="${valuesTable}"> <classpath refid="master-classpath"/> </sql> </target> <target name="printData"> <echo message="PRINT DATA USING: ${db.driver} ${db.url}"/> <sql driver="${db.driver}" url="${db.url}" userid="${db.user}" password="${db.pw}" onerror="continue" print="true"> <classpath refid="master-classpath"/> SELECT * FROM adrese; </sql> </target> </project>
E.2
mysql
Instalarea produsului. Pentru instalare s-a descrcat varianta fr ina aa stalare automat mysqll-*.*.*-win*.zip. Acest ier se dezarhiveaz a s a ntr-un catalog MYSQL HOME.
360
Implicit, serverul mysql utilizeaz portul 3306, iar ierele bazelor de date a s vor gzduite catalogul MYSQL HOME\data. a n Pentru utilizarea aplicatii Java trebuie descrcat un conector mysqln a connector-java-*.*.*.tar.gz, continnd ierul mysql-connector-java a s *.*.*-bin.jar. Utilizarea produsului. Se ntreprind urmtoarele operatii: a 1. Lansarea serverului mysql :
set MYSQL_HOME=. . . set PATH=%MYSQL_HOME%\bin;%PATH% mysqld
2. Unui utilizator i se poate atasa o parol, executnd a a ntr-o sesiune mysql comenzile
set password for root@localhost=password(parola); set password for [email protected]=password(parola);
Daca utilizatorul are o parola atunci la apelarea utilitarului mysql va prezent i optiunea -p. as 3. Exemplul E.2.1 Crearea bazei de date AgendaEMail se va face prin intermediul ierului s 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 );
361
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 ) ;
E.3
Interactiunea cu baze de date relationale implic: a 1. Stabilirea corespondentei dintre date aate obiecte i atribute / tabele n s (object to relational database mapping). 2. Apelarea actiunilor CRUD (Create, Read, Update, Delete). Pentru realizarea acestor activiti se utilizeaz modelul Data Access Object at a DAO Limbajul SQL (Structured Query Language) este dependent de SGBD utilizat. Dezvoltarea interactiunii dintre un program Java (client) cu o baz de a date dintr-un SGBD s-a nscut din dorinta de a asigura independenta stratului a Java de SGBD. Solutia gsit const introducerea unui strat suplimentar, a a a n ntre Java i SGBD care asigur corespondenta s a ntre obiectele Java cu tabelele unei baze de date i permite o congurare simpl la schimbarea SGBD. Astfel s a se folosete terminologia de aplicatie multistrat. s Materializarea acestor idei (Object Relational Mapping - ORM) se a a n interfata de programare (API) Java Persistence API (JPA); Exist mai multe implementri JPA. a a interfata de programare (API) Java Data Object (JDO); produsul Hibernate. Hibernate contine i o implementare JPA. s
362
Scopul urmrit este realizarea trecerii de la un SGBD la altul prin modicri a a minime stratul intermediar. n Pentru nceput vom face abstractie de modelele mentionate anterior i vom s trata modul cel mai simplu realizarea unei aplicatii care interactioneaz cu n a o baz de date gestionat de un SGBD. a a Pentru a avea acces la o baz de date trebuie stabilit o conexiune la acea a a acest sens este necesar cunoaterea: baz de date. In a s 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 Fiierul s driver-ului mysql-connector-java-*.*.*-bin.jar (www.mysql.com) derbyclient.jar (distributia derby) postgresql-*.*-*.jdbc4.jar hsqldb.jar ojdbc14.jar
Dac a ntr-un servlet se realizeaz o conexiune la o baz de date atunci a a ierul driver-ului trebuie copiat catalogul lib al aplicatiei. s n adresa URL a bazei de date (String URLBazaDate), sub forma Tip SGBD Referinta 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 Sablonul de prelucrare este String URLBazaDate=. . . Connection con=null; try{ Class.forName(jdbcDriver).newInstance(); con=DriverManager.getConnection(URLBazaDate); ... } catch(ClassNotFoundException e){. . .} catch(SQLException e){. . .}
363
Anumite SGBD asigur accesul la o baz de date dac sunt xati parametrii a a a acest caz se programeaz username i password. In s a con=DriverManager.getConnection(URLBazaDate,username,password); Odat conexiunea cu baza de date stabilit se genereaz un obiect de tip a a a Statement prin intermediul cruia se execut interogarea SQL. a a Statement instructiune=con.createStatement(); String sql=. . . //fraza select; Rezultatele interogrii bazei de date se obtine prin a try{ ResultSet rs=instructiune.executeQuery(sql); while(rs.next()){ prelucrarea rezultatului } } catch(SQLException e){...} Exemplul E.3.1 O interogare simpl a bazei de date AgendaEMail se realizeaz cu programul a a
1 2 3 4 6 7 9 10 11 12 14 15 16 18 19 20 21 22 23 24 25
public c l a s s AgendaE { Statement i n s t r u c t i u n e=n u l l ; public void i n i t ( S t r i n g username , S t r i n g password ) { // 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 ; C o n n e c t i o n con=n u l l ; 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 ( ) ; i f ( username != n u l l ) con = DriverManager . g e t C o n n e c t i o n ( URLBazaDate , username , password ) ; else 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 ( ) ;
364
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 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
} 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 s t a t i c void main ( S t r i n g [ ] a r g s ) { AgendaE agenda=new AgendaE ( ) ; i f ( a r g s . l e n g t h >1) agenda . i n i t ( a r g s [ 0 ] , a r g s [ 1 ] ) ; else agenda . i n i t ( null , n u l 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 ) ; 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 ; 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 ()+ \ ; s q l= s e l e c t from a d r e s e where nume=+nume ; r s=agenda . i n s t r u c t i u n e . e x e c u t e Q u e r y ( s q l ) ; i f ( r s != n u l l ) { System . out . p r i n t l n ( Sau g a s i t a d r e s e l e de em a i l : ) ; while ( r s . n e x t ( ) ) { System . out . p r i n t l n ( r s . g e t S t r i n g ( e m a i l ) ) ; } } else { System . out . p r i n t l n ( Fara a d r e s a de em 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 ()+ \ ; 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 ; r s=agenda . i n s t r u c t i u n e . e x e c u t e Q u e r y ( s q l ) ; i f ( r s != n u l l ) {
365
System . out . p r i n t l n ( Sa g a s i t numele + :); while ( r s . n e x t ( ) ) { System . out . p r i n t l n ( r s . g e t S t r i n g ( nume ) ) ; } } else { System . out . p r i n t l n ( Numar i n e x i s t e n t ! ) ; } 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 ) { 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 ( ) ) ; } } }
Fraza select i interogarea se mai putea programa prin s String sql="select * from adrese where nume =?"; PreparedStatement prepStmt=con.prepareStatement(sql); prepStmt.setString(1,nume); RezultSet rs=prepStmt.executeQuery(); . . . prepStmt.close(); acest caz, valoarea variabilei nume este fr apostroafe. In aa Compilarea i executia programului necesit declararea variabila classpath s a n a ierelor s Varianta Derby derbyclient.jar din catalogul %DERBY INSTALL%\lib. Varianta mysql %MYSQL CONNECTOR JAVA HOME%\mysql-connector-java-*.*.*-bin.jar Executia programului presupune serverul SGBD activ.
366
1. S se realizeze conversia temperaturii exprimat grade Celsius grade a a n n Fahrenheit i invers. Formula de transformare este s tF = 1.8tC + 32o F RMI, programul server implementeaz interfata (la distanta) In 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 se realizeze conversia a unei sume de bani a ntre USD, EURO i RON. s Programul server (RMI) implementeaz interfata 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)
367
368
Rata zilnic de schimb preia dinamic sub forma unui ier xml, apelnd a s a http://www.bnr.ro/nbrfxrates.xml. 3. S se realizeze conversia unui numr natural, din cifre arabe cifre a a n romane i invers. s Pentru numere x (3999, 3999999], x = a 1000 + b se va folosi scrierea sub forma (A)B, unde A, B reprezint conversiile lui a, respectiv b. a Exemplu: Conversia numrului 2289463 este (MMCCLXXXIX)CDLXIII. a Pentru numere x (4000000, 3999999999], x = a1000000+b1000+c se va folosi scrierea sub forma [A](B)C, unde A, B, C reprezint conversiile a lui a, b, c. 4. S se realizeze conversia unui numr dintr-o baz alta. a a a n 5. Un server adun la un numr (initializat cu 0) o valoare trimis de a a a un client returnnd rezultatul. Exist o singur instanta a numrului, a a a a acelai pentru orice client. s S se programeze serviciul descris mai sus. a 6. Aplicatia productor consumator. a Fie un sistem format din dou procese P1 i P2 , primul producnd nite a s a s date care apoi vor preluate de cel de al doilea. Comunicarea ntre cele dou procese se realizeaz prin intermediul unei zone de memorie a a tampon, de o anumit dimensiune, care procesul P1 introduce a n informatii (sub forma unor nregistrri), pe care apoi P2 le extrage. a Procesul P2 nu este nevoit s atepte pentru ecare a s nregistrare parte, n iar P1 nu atept pn ce P2 este gata s receptioneze s a a a a nregistrarea produs. Procesele evolueaz independent unul de cellat, P1 introducnd a a a a tampon n nregistrarea produs, de unde P2 o va extrage la nevoie. a Se impun urmtoarele restrictii: a Procesul P1 ncearc s introduc o a a a nregistrare tampon i conn s stat c acesta s-a umplut. acest caz, el va trebui s atepte pn a a In a s a a ce se ivete un loc tampon (ceea ce se va ampla ca urmare a s n nt extrageri unei nregistrri de ctre P2 ). a a
369
Procesul P2 ncearc s extrag o a a a nregistrare i constat c tams a a acest caz el va trebui s atepte pn ce apare o ponul este gol. In a s a a nregistrare ca urmare a introduceri unei nregistrri tampon de a n ctre P1 . a Se denete interfata RMI s
package iprodcons; public interface IBoundedBuffer extends java.rmi.Remote{ public void put(Object obj) throws java.rmi.RemoteException; public Object get() throws java.rmi.RemoteException; }
Se cere: (a) Implementarea interfetei IBoundedBuer. (b) Realizarea a dou programe client Producator, care introduce obiecte a tampon i Consumator pentru extragerea lor. n s 7. Aplicatie 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; } }
370
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 prealabil s n a se nregistreze (createUser). Un client nregistrat se poate conecta la serverul de e-mail (login) dup a care poate scrie (trimite) sau citi (receptiona) mesaje. Se cere ca la adgarea unui mesaj (deci a naintea apelrii metodei User.addEmail) a s se verice dac emitentul este conectat i dac destinatarul este a a s a nregistrat. caz contrar se genereaz exceptia UnknownUserException n a
package iemail; public class UnknownUserException extends Exception { public UnknownUserException() { super(); }
371
Citirea mesajelor este lsat la latitudinea clientilor sensul c clientul a a n a implementeaz metoda printEmail al interfetei ICallbackEmail. a
package iemail; import java.rmi.*; import java.rmi.server.*; public interface ICallbackEmail extends Remote { public void printEmail(Email email) throws RemoteException; }
Solicitarea receptionrii mesajelor se realizeaz de ctre server prin apelarea a a a metodei printEmail pentru ecare mesaj primit de client. Se cere: (a) Implementarea interfetei IEmailServer. (b) Realizarea a dou programe client AddClient pentru a nregistrarea utilizatorilor i ClientEmail pentru exploatarea serviciului de es mail. Fiecare din cele dou programe are ca parametri numele a (identicatorul) clientului, parola i referinta serverului. s 8. Integrare numeric. a Scopul aplicatiei este calculul unei integrale de un program server cu functia de integrat detinut de ctre client. cazul aplicatiei RMI, a a In evalurile functiei cerute de formula de integrare numeric se vor reala a iza prin apel invers. Integrarea numeric va executat de un server a disponibil clientilor prin mecanismul de fabric de obiecte. a Interfata fabricii de obiecte este
package integ; import java.rmi.*; public interface IFabIntegrator extends Remote{ IIntegrator getIntegrator() throws RemoteException; }
372
declar o metod ce calculeaz un ir (Imk )k pn momentul |Imk a a a s a a n Imk1 | < . Propunem utilizarea formulei lui Simpson
b a m1 m1 ba f (x)dx Im = [f (a) + 2 f (a2i ) + 4 f (a2i+1 ) + f (b)] 6m i=1 i=0
unde ai = a + i ba . 2m Sirul (mk )k este denit prin mk = 2k m0 . Semnicatia parametrilor metodei adaptiveSimpson este leftEnd rightEnd epsilon initParam Interfata apelului invers este
package integ; import java.rmi.*; double function(double x)throws RemoteException; }
a b m0
Se cere implementarea aplicatiei cu minimizarea numrului de apelri a a a metodei function. 9. Agend telefonic. a a Pentru crearea i s ntretinerea unei agende telefonice utiliznd RMI con a siderm: a Un ServerCarteTelefon realizeaz urmtoarele operatii: a a adaug o a nregisrare agenda telefonic; n a O nregistrare este alctuit dintr-o pereche (nume, numr). a a a
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; } }
373
sterge nregistrarea corespunztoare unui nume din agenda telea fonic. a interogarea agendei: furnizeaz numrul de telefon al unui nume; a a modicarea numrului de telefon corespunztor unui nume; a a aarea s nregistrrilor; a salvarea nregistrrilor a ntr-un ier; s restaurarea nregistrrilor dintr-un ier. a s Interfata corespunztoare ICarteTelefon este a
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 aplicatiei de creare i s ntretinere a agendei tele fonice. Se extinde aplicatia anterioar cu functiunea suplimentar a serverului de a a a retine toate modicrile efectuate de ctre un client i care la solicitare a a s pot aate. s Modicrile se retin a ntr-o variabil mod de tip Vector. La solicitarea a clientului, pentru ecare modicare memorat, programul server apea leaz metoda schimbStare declarat interfata a a n
package itelef; import java.rmi.*; public interface IApelInvers extends Remote{ void schimbStare(Entry e) throws RemoteException; }
374
Metoda schimbStare(Entry e) nu face altceva dect aeaz cmpurile a s a a variabilei e. Interfata ICarteTelefon declar plus metoda a n void apelInvers(IApelInvers obj)throws RemoteException; Aceast metod va implementat programul ServerCarteTelefon.java. a a a n Elementelor retinute vectorul mod li se aplic metoda schimbStare(). n a S se implementeze acest functiune utiliznd tehnica apelului invers. a a a Se poate utiliza baza de date AGENDATELEFONICA format din tabelul a TELEF ID NUME NUMAR 10. S se realizeze programe client avnd o interfat grac. Recomandm a a a a a utilizarea produsului NetBeans. R. Exemplu de client pentru problema calculului celui mai mare divizor comun a dou numere cu soclu TCP. a
import java.net.*; import java.io.*; public class VisualCmmdcClient extends javax.swing.JFrame { public VisualCmmdcClient() { initComponents(); } private void initComponents(){ // cod generat de Netbeans } private void jButton1MouseClicked(java.awt.event.MouseEvent evt){ long m=(new Long(jTextField1.getText())).longValue(); long n=(new Long(jTextField2.getText())).longValue(); String host=jTextField4.getText(); int port=(new Integer(jTextField5.getText())).intValue(); Socket cmmdcSocket = null; DataInputStream in=null; DataOutputStream out=null; try { cmmdcSocket = new Socket(host, port); out=new DataOutputStream(cmmdcSocket.getOutputStream()); in=new DataInputStream(cmmdcSocket.getInputStream()); }
375
catch(UnknownHostException e) { System.err.println("Server necunoscut: "+host); System.exit(1); } catch (IOException e) { System.err.println("Eroare I/O : "+host+" la portul "+port); System.exit(1); } try{ out.writeLong(m); out.writeLong(n); long r=in.readLong(); jTextField3.setText(new Long(r).toString()); out.close(); in.close(); cmmdcSocket.close(); } catch(IOException e){ System.err.println("Imposibilitate de comunicare"); } } private void exitForm(java.awt.event.WindowEvent evt) { System.exit(0); } public static void main(String args[]) { new VisualCmmdcClient().setVisible(true); } private private private private private private private private private private } javax.swing.JButton jButton1; javax.swing.JLabel jLabel1; javax.swing.JLabel jLabel2; javax.swing.JLabel jLabel3; javax.swing.JLabel jLabel4; javax.swing.JTextField jTextField1; javax.swing.JTextField jTextField2; javax.swing.JTextField jTextField3; javax.swing.JTextField jTextField4; javax.swing.JTextField jTextField5;
11. S se determine zodia (chinezeasc) corespunztoare unei date calena a a daristice. Obs. Inceputul anului nou chinezesc nu coincide cu nceputul anului nou calendaristic. a a Se va crea baza de date AN CHINEZESC alctuit din tabelul INCEPUT AN LUNA ZI 12. Se consider baza de date UNITATI DE MASURA format din tabelul a a
376 CONVERSIE UM SI UM SIMBOL DENUMIRE (ROM) VAL Exemplu: 1 2 3 4 M INCH Tol M FEET (FT) Picior KG UK ONCE Uncie (UK) KG UK POUND Livra (UK)
S se realizeze o aplicatie pentru conversia unitilor de msur extinznd a at a a a continutul bazei de date. 13. Se consider baza de date NORME-DIDACTICE format din tabelele a a CADRU-DIDACTIC COD-CADRU-DIDACTIC NUME MATERIA COD-MATERIE DENUMIRE CURSURI COD-CURS COD-CADRU-DIDACTIC COD-MATERIE
S se elaboreze programe de a ntretinere i interogare a bazei de date. s 14. Se consider baza de date APROVIZIONARE format din tabelele a a RESURSA FURNIZOR CONTRACT COD-RESURSA COD-FURNIZOR COD-CONTRACT DENUMIRE NUME COD-FURNIZOR CANTITATE COD-RESURSA CANTITATE S se elaboreze programe de a ntretinere i interogare a bazei de date. s 15. Se consider baza de date DESFACERE format din tabelele a a PRODUSE BENEFICIAR CONTRACT COD-PRODUS COD-BENEFICIAR COD-CONTRACT DENUMIRE NUME COD-BENEFICIAR CANTITATE COD-PRODUS CANTITATE
377
S se elaboreze programe de a ntretinere i interogare a bazei de date. s 16. Validarea codului numeric personal.
Codul Numeric Personal (CNP) constituie numrul de ordine atribuit de a Evidenta populatiei unei persoane la natere, de cetenie romn, care se s at a a nscrie actele i certicatele de stare civil i se preia celelate acte cu n s a s n caracter ocial.
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 folosete cheia de testare 279146358279. s Primele 12 cifre ale CNP se nmultesc pe rnd de la stnga spre dreapta a a cu cifra corespunztoare a cheii de testare. Cele 12 produse se adun, a a iar suma se mparte la 11. Dac restul artirii este mai mic dect 10, a mp a atunci acesta va cifra de control. Dac restul artirii este 10 atunci a mp cifra de control este 1. S se elaboreze un program pentru vericarea CNP. a 17. Informatiile unui aeroport civil privind decolrile(plecri) i aterizri(sosiri) a a s a pe parcursul unei perioade sunt cuprinse tabelul activitate al bazei de n date aeroport
Bibliograe
[1] ATHANASIU I., COSTINESCU B., DRAGOI O.A., POPOVICI F.I., 1998, Limbajul Java. O perspectiv pragmatic. Ed. Computer Libris a a Agora, Cluj-Napoca. [2] BOIAN F.M., BOIAN R. F., 2004, Tehnologii fundamentale Java pentru aplicatii Web. Ed. Albastr, Cluj-Napoca. a [3] BOIAN F.M., 2011, Servicii Web; Modele, Platforme, Aplicatii. Ed. Al bastr, Cluj-Napoca. a [4] BURAGA S.C., 2001, Tehnologii Web. Ed. Matrix Rom,Bucureti. s [5] BURAGA S. (ed), 2007, Programarea n Web 2.0., Ed. Polirom, Iai. s [6] JURCA I., 2000, Programarea retelelor de calculatoare. Ed. de Vest, Timioara. s [7] HUNTER J., CRAWFORD W., 1998, Java Servlet Programming. OReilly. [8] ALBOAIE L., BURAGA S., 2006, Servicii Web. Ed. Polirom, Iai. s [9] SCHEIBER E., 2007, Programare concurent i paralel distribuit n Java. as a Ed. Albastr, Cluj-Napoca. a [10] TANASA S., ANDREI S., OLARU C., 2011, Java de la 0 la extert. Ed. Polirom, Iai. s [11] TANASA S., OLARU C., 2005, Dezvoltarea aplicatiilor Web folosind Java. Ed. Polirom, Iai. s [12] * * * , Java 2 SDK /docs/, Sun Microsystems. [13] * * * , JavaWS Tutorial 1.*, Sun Microsystems. 379
380 [14] * * * , J2EE Tutorial, Sun Microsystems. [15] * * * , Java 2 Tutorial, Sun Microsystems.
BIBLIOGRAFIE