distr1
TRANSCRIPT
Universitatea Transilvania din BrasovFacultatea de Matematica–Informatica
Catedra de Informatica
ERNEST SCHEIBER
PROGRAMARE DISTRIBUITA INJAVA
Brasov
2
Introducere
Retelele locale, internetul, raspandirea pe o arie geografica a resurselor si alocatiilor ın care se petrec actiuni ce tin de o activitate bine definita sau sunturmarite, gestionate din alte locuri au drept consecinta existenta aplicatiilor dis-tribuite. Termenul distribuit se refera tocmai la faptul ca componente ale aplicatieise afla pe calculatoare diferite dar ıntre care au loc schimburi de date. Dacapartile unei aplicatii sau resursele utilizate se gasesc pe calculatoare distincte atunciaplicatia se numeste distribuita.
Intre partile sau resursele unei aplicatii distribuite au loc schimburi de date,ceea ce se face utilizand diferite mecanisme la realizarea carora concura sistemul decalcul, sistemul de operare si limbajul de programare.
Astfel se vorbeste de programare distribuita ca mijloc de realizare a aplicatiilordistribuite. Pe langa algoritm, structuri de date, limbaj de programare, la realizareaunei aplicatii distribuite intervin comunicatiile: schimbul de date dintre doua com-ponente aflate pe calculatoare diferite.
Punem ın evidenta doua modele de aplicatii distribuite:
• client-server: Programul server executa cererile clientilor. Amintim urmatoareletehnologii Java pentru realizarea aplicatiilor client-server:
– RMI (Remote Method Invocation)
– CORBA (Common Object Request Brocker Arhitecture)
– JMS (Java Message Service)
– Servlet si JSP (Java Server Pages)
– Portlet
– Java Web Start
– Java Management Extentions (JMX)
• dispecer-lucrator: Programul dispecer distribuie sarcinile de executat lucratorilorsi le coordoneaza activitatea. Exista multe abordari de programere a aplicatiilordispecer-lucrator.
Scopul acestui curs este prezentarea tehnologiilor de programare Java care permitprogramarea aplicatiilor client - server:
3
4
• socluri Java;
• apelarea metodelor de la distanta (Remote Method Invocation - RMI );
• CORBA - Common Object Request Brocker Arhitecture;
• mesageria Java;
• servlet;
• Java Server Pages - JSP;
• Portlet si Portal;
• Java Management Extentions - JMX.
Metodele si instrumentele de programare vor fi exemplificate pe problema foartesimpla de calcul a celui mai mare divizor comun a doua numere naturale. Codulmetodei de calcul este
1 public long cmmdc( long m, long n){2 long r , c ;3 do{4 c=n ;5 r=m%n ;6 m=n ;7 n=r ;8 }9 while ( r !=0) ;
10 return c ;11 }
Pentru aplicatiile care utilizeaza o baza de date, sistemul de gestiune a bazei dedate (SGBD) va fi una dintre sistemele Derby/Javadb sau mysql.
Cuprins
1 Applet - Miniaplicatie Java 9
1.1 Clasa Applet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
1.2 Desfasurarea unui applet . . . . . . . . . . . . . . . . . . . . . . . . . 10
1.3 Comunicare Java - JavaScript ıntr-un applet . . . . . . . . . . . . . . 17
2 Programare cu socluri Java 19
2.1 Aplicatii client – server . . . . . . . . . . . . . . . . . . . . . . . . . . 19
2.2 Notiuni despre retele . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
2.3 Soclu TCP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
2.3.1 Clasa java.net.Socket . . . . . . . . . . . . . . . . . . . . . 21
2.3.2 Clasa java.net.ServerSocket . . . . . . . . . . . . . . . . . 21
2.4 Aplicatie client – server cu socluri . . . . . . . . . . . . . . . . . . . 22
2.5 Datagrame . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
2.5.1 Clasa java.net.DatagramPacket. . . . . . . . . . . . . . . . 26
2.5.2 Clasa java.net.DatagramSocket . . . . . . . . . . . . . . . 27
2.5.3 Clasa java.net.InetAddress . . . . . . . . . . . . . . . . . 29
2.5.4 Aplicatii client – server cu datagrame. . . . . . . . . . . . . . 31
2.5.5 Multicast vs. Broadcast . . . . . . . . . . . . . . . . . . . . . 35
2.6 Canale de comunicatie . . . . . . . . . . . . . . . . . . . . . . . . . . 36
2.6.1 Clasa java.nio.Buffer . . . . . . . . . . . . . . . . . . . . . 36
2.6.2 Clasa java.nio.ByteBuffer . . . . . . . . . . . . . . . . . . 39
2.6.3 Clasa java.net.InetSocketAddress . . . . . . . . . . . . . 40
2.6.4 Clasa java.nio.channels.ServerSocketChannel . . . . . . 40
2.6.5 Clasa java.nio.channels.SocketChannel . . . . . . . . . . 41
2.6.6 Clasa java.nio.channels.DatagramChannel . . . . . . . . . 43
2.7 Conexiuni HTTP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
3 Regasirea obiectelor prin servicii de nume 49
3.1 Java Naming and Directory Interface . . . . . . . . . . . . . . . . . . 49
3.1.1 LDAP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
5
6 CUPRINS
4 Invocarea procedurilor la distanta 57
4.1 Remote Method Invocation . . . . . . . . . . . . . . . . . . . . . . . 57
4.1.1 Crearea unei aplicatii RMI . . . . . . . . . . . . . . . . . . . 60
4.1.2 Tipare de programare . . . . . . . . . . . . . . . . . . . . . . 65
4.1.3 Obiect activabil la distanta . . . . . . . . . . . . . . . . . . . 71
4.2 CORBA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
4.2.1 Conexiunea RMI - CORBA . . . . . . . . . . . . . . . . . . . 76
4.2.2 Aplicatie Java prin CORBA . . . . . . . . . . . . . . . . . . . 81
5 Mesaje ın Java 89
5.1 Java Message Service (JMS) . . . . . . . . . . . . . . . . . . . . . . . 89
5.2 Open Message Queue . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
5.3 Apache ActiveMQ . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
5.4 Elemente de programare - JMS . . . . . . . . . . . . . . . . . . . . . 92
5.4.1 Trimiterea unui mesaj . . . . . . . . . . . . . . . . . . . . . . 92
5.4.2 Receptia sincrona a unui mesaj . . . . . . . . . . . . . . . . . 97
5.4.3 Receptia asincrona a unui mesaj . . . . . . . . . . . . . . . . 99
5.4.4 Publicarea mesajelor . . . . . . . . . . . . . . . . . . . . . . . 100
5.4.5 Subscrierea si receptia mesajelor . . . . . . . . . . . . . . . . 101
5.5 Mesaje SOAP prin Java Message Service . . . . . . . . . . . . . . . . 103
5.5.1 SOAP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
5.5.2 Mesaje SOAP . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
5.5.3 Atasamente SOAP . . . . . . . . . . . . . . . . . . . . . . . . 111
5.6 Programe JMS prin apache-qpid . . . . . . . . . . . . . . . . . . . . 119
5.7 Protocolul AMQP . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126
5.7.1 Crearea unei cozi . . . . . . . . . . . . . . . . . . . . . . . . . 128
5.7.2 Expedierea / publicarea unui mesaj . . . . . . . . . . . . . . 129
5.7.3 Receptionarea mesajelor . . . . . . . . . . . . . . . . . . . . . 131
6 Servlet 137
6.1 Marcajul <form> . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
6.2 Server Web - container de servlet . . . . . . . . . . . . . . . . . . . . 139
6.3 Realizarea unui servlet . . . . . . . . . . . . . . . . . . . . . . . . . . 140
6.3.1 Instalarea unui servlet . . . . . . . . . . . . . . . . . . . . . . 140
6.3.2 Compilarea si apelarea unui servlet . . . . . . . . . . . . . . . 142
6.3.3 Codul unui servlet . . . . . . . . . . . . . . . . . . . . . . . . 143
6.4 Facilitati de programare cu servlet . . . . . . . . . . . . . . . . . . . 149
6.4.1 Program client al unui servlet . . . . . . . . . . . . . . . . . . 149
6.4.2 Servlete ınlantuite . . . . . . . . . . . . . . . . . . . . . . . . 152
6.4.3 Sesiune de lucru . . . . . . . . . . . . . . . . . . . . . . . . . 154
6.4.4 Cookie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155
6.4.5 Autorizarea accesului prin parola . . . . . . . . . . . . . . . . 157
CUPRINS 7
6.4.6 Servlet cu conexiune la o baza de date . . . . . . . . . . . . . 159
6.4.7 Imagini furnizate de servlet . . . . . . . . . . . . . . . . . . . 161
6.4.8 Servlet cu RMI . . . . . . . . . . . . . . . . . . . . . . . . . . 163
6.4.9 Servlet cu JMS . . . . . . . . . . . . . . . . . . . . . . . . . . 164
6.5 FileUpload . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
6.6 Descarcarea unui fisier . . . . . . . . . . . . . . . . . . . . . . . . . . 172
6.7 Filtru . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173
7 Java Server Page – JSP 177
7.1 Tehnologia JSP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 177
7.1.1 Declaratii JSP . . . . . . . . . . . . . . . . . . . . . . . . . . 182
7.1.2 Directive JSP . . . . . . . . . . . . . . . . . . . . . . . . . . . 183
7.1.3 Marcaje JSP predefinite . . . . . . . . . . . . . . . . . . . . . 184
7.1.4 Componenta Java (Java Bean) . . . . . . . . . . . . . . . . . 185
7.1.5 Pagini JSP cu componente Java . . . . . . . . . . . . . . . . 186
7.2 JSP Standard Tag Library JSTL . . . . . . . . . . . . . . . . . . . . 189
7.2.1 Biblioteca de baza . . . . . . . . . . . . . . . . . . . . . . . . 190
7.2.2 Biblioteca de lucru cu baze de date . . . . . . . . . . . . . . . 195
7.3 Marcaje JSP personale . . . . . . . . . . . . . . . . . . . . . . . . . . 196
7.3.1 Marcaje fara atribute si fara corp. . . . . . . . . . . . . . . . 196
7.3.2 Marcaje cu atribute si fara corp. . . . . . . . . . . . . . . . . 200
7.3.3 Marcaje cu corp. . . . . . . . . . . . . . . . . . . . . . . . . . 202
8 Portlet 205
8.1 Apache-pluto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 207
8.2 Dezvoltarea unui portlet . . . . . . . . . . . . . . . . . . . . . . . . . 207
8.3 Elemente de programare . . . . . . . . . . . . . . . . . . . . . . . . . 211
8.4 Produse Portal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221
8.4.1 uPortal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221
8.4.2 Jetspeed-2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224
9 Java Web Start 227
9.1 Java Web Start . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 227
10 Java Management Extensions 233
10.1 Standard MBean . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 234
10.1.1 Crearea unui Standard MBean . . . . . . . . . . . . . . . . . 234
10.1.2 Crearea unui MBeanServer . . . . . . . . . . . . . . . . . . . 236
10.1.3 Notificari . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 239
10.1.4 Agent MBean . . . . . . . . . . . . . . . . . . . . . . . . . . . 242
10.1.5 Invocarea la distanta . . . . . . . . . . . . . . . . . . . . . . . 243
8 CUPRINS
11 Teme de laborator 25711.1 Probleme propuse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 257
A Unealta de dezvoltare apache-ant 269
B Utilizarea SGBD ın Java 275B.1 Derby / Javadb . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 275B.2 mysql . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 277B.3 PostgreSQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 279B.4 HyperSQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 280B.5 Oracle XE 10g . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 281B.6 Sablonul de utilizare a unei baze de date . . . . . . . . . . . . . . . . 282B.7 Modelul DAO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 286B.8 Java Persistence API - JPA . . . . . . . . . . . . . . . . . . . . . . . 294
B.8.1 apache-openjpa . . . . . . . . . . . . . . . . . . . . . . . . . . 295
Bibliografie 303
Capitolul 1
Applet - Miniaplicatie Java
O categorie deosebita de programe Java ıl reprezinta miniaplicatiile (applet-uri), care se executa prin intermediul unui program de navigare ın WWW (WorldWide Web) – browser (Mozilla Firefox, Google Chrome, Microsoft InternetExplorer,Opera, Apple Safari. La aparitia limbajului de programare Java, acest tip deaplicatie a reprezentat unul din factorii de impact prin noutatea si simplitateasolutiei oferite.
Applet-ul este o resursa program, depusa ıntr-o zona publica, accesibila prinInternet (server Web.) Un program de navigare preia codul applet-ului si ıl executa.Apelarea unui applet se face dintr-un fisier html.
Datorita acestui mod de folosire, applet-urile au o structura speciala si suntsupuse la reguli stricte de securitate, printre care acela de a nu putea scrie informatiipe calculatorul pe care se executa - calculatorul clientului.
Metoda actuala de apelare a unui applet se face prin intermediul unei resurseDeployment Toolkit(DT) - o biblioteca de functii javascript. Resursa DT este apela-bila la adresa http://java.com/js/deployJava.js iar codul se poate consulta lawww.java.com/js/deployJava.js.
DT utilizeaza protocolul Java Network Launching Protocol (jnlp) si evita prob-lemele de compatibilitate cu programul navigator. Aceasta resursa realizeaza descarcareaapplet-ului cat si lansarea ın executie. Pe calculatorul client, adica pe care ruleazaapplet-ul, trebuie sa fie instalat jre - Java Runtime Environment - versiunea pe 32biti.
Programarea unui applet se face prin extinderea clasei java.applet.Applet
sau javax.swing.JApplet. Clasa Applet extinde clasa java.awt.Panel iar clasaJApplet extinde clasa Applet.
Interfata grafica, ın cazul extinderii clasei Applet, va utiliza controlurile apartinandinterfetei de programare AWT (Abstract Window Toolkit), iar ın cazul extinderii cla-sei JApplet se vor utiliza controluri Swing.
9
10 CAPITOLUL 1. APPLET - MINIAPLICATIE JAVA
1.1 Clasa Applet
Structura unui applet este
import java.applet.*;
import java.awt.*;
public classNumeClasa extends Applet{public void init(){
Actiuni efectuate la instantierea clasei applet-ului.}public void start(){
Actiuni efectuate la lansarea applet-ului ın executie sau lareıntoarcerea ın pagina applet-ului.
}public void paint(Graphics g){
Actiuni efectuate ori de cate ori este necesara redesenareaferestrei applet-ului.
}public void stop(){
Actiuni efectuate la oprirea applet-ului, ca urmare aınchiderii ferestrei corespunzatoare applet-ului.
}public void destroy(){
Actiuni efectuate la distrugerea applet-ului, ce au loc candnavigatorul paraseste documentul html din care s-a apelatapplet-ul.
}}
Executarea applet-ului este controlat de programul navigator si revine la apelareametodelor init, start, stop. Acest fenomen se numeste inversarea controlului.
1.2 Desfasurarea unui applet
Prin desfasurarea (deployment) unei aplicatii se ıntelege realizarea structurilor decataloage si fisiere dar si a operatiilor care trebuie ıntreprinse ın vederea functionariiunei aplicatii distribuite.
Desfasurarea unui applet se poate face ın mai multe feluri:
Varianta 1
1. Arhivarea fisierelor class ale applet-ului.
1.2. DESFASURAREA UNUI APPLET 11
2. Editarea fisierului html de apelare a applet-ului. Sablonul specific apelariiapplet-ului este
<BODY>
. . .
<script src="http://java.com/js/deployJava.js"></script>
<script>
var attributes={ code:’numele_clasei_Applet’,
archive:’numele_arhivei_jar’,width:...,height:...};
var parameters={. . .};
var minimumVersion=’1.6’;
deployJava.runApplet(attributes, parameters, minimumVersion);
</script>
. . .
</BODY>
3. Cele doua fisiere se depun ıntr-un catalog al unui server Web, asigurand viz-ibilitatea aplicatiei ın Internet.
Verificarea aplicatiei se poate face, dintr-un program navigator, prin simplaapelare a fisierului html. In acest caz, calculatorul trebuie sa fie conectat lainternet.
Daca dispunem de deployJava.js atunci acest fisier se alatura celorlalte douaresurse, iar atributul src al elementului script va fi src="deployJava.js".
Exemplul 1.2.1 ”Hello ”+nume. Numele se transmite miniaplicatiei ca parametru.
Codul applet-ului este:
1 import java . awt . ∗ ;2 import java . app le t . ∗ ;
4 public class Inceput extends Applet{5 public void i n i t ( ){}
7 public void paint ( Graphics g ){8 St r ing name=getParameter ( ”nume” ) ;9 g . drawString ( ” He l lo ”+name+” ! ! ” , 50 , 60 ) ;
10 }11 }
Fisierul html de apelare (inceput.html)
1 <HTML>2 <HEAD>3 <TITLE> Hel lo </TITLE>4 </HEAD>5 <BODY>6 <script src=” http :// java . com/ j s / deployJava . j s ”></ script>7 <script>8 var a t t r i b u t e s = { code : ’ Inceput . c l a s s ’ , a r ch ive : ’ inceput . ja r ’ ,9 width : 300 , he ight : 3 0 0} ;
12 CAPITOLUL 1. APPLET - MINIAPLICATIE JAVA
10 var parameters={nume : ’XYZ’} ;11 var minimumVersion = ’ 1 . 6 . 0 ’ ;12 deployJava . runApplet ( a t t r i b u t e s , parameters , minimumVersion ) ;13 </ script>14 </BODY>15 </HTML>
Varianta 2
Pe aceasta cale se va edita un fisier de configurare cu extensia jnlp. Realizareaapplet-ului consta din:
1. Arhivarea fisierelor class ale applet-ului.
2. Editarea unui fisier de configurare jnlp. Structura acestui fisier este
<?xml version="1.0" encoding="UTF-8"?>
<jnlp spec="1.0+" codebase="http://host:port/cale_applet" href="">
<information>
<title>. . .</title>
<vendor>. . .</vendor>
</information>
<resources>
<!-- Application Resources -->
<j2se version="1.6+"
href="http://java.sun.com/products/autodl/j2se"
max-heap-size="128m" />
<jar href="numele_arhivei_jar" main="true" />
</resources>
<applet-desc
name="numele_simbolic_al_applet-ului"
main-class="clasa_principala_a_applet-ului"
width="latimea_ferestrei_applet-ului"
height="inaltimea_ferestrei_applet-ului">
</applet-desc>
</jnlp>
3. Editarea fisierului html de apelare a applet-ului. Sablonul specific apelariiapplet-ului este
<BODY>
. . .
<script src="http://java.com/js/deployJava.js"></script>
1.2. DESFASURAREA UNUI APPLET 13
<script>
var attributes={code:’numele_arhivei_jar’,width:...,height:...};
var parameters={jnlp_href: ’cmmdc.jnlp’};
var minimumVersion=’1.6’;
deployJava.runApplet(attributes, parameters, minimumVersion);
</script>
. . .
</BODY>
4. Cele trei fisiere (eventual patru cu deployJava.js) se depun ıntr-un catalog alunui server Web, asigurand vizibilitatea aplicatiei ın Internet.
Exemplul 1.2.2 Calculul celui mai mare divizor comun a doua naturale.
Introducerea datelor exterioare se face prin intermediul unei interfete grafice.Applet-ul extinzand clasa Applet are codul
1 import java . awt . ∗ ;2 import java . app le t . ∗ ;3 import java . awt . event . ∗ ;
5 public class VisualCmmdc extends Applet implements Act ionL i s t ene r {6 TextFie ld tm , tn , r e z ;
8 public void i n i t ( ){9 setBackground ( Color . ye l low ) ;
10 GridLayout g l=new GridLayout ( 3 , 2 , 3 0 , 2 0 ) ;11 setLayout ( g l ) ;12 Label lm=new Label ( ”Primul numar : ” ) ;13 add ( lm ) ;14 tm=new TextFie ld ( ”1” , 5 ) ;15 add (tm ) ;16 Label ln=new Label ( ”Al d o i l e a numar : ” ) ;17 add ( ln ) ;18 tn=new TextFie ld ( ”1” , 5 ) ;19 add ( tn ) ;20 Button compute=new Button ( ” Calcu leaza ” ) ;21 compute . addAct ionLis tener ( this ) ;22 add ( compute ) ;23 r e z=new TextFie ld ( ”1” , 5 ) ;24 r e z . s e t E d i t a b l e ( fa l se ) ;25 add ( r ez ) ;26 }
28 public void paint ( Graphics g ){29 St r ing sm=tm . getText ( ) ;30 long m=Long . parseLong (sm ) ;31 St r ing sn=tn . getText ( ) ;32 long n=Long . parseLong ( sn ) ;33 long c=cmmdc(m, n ) ;34 r e z . setText ( (new Long ( c ) ) . t oS t r i ng ( ) ) ;35 }
37 public void act ionPerformed ( ActionEvent ae ){38 r epa in t ( ) ;39 }
14 CAPITOLUL 1. APPLET - MINIAPLICATIE JAVA
41 long cmmdc( long m, long n ) { . . .}42 }
iar ın cazul extinderii clasei JApplet
1 import java . awt . ∗ ;2 import javax . swing . ∗ ;3 import java . awt . event . ∗ ;
5 public class VisualCmmdc extends JApplet implements Act ionL i s t ene r {6 JTextFie ld tm , tn , r e z ;
8 public void i n i t ( ){9 Container content = getContentPane ( ) ;
10 content . setBackground ( Color . ye l low ) ;11 setLayout (new GridLayout ( 3 , 2 , 3 0 , 2 0 ) ) ;12 JLabel lm=new JLabel ( ”Primul numar : ” ) ;13 content . add ( lm ) ;14 tm=new JTextFie ld ( ”1” , 5 ) ;15 content . add (tm ) ;16 JLabel ln=new JLabel ( ”Al d o i l e a numar : ” ) ;17 content . add ( ln ) ;18 tn=new JTextFie ld ( ”1” , 5 ) ;19 content . add ( tn ) ;20 JButton compute=new JButton ( ” Calcu leaza ” ) ;21 compute . addAct ionLis tener ( this ) ;22 content . add ( compute ) ;23 r e z=new JTextFie ld ( ”1” , 5 ) ;24 r e z . s e t E d i t a b l e ( fa l se ) ;25 content . add ( r ez ) ;26 s e t V i s i b l e ( true ) ;27 }
29 public void paint ( Graphics g ){30 St r ing sm=tm . getText ( ) ;31 long m=Long . parseLong (sm ) ;32 St r ing sn=tn . getText ( ) ;33 long n=Long . parseLong ( sn ) ;34 long c=cmmdc(m, n ) ;35 r e z . setText ( (new Long ( c ) ) . t oS t r i ng ( ) ) ;36 }
38 public void act ionPerformed ( ActionEvent ae ){39 r epa in t ( ) ;40 }
42 long cmmdc( long m, long n ) { . . .}43 }
Fisierul de configurare jnlp (cmmdc.jnlp) este
1 <?xml version=” 1 .0 ” encoding=”UTF−8”?>2 <j n l p spec=”1.0+” codebase=” ht tp : // l o c a l h o s t : 8 0 8 0 /cmmdc” h r e f=””>3 <i n fo rmat ion>4 < t i t l e>Visua l Cmmdc</ t i t l e>5 <vendor>Trans i l van ia Un ive r s i ty o f Brasov</ vendor>6 </ in fo rmat ion>7 <r e s o u r c e s>8 < !−− App l i ca t ion Resources −−>
1.2. DESFASURAREA UNUI APPLET 15
9 < j 2 s e version=”1.6+”10 h r e f=” ht t p : // java . sun . com/ products / autodl / j 2 s e ”11 max−heap−s i z e=”128m” />
13 < j a r h r e f=”cmmdc . j a r ” main=” true ” />14 </ r e s o u r c e s>15 <applet−desc16 name=”VisualCmmdc Applet ”17 main−c l a s s=”VisualCmmdc”18 width=”300”19 he ight=”300”>20 </ applet−desc>21 </ j n l p>
iar apelarea se face din (VisualCmmdc.html)
1 <html>2 <body bgco lo r=”#AAEEAA”>3 <c en te r>4 <h1> Cel mai mare d i v i z o r comun </h1>5 <s c r i p t s r c=” deployJava . j s ”></ s c r i p t>6 <s c r i p t>7 var a t t r i b u t e s = { code : ’cmmdc ’ , width:300 , he i gh t : 300 } ;8 var parameters = { j n l p h r e f : ’cmmdc . j n l p ’ } ;9 var minimumVersion = ’ 1 .6 ’ ;
10 deployJava . runApplet ( a t t r i b u t e s , parameters , minimumVersion ) ;11 </ s c r i p t>12 </ cente r>13 </body>14 </html>
sau cu descarcarea fisierului jnlp1
1 <HTML>2 <BODY BGCOLOR=”#AAEEAA”>3 <CENTER>4 <h1> Cel mai mare d i v i z o r comun </h1>5 <s c r i p t s r c=” h t t p : // java . com/ j s / deployJava . j s ”></ s c r i p t>6 <s c r i p t>7 deployJava . launch ( ’cmmdc . j n l p ’ ) ;8 </ s c r i p t>9 </CENTER>
10 </BODY>11 </HTML>
O alternativa (depasita) la modurile de apelare al applet-ului descrise anterioreste prin utilizarea elementului html <applet>.
Atributele obligatorii ale unui element applet sunt
• code
Valoarea atributului este numele clasei applet-ului.
• width
Valoarea atributului este latimea ferestrei atribuita de navigator applet-ului laafisarea documentului html.
1Functioneaza ın navigatoarele Mozilla Firefox, Microsoft Internet Explorer.
16 CAPITOLUL 1. APPLET - MINIAPLICATIE JAVA
• height
Valoarea atributului este ınaltimea ferestrei atribuita de navigator applet-uluila afisarea documentului html.
Atribute optionale sunt
• codebase
Valoarea atributului este adresa URL ( Universal Resource Locator) sau caleala fisierul cu clasa applet-ului. In lipsa acestui parametru, cautarea clasei areloc ın catalogul din care a fost ıncarcata sursa html.
• vspace
Valoarea atributului este lungimea, exprimata ın pixeli, care se lasa liberadeasupra si dedesuptul ferestrei miniaplicatiei.
• hspace
Valoarea parametrului este lungimea, exprimata ın pixeli, care se lasa liberala stanga si la dreapta ferestrei applet-ului.
In marcajul <applet> prin intermediul elementului <param> pot fi inclusi parametrice pot fi preluati de applet. Un parametru se defineste prin atributele:
• name
Valoarea atributului este numele variabilei recunoscuta ın applet.
• value
Valoarea atributului este valoarea receptionata de applet si este de tip String.Preluarea se realizeaza cu metoda
public String getParameter(String name)
Documentul html de apelare al applet-ului Inceput este:
1 <HTML>2 <HEAD>3 <TITLE> Hel lo </TITLE>4 </HEAD>5 <BODY>6 <CENTER>7 <APPLET8 code = ” Inceput . c l a s s ”9 width = ”500”
10 height = ”300” >11 </APPLET>12 </CENTER>13 </BODY>14 </HTML>
1.3. COMUNICARE JAVA - JAVASCRIPT INTR-UN APPLET 17
Daca fisierul class al applet-ului nu se afla ın acelasi catalog cu documentul htmlatunci localizarea clasei se face cu valoarea atributului codebase =
"file://host/calea catre catalogul clasei applet-ului"
Pentru testare, ın locul navigatorului se poate folosi programul appletviewer.exedin distributia jdk.
1.3 Comunicare Java - JavaScript ıntr-un applet
Dintr-un applet set apela functii JavaScript definite ın documentul html din carese apeleaza applet-ul.
Prin intermnediul unui obiect de tip netscape.javascript.JSObject, creatprinstatic JSObject getWindow(java.applet.Applet applet)se apeleaza metodacall(String numeFunctieJavaScript, java.lang.Object[] args).
Sablonul de utilizare este
import netscape.javascript.*;
public void init(){
. . .
JSObject window=JSObject.getWindow(null);
window.call("numeFunctieJavaScript",args);
. . .
}
Pachetul netscape.javascript se afla ın distributia jdk ın catalogul JAVA HOME\jre\lib\plugin.jar. Pentru compilare, variabila de sistem classpath trebuie sacontina aceasta referinta.
18 CAPITOLUL 1. APPLET - MINIAPLICATIE JAVA
Capitolul 2
Programare cu socluri Java
Limbajul de programare Java ofera facilitati de elaborare ale unor programe careutilizeaza si interactioneaza cu resurse din Internet si din World Wide Web.
In plus limbajul Java permite utilizarea URL-ului (Universal Resource Locator– adresa resurselor ın Internet), a soclurilor (socket) si a datagramelor.
2.1 Aplicatii client – server
O aplicatie client – server se compune din:
• componenta server - alcatuita din programe / clase ce asigura una sau maimulte functiuni (servicii), care pot fi apelate de catre clienti.
• componenta client - alcatuita din programe / clase care permit accesul la serversi apelarea serviciilor acestuia.
Serverul si clientul (clientii) ruleaza, de obicei, pe calculatoare distincte. Unserver trebuie sa satisfaca cererile mai multor clienti.
Durata de viata a unei aplicatii client – server este data de durata functionariiserverului. Aceasta durata poate fi alcatuita din intervale disjuncte de timp, ıntreacele intervale, din diverse motive, serverul este inactiv.
Intervalul de timp determinat de conectarea unui client la server si pana ladeconectare poarta numele de sesiune. In aceasta perioada, clientul poate invocamai multe servicii ale serverului. Un client poate initia mai multe sesiuni.
Un client trebuie sa-si regaseasca datele ın cadrul unei sesiuni, ıntre sesiuni, petoata durata de viata a aplicatiei. Astfel se pune problema retinerii / persistenteidatelor pentru fiecare client ın parte.
19
20 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA
Autentificare si autorizare
Uzual, pentru a folosi serviciul unui server, un client trebuie sa se ınregistreze,moment ın care i se stabilesc drepturile de care dispune la utilizarea serviciilor oferitede server.
La apelarea serverului, clientul este autentificat - adica i se recunoaste identitatea- si apoi i se asigura accesul la servicii ın limita drepturilor pe care le are.
2.2 Notiuni despre retele
Calculatoarele ce ruleaza ın Internet comunica ıntre ele folosind protocolul TCP(Transport Control Protocol) sau UDP (User Datagram Protocol).
Intr-un program Java se utilizeaza clasele pachetului java.net prin intermediulcarora se acceseaza nivelele deservite de protocoalele TCP sau UDP. In felul acestase pot realiza comunicatii independente de platforma de calcul. Pentru a alege careclasa Java sa fie utilizata trebuie cunoscuta diferenta dintre TCP si UDP.
TCP Cand doua aplicatii comunica ıntre ele se stabileste o conexiune prin in-termediul careia se schimba date. Folosind protocolul TCP, comunicatia garanteazaca datele trimise dintr-un capat ajung ın celalalt capat cu pastrarea ordinii ın careau fost trimise. Acest tip de comunicatie seamana cu o convorbire telefonica. TCPfurnizeaza un canal sigur de comunicatie ıntre aplicatii.
UDP Utilizarea protocolului UDP presupune trimiterea unor pachete de date –numite datagrame – de la o aplicatie la alta fara sa se asigure faptul ca datagrameleajung la destinatie si nici ordinea lor de sosire. Acest tip de comunicatie seamanacu trimiterea scrisorilor prin posta.
2.3 Soclu TCP
Conexiunile bazate pe protocolul HTTP (Hyper Text Transfer Protocol) reprezintaun mecanism de nivel ınalt pentru accesarea resurselor din Internet.
Aplicatii de tip client – server se pot realiza utilizand comunicatii de nivel scazut.Pentru a comunica utilizand TCP programul client si programul server stabilesc oconexiune sigura. Fiecare program se leaga la conexiune printr-un soclu (socket).Un soclu este capatul unei cai de comunicatie bidirectional ıntre doua programece ruleaza ın retea. Un soclu este legat de un port – prin care nivelul TCP poateidentifica aplicatia careia ıi sunt transmise datele. Din punct de vedere fizic, un porteste o adresa de memorie cuprinsa ıntre 0 si 65535.
Pentru a comunica atat clientul cat si serverul citesc date de la si scriu date lasoclul legat la conexiunea dintre ele.
2.3. SOCLU TCP 21
In pachetul java.net clasele Socket si ServerSocket implementeaza un socludin partea clientului si respectiv din partea serverului.
Clientul cunoaste numele calculatorului pe care ruleaza serverul cat si portul lacare acesta este conectat. Pentru stabilirea conexiunii, clientul ıncearca un rendez-vous cu serverul de pe masina serverului si la portul serverului. Daca totul de-curge bine, serverul accepta conexiunea. Dupa acceptare, serverul creaza pentruclient un nou soclu legat la un alt port ın asa fel ıncat ascultarea cererilor la soclulinitial sa poata continua ın timp ce sunt satisfacute cererile clientului conectat. Dinpartea clientului, dupa acceptarea conexiunii soclul este creat si este utilizat pentrucomunicatia cu serverul.
2.3.1 Clasa java.net.Socket
Resursele clasei Socket sunt destinate clientului.
Constructori
• public Socket(String host, int port) throws UnknownHostException,
IOException
Creaza un soclu conectat la calculatorul cu portul specificat.
• public Socket(InetAddress host, int port) throws IOException
Creaza un soclu conectat la calculatorul cu portul specificat.
Metode
• public InputStream getInputStream() throws IOException
Returneaza un flux de intrare atasat soclului, pentru citirea (preluarea) informatiilorde la soclu.
• public OutputStream getOutputStream() throws IOException
Returneaza un flux de iesire atasat soclului, pentru scrierea (transmiterea)informatiilor la soclu.
• public synchronized void close() throws IOException
ınchide soclul de referinta.
2.3.2 Clasa java.net.ServerSocket
Resursele clasei ServerSocket sunt destinate serverului.
Constructori
22 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA
• public ServerSocket(int port) throws IOException
Creaza un soclu la portul specificat. Daca port=0, atunci va fi utilizat oriceport disponibil. Capacitatea sirului (tamponului) de asteptare pentru cererilede conectare se fizeaza la valoarea implicita 50. Cererile ın exces vor fi refuzate.
• public ServerSocket(int port, int lung) throws IOException
In plus fixeaza lungimea sirului (tamponului) de asteptare.
• public ServerSocket(int port, int lung, InetAddress adr)throws IOException
Se specifica ın plus calculatorul de la care se asteapta cereri. Daca adr=null,
atunci se accepta cereri de la orice calculator.
Metode
• public Socket accept() throws IOException
Metoda blocheaza procesul (firul de executie) apelant pana la sosirea uneicereri de conectare si creaza un soclu client prin care se va desfasura comuni-carea cu solicitantul acceptat.
• public synchronized void close() throws IOException
ınchide soclul de referinta.
2.4 Aplicatie client – server cu socluri
Serverul trebuie sa satisfaca simultan solicitarile mai multor clienti. Fiecareclient apeleaza programul server la acelasi port si ın consecinta cererile de conectaresunt receptionate de acelasi ServerSocket. Serverul receptioneaza apelurile secvential.La un apel, se creaza de partea severului un soclu prin care se va face schimbul dedate cu clientul. Cererile clientilor pot fi satisface concurent/paralel, utilizand firede executie ce implementeaza serviciul oferit sau secvential - ın cazul unor serviciide durata scurta.
Exemplul 2.4.1 Sistem client - server pentru calculul celui mai mare divizor comuna doua numere naturale. Portul obiectului de tip ServerSocket este 7999.
Programul client CmmdcClient se conecteaza la server, transmite serveruluicele doua numere naturale si receptioneaza rezultatul pe care apoi ıl afiseaza.
In esenta orice program client trebuie sa execute:
1. Deschide/creaza un soclu.
2.4. APLICATIE CLIENT – SERVER CU SOCLURI 23
2. Deschide/creaza fluxuri de date pentru comunicatia cu serverul.
3. Transmite si receptioneaza date potrivit specificului aplicatiei (protocoluluiserverului). Acest pas variaza de la un program client la altul.
4. Inchiderea fluxurilor de date.
5. Inchiderea soclului.
1 import java . i o . ∗ ;2 import java . net . ∗ ;3 import java . u t i l . Scanner ;
5 public class CmmdcClient {6 public stat ic void main ( St r ing [ ] a rgs ) throws IOException {7 St r ing host=” l o c a l h o s t ” ;8 int port =7999;9 i f ( args . length >0)
10 host=args [ 0 ] ;11 i f ( args . length >1)12 port=I n t e g e r . pa r s e In t ( args [ 1 ] ) ;13 Socket cmmdcSocket = null ;14 DataInputStream in=null ;15 DataOutputStream out=null ;
17 try {18 cmmdcSocket = new Socket ( host , port ) ;19 out=new DataOutputStream ( cmmdcSocket . getOutputStream ( ) ) ;20 in=new DataInputStream ( cmmdcSocket . getInputStream ( ) ) ;21 }22 catch ( Exception e ) {23 System . e r r . p r i n t l n ( ” Connection Error : ”+e . getMessage ( ) ) ;24 System . e x i t ( 1 ) ;25 }
27 Scanner scanner=new Scanner ( System . in ) ;28 long m, n , r ;29 System . out . p r i n t l n ( ”m=” ) ;30 m=scanner . nextLong ( ) ;31 System . out . p r i n t l n ( ”n=” ) ;32 n=scanner . nextLong ( ) ;
34 try{35 out . writeLong (m) ;36 out . writeLong (n ) ;37 r=in . readLong ( ) ;38 System . out . p r i n t l n ( ”Cmmdc : ”+r ) ;39 }40 catch ( IOException e ){41 System . e r r . p r i n t l n ( ”Comunication e r r o r ”+e . getMessage ( ) ) ;42 }
44 out . c l o s e ( ) ;45 in . c l o s e ( ) ;46 cmmdcSocket . c l o s e ( ) ;47 }48 }
24 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA
Se presupune ca programul server ruleaza pe calculatorul local si utilizeaza portul7999. Daca acesti parametri se modifica - de exemplu serverul ruleaza ın retea pecalculatorul atlantis la portul 8200 - atunci la apelare transmitem acesti parametriprin java CmmdcClient atlantis 8200
Partea server este alcatuita din mai multe clase:
• Clasa MyMServer, independenta de un serviciu anume, preia apelurile clientilorsi lanseaza satisfacerea cererii.
1 import java . net . ∗ ;2 import java . i o . ∗ ;
4 public class MyMServer {5 public stat ic void main ( St r ing [ ] a rgs ) throws IOException {6 int port =7999;7 boolean l i s t e n i n g=true ;8 ServerSocket s e rve rSocke t = null ;9 try {
10 s e rve rSocke t = new ServerSocket ( port ) ;11 }12 catch ( IOException e ) {13 System . e r r . p r i n t l n ( ”Could not l i s t e n on port : ”+port ) ;14 System . out . p r i n t l n ( e . getMessage ( ) ) ;15 System . e x i t ( 1 ) ;16 }
18 while ( l i s t e n i n g )19 // var ian ta 120 new AppThread ( s e rve rSocke t . accept ( ) ) . s t a r t ( ) ;21 // var ian ta 222 /∗23 {24 Socket socke t=serverSocke t . accept ( ) ;25 t r y {26 DataOutputStream out=27 new DataOutputStream ( socke t . getOutputStream ( ) ) ;28 DataInputStream in=29 new DataInputStream ( socke t . getInputStream ( ) ) ;30 l ong m=0,n=0,r ;31 App app=new App ( ) ;32 m=in . readLong ( ) ;33 n=in . readLong ( ) ;34 r=app .cmmdc(m, n ) ;35 out . writeLong ( r ) ;36 out . c l o s e ( ) ;37 in . c l o s e ( ) ;38 socke t . c l o s e ( ) ;39 }40 catch ( IOException e ){41 System . err . p r i n t l n (” Server comunication error : ”+42 e . getMessage ( ) ) ;43 }44 }45 ∗/46 s e rve rSocke t . c l o s e ( ) ;47 }48 }
2.4. APLICATIE CLIENT – SERVER CU SOCLURI 25
In ciclul while, la receptia unei solicitari de conexiune se creaza si se lanseazaun fir de executie a carei metoda run contine actiunile ce raspund solicitarii.
O solutie mai eficienta este utilizarea unui bazin de fire de executie:
static final int NTHREADS=100;
static ExecutorService exec=Executors.newFixedThreadPool(NTHREADS);
. . .
while(listening){
AppThread obj=new AppThread(serverSocket.accept());
exec.execute(obj);
}
. . .
• Clasa AppTread - fir de executie responsabil de preluarea datelor si de trans-mitere a rezultatului.
1 import java . net . ∗ ;2 import java . i o . ∗ ;
4 public class AppThread extends Thread{5 Socket socke t=null ;
7 public AppThread ( Socket socke t ){8 this . s ocke t=socket ;9 }
11 public void run ( ){12 try{13 DataOutputStream out=new DataOutputStream ( socke t . getOutputStream ( ) ) ;14 DataInputStream in=new DataInputStream ( socke t . getInputStream ( ) ) ;15 long m=0,n=0, r ;16 App app=new App ( ) ;17 m=in . readLong ( ) ;18 n=in . readLong ( ) ;19 r=app . cmmdc(m, n ) ;20 out . writeLong ( r ) ;21 out . c l o s e ( ) ;22 in . c l o s e ( ) ;23 socke t . c l o s e ( ) ;24 }25 catch ( IOException e ){26 System . e r r . p r i n t l n ( ” Server comunication e r r o r : ”+e . getMessage ( ) ) ;27 }28 }29 }
• Clasa App corespunzatoare calcului celui mai mare divizor comul a doua nu-mere naturale.
1 public class App{2 public long cmmdc( long m, long n ) { . . .}3 }
26 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA
Rularea programelor. Se porneste la ınceput programul server MyMServer
iar apoi clientul CmmdcClient. Clientul se poate rula de pe orice calculator alretelei. Daca programul client se executa pe alt calculator decat cel pe care ruleazaprogramul server, atunci la apelarea clientului trebuie precizat numele calculatoruluiserver si eventual portul utilizat.
2.5 Datagrame
Pentru utilizarea datagramelor pachetul java.net pune la dispozitie clasele
• DatagramSocket
• DatagramPacket
• MulticastSocket
O aplicatie trimite si receptioneaza pachete DatagramPacket prin intermediulunui DatagramSocket. Un pachet DatagramPacket poate fi trimis la mai multidestinatari prin intermediul unui MulticastSocket.
Reamintim ca o datagrama este un mesaj trimis prin retea a carei sosire nu estegarantata iar momentul de sosire este neprecizat.
2.5.1 Clasa java.net.DatagramPacket.
Trimiterea unui pachet UDP necesita crearea unui obiectDatagramPachet care contine corpul mesajului si adresa destinatiei. Apoi acestobiect DatagramPacket poate fi pus ın retea ın vederea trimiterii sale. Primirea unuipachet UDP necesita crearea unui obiect DatagramPacket si apoi acceptarea unuipachet UDP din retea. Dupa primire, se poate extrage din obiectul DatagramPacketadresa sursa si continutul mesajului.
Constructori
Exista doi constructori pentru datagrame UDP. Primul constructor este folositpentru primirea de pachete si necesita doar furnizarea unei memorii tampon, iarcelalalt este folosit pentru trimiterea de pachete si necesita specificarea adresei des-tinatarului.
• DatagramPacket(byte[ ] buffer,int lung)
Acest contructor este folosit pentru primirea pachetelor. Un pachet se memo-reaza ın tamponul buffer avand lung octeti. Daca lungimea pachetului depasesteaceasta lungime, atunci pachetul este trunchiat iar octetii ın plus se pierd.
• DatagramPacket(byte[ ] buffer,int lung ,InetAddress adresa ,int port)
2.5. DATAGRAME 27
Acest constructor este folosit pentru crearea unui pachet ın vederea expedierii.Corpul pachetului este continut ın tamponul buffer avand lung octeti. Pa-chetul va fi trimis catre adresa si portul specificat. Trebuie sa existe un serverUDP care asculta la portul specificat pentru trimiterea pachetelor. Un serverUDP poate coexista cu un server TCP care asculta acelasi port.
Metode
• InetAddress getAddress()
returneaza adresa IP a pachetului.
• int getPort()
returneaza portul.
• byte[] getData()
returneaza continutul pachetului.
• int getLength()
returneaza lungimea pachetului.
• void setAddress(InetAddress adresa)
fixeaza adresa IP a pachetului.
• void setPort(int port)
fixeaza portul.
• void setData(byte[] buffer)
fixeaza continutul pachetului.
• void setLength(int lung)
fixeaza lungimea pachetului.
2.5.2 Clasa java.net.DatagramSocket
Aceasta clasa se foloseste atat pentru trimiterea, cat si pentru primirea obiectelorDatagramPacket. Un obiect DatagramSocket asculta la un port cuprins ıntre 1si 65535 (porturile cuprinse ıntre 1 si 1023 sunt rezervate pentru aplicatiile sis-tem). Deoarece UDP nu este orientat pe conexiune, se va crea un singur obiectDatagramSocket pentru trimiterea pachetelor catre diferite destinatii si primireapachetelor de la diferite surse.
Constructori
28 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA
• DatagramSocket() throws SocketException
Creaza un obiect DatagramSocket cu un numar de port aleator;
• DatagramSocket(int port) throws SocketException
Creaza un obiect DatagramSocket cu numarul de port specificat;
• DatagramSocket(int port, InetAddress adresa) throws SocketException
Creaza un obiect DatagramSocket cu numarul de port specificat la adresaspecificata;
MetodeClasa DatagramSocket contine metode pentru trimiterea si primirea de obiecte
DatagramPacket, ınchiderea soclului, determinarea informatiilor adresei locale sisetarea timpului de primire.
• void send(DatagramPacket pachet) throws IOException
Trimite pachetul prin retea. Daca se trimit pachete la o destinatie necunoscutasau care nu asculta, ın cele din urma se genereaza o exceptie IOException.
• void receive(DatagramPacket pachet) throws IOException
Metoda primeste un singur pachet UDP ın obiectul pachet specificat. Apoi,pachetul poate fi inspectat pentru determinarea adresei IP sursa, portul sursasi lungimea mesajului. Executia metodei este blocata pana cand se primestecu succes un pachet sau se scurge timpul de asteptare.
• InetAddress getLocalAddress()
Returneaza adresa locala catre care este legat acest DatagramSocket;
• int getLocalPort()
Returneaza numarul de port unde asculta DatagramSocket.
• void close()
Inchide DatagramSocket.
• void setSoTimeout(int timpDeAsteptere) throws SocketException
Metoda fixeaza timpul de asteptare (ın milisecunde) a soclului. Metoda receive()se va bloca pentru timpul de asteptare specificat pentru primirea unui pachetUDP, dupa care va arunca o exceptie Interrupted Exception. Daca valoareaparametrului este 0, atunci soclul este blocat.
• int getSoTimeout() throws SocketException
Returneaza timpul de asteptare.
2.5. DATAGRAME 29
• void setSendBufferSize(int lungime) throws SocketException
Fixeaza lungimea tamponului de trimitere a soclului la valoarea specificata.Nu poate fi trimis mesaj UDP de lungime mai mare de aceasta valoare.
• int getSendBufferSize() throws SocketException
Returneaza lungimea tamponului de trimitere a soclului.
• void setReceiveBufferSize(int lungime) throws SocketException
Fixeaza lungimea tamponului de primire a soclului la valoarea specificata. Nupoate fi primit un mesaj UDP de lungime mai mare de aceasta valoare.
• int getReceiveBufferSize() throws SocketException
Returneaza lungimea tamponului de primire a soclului.
• void connect(InetAddress adresa, int port) throws SocketException
Conecteaza soclul la adresa si portul specificat. Aceasta metoda nu este cerutapentru operatiile uzuale UDP.
• void disconnect()
Deconecteaza soclul conectat.
• InetAddress getInetAddress()
Returneaza obiectul InetAddress catre care este conectat soclul sau null dacaacesta nu este conectat.
• int getPort()
Returneaza portul la care este conectat soclul sau -1 daca acesta nu este conec-tat.
2.5.3 Clasa java.net.InetAddress
Datele pot fi trimise prin retea indicand adresa IP corespunzatoare masiniidestinatie. Clasa InetAddress furnizeaza acces la adresele IP.
Nu exista constructori pentru aceasta clasa. Instantele trebuie create folosindmetodele statice:
• InetAddress getLocalHost() throws UnknownHostException
Returneaza un obiect InetAddress corespunzator masinii locale.
• InetAddress getByName(String host) throws UnknownHostException
Returneaza un obiect InetAddress corespunzator masinii host, parametrucare poate fi specificat prin nume (de exemplu ”atlantis”) sau prin adresaIP (”168.192.0.1”).
30 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA
• InetAddress [ ]getAllByName(String host)throws UnknownHostException
Returneaza un sir de obiecte InetAddress corespunzator fiecarei adrese IP amasinii host.
Metodele clasei InetAddress
• byte [ ] getAddress()
Returneaza sirul de octeti corespunzator obiectului InetAddress de referinta.
• String getHostName()
Returneaza numele masinii gazda.
• String getHostAddress()
Returneaza adresa IP a masinii gazda.
• boolean isMulticastAddress()
Returneaza true daca obiectul InetAddress reprezinta o adresa IP multicast(primul octet cuprins ıntre 224 si 239).
Exemplul urmator afiseaza numele si adresa calculatorului gazda cat si acela alcalculatoarelor ale caror nume este transmis programului ca parametru.
Exemplul 2.5.1
1 import java . net . ∗ ;
3 public class AdreseIP{4 public stat ic void main ( St r ing arg [ ] ) {5 InetAddress adresa=null ;6 try{7 adresa=InetAddress . getLocalHost ( ) ;8 System . out . p r i n t l n ( ” C a l c u l a t o r u l gazda are : ” ) ;9 System . out . p r i n t l n ( ”numele : ”+adresa . getHostName ( ) ) ;
10 System . out . p r i n t l n ( ” adresa IP : ”+adresa . getHostAddress ( ) ) ;11 }12 catch ( UnknownHostException e ){13 System . out . p r i n t l n ( ”UnknownHostException : ”+e . getMessage ( ) ) ;14 }15 i f ( arg . length >0){16 for ( int i =0; i<arg . l ength ; i ++){17 try{18 adresa=InetAddress . getByName( arg [ i ] ) ;19 System . out . p r i n t l n ( ” C a l c u l a t o r u l ”+arg [ i ]+” are : ” ) ;20 System . out . p r i n t l n ( ” adresa IP \”getByName\” : ”+adresa ) ;21 byte [ ] b=adresa . getAddress ( ) ;22 for ( int j =0; j<b . l ength ; j++)23 i f (b [ j ]<0)24 System . out . p r i n t (256+b [ j ]+” . ” ) ;
2.5. DATAGRAME 31
25 else26 System . out . p r i n t (b [ j ]+” . ” ) ;27 System . out . p r i n t l n ( ) ;28 }29 catch ( UnknownHostException e ){30 System . out . p r i n t l n ( ”UnknownHostException : ”+31 e . getMessage ( ) ) ;32 }33 }34 }35 }36 }
2.5.4 Aplicatii client – server cu datagrame.
Un pachet de tip DatagramPacket este alcatuit dintr-un sir de octeti. Este da-toria programatorului sa transforme datele (mesajul) ın siruri de octeti la expedieresi la receptie.
Transformarea unui obiect serializabil ıntr-un sir de octeti si invers se poaterealiza cu schema
Object Object
ObjectOutputStream ObjectInputStream
ByteArrayOutputStream ByteArrayInputStream
output - DatagramPacket input - DatagramPacket
? 6
? 6
? 6
? 6
Fie socket un obiect de tip DatagramSocket prin intermediul caruia se executaexpedierea / receptionarea pachetelor de tip DatagramPacket.
In principiu expedierea si transformarea obiectului obj ıntr-un sir de octeti sepoate realiza cu secventa de cod
ByteArrayOutputStream baos=new ByteArrayOutputStream(256);
ObjectOutputStream out=new ObjectOutputStream(baos);
out.writeObject(obj);
byte[] bout=baos.toByteArray();
DatagramPacket packet=new DatagramPacket(bout,bout.length,
address,port);
socket.send(packet);
unde address si port sunt adresa si portul utilizat de expeditorul mesajului. Dacapacket este un obiect DatagramPacket receptionat atunci metodele getAddress()
si getPort() furnizeaza adresa si portul expeditoruluiReceptionarea si transformarea inversa este
32 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA
byte[] bin=new byte[256];
packet=new DatagramPacket(bin,bin.length);
socket.receive(packet);
ByteArrayInputStream bais=new ByteArrayInputStream(bin);
ObjectInputStream in=new ObjectInputStream(bais);
obj=in.readObject();
Daca mesajul este un obiect String atunci el se transforma ıntr-un sir de octeticu metoda byte[] String.getByte() si invers, el se obtine prin new String(bin)
sau new String(packet.getData()).
Exemplul 2.5.2 Programam serviciul calculului celui mai mare divizor comun adoua numere.
In vederea transportului definim clasa
1 import java . i o . ∗ ;
3 public class Protoco l implements S e r i a l i z a b l e {4 long x , y ;5 Protoco l ( long x , long y ){6 this . x=x ;7 this . y=y ;8 }9 }
Clientul va trimite un obiect Protocol, care va contine datele problemei si vareceptiona un obiect de acelasi tip cu rezultatul (cel mai mare divizor comun) ınprimul camp al obiectului.
Programul client este
1 import java . net . ∗ ;2 import java . i o . ∗ ;3 import java . u t i l . Scanner ;
5 public class ClientCmmdc{6 public stat ic void main ( St r ing [ ] a rgs ){
8 St r ing hos tServe r=” l o c a l h o s t ” ;9 int por tSe rve r =7999;
10 i f ( args . length >0)11 hos tServe r=args [ 0 ] ;12 i f ( args . length >1)13 por tSe rve r=I n t e g e r . pa r s e In t ( args [ 1 ] ) ;14 try{15 // Crearea unui soc lu Datagramsocket16 DatagramSocket socke t=new DatagramSocket ( ) ;
18 // Formarea mesaju lu i19 Protoco l p=new Protoco l ( 0 , 0 ) ;
2.5. DATAGRAME 33
20 Scanner scanner=new Scanner ( System . in ) ;21 System . out . p r i n t l n ( ” I n t r o d u c e t i primul numar : ” ) ;22 p . x=scanner . nextLong ( ) ;23 System . out . p r i n t l n ( ” I n t r o d u c e t i a l d o i l e a numar : ” ) ;24 p . y=scanner . nextLong ( ) ;
26 // Transformarea mesa ju lu i in t r−un s i r de o c t e t i
28 ByteArrayOutputStream baos=new ByteArrayOutputStream ( 2 5 6 ) ;29 ObjectOutputStream out=new ObjectOutputStream ( baos ) ;30 out . wr i teObject (p ) ;31 byte [ ] bout=baos . toByteArray ( ) ;
33 // Expedierea mesaju lu i
35 InetAddress address=InetAddress . getByName( hos tServe r ) ;36 DatagramPacket packet=new37 DatagramPacket ( bout , bout . length , address , por tServe r ) ;38 socke t . send ( packet ) ;
40 // Asteptarea raspunsu lu i
42 byte [ ] bin=new byte [ 2 5 6 ] ;43 packet=new DatagramPacket ( bin , bin . l ength ) ;44 socke t . r e c e i v e ( packet ) ;
46 // Pre lucrarea raspunsu lu i
48 ByteArrayInputStream ba i s=new ByteArrayInputStream ( bin ) ;49 ObjectInputStream in=new ObjectInputStream ( ba i s ) ;50 p=(Protoco l ) in . readObject ( ) ;51 System . out . p r i n t l n ( ”Cmmdc = ”+p . x ) ;
53 socke t . c l o s e ( ) ;54 }55 catch ( Exception e ){56 System . out . p r i n t l n ( e . getMessage ( ) ) ;57 }58 }59 }
Programul server este
1 import java . net . ∗ ;2 import java . i o . ∗ ;
4 public class ServerCmmdc{5 public stat ic void main ( St r ing [ ] a rgs ){
7 DatagramSocket socke t=null ;8 int s e rve rPor t =7999;9 try{
10 // Crearea unui soc lu DatagramSocket
12 socke t=new DatagramSocket ( s e rve rPor t ) ;
14 }15 catch ( Exception e ){16 System . out . p r i n t l n ( ”DatagramSocket−e r ror−”+e . getMessage ( ) ) ;
34 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA
17 System . e x i t ( 0 ) ;18 }
20 // Ac t i v i t a t e a s e r v e r u l u i
22 boolean l i s t e n i n g=true ;23 DatagramPacket packet=null ;24 App app=new App ( ) ;25 Protoco l p=null ;
27 while ( l i s t e n i n g ){28 try{
30 // Receptionarea unui mesaj
32 byte [ ] bin=new byte [ 2 5 6 ] ;33 packet=new DatagramPacket ( bin , bin . l ength ) ;34 socke t . r e c e i v e ( packet ) ;
36 // Pre lucrarea da t e l o r
38 ByteArrayInputStream ba i s=new ByteArrayInputStream ( bin ) ;39 ObjectInputStream in=new ObjectInputStream ( ba i s ) ;40 p=(Protoco l ) in . readObject ( ) ;
42 // Rezolvarea c e r e r i i c l i e n t u l u i
44 p . x=app . cmmdc(p . x , p . y ) ;45 p . y=0;
47 // Transformarea mesa ju lu i de raspuns in t r−un s i r de o c t e t i
49 ByteArrayOutputStream baos=new ByteArrayOutputStream ( 2 5 6 ) ;50 ObjectOutputStream out=new ObjectOutputStream ( baos ) ;51 out . wr i teObject (p ) ;52 byte [ ] bout=baos . toByteArray ( ) ;
54 // Expedierea mesaju lu i ne c e s i t a cunoasterea e x p e d i t o r u l u i
56 InetAddress address=packet . getAddress ( ) ;57 int port=packet . getPort ( ) ;58 packet=new DatagramPacket ( bout , bout . length , address , port ) ;59 socke t . send ( packet ) ;60 }61 catch ( Exception e ){62 System . out . p r i n t l n ( e . getMessage ( ) ) ;63 }64 }65 socke t . c l o s e ( ) ;66 }67 }
Clasa App este cea utilizata la exemplul cu socluri TCP.
2.5. DATAGRAME 35
2.5.5 Clasa java.net.MulticastSocket
Multicast vs. Broadcast
Prin intermediul unui soclu de tip MulticastSocket se pot receptiona datagrameexpediate de un server catre toti clientii cu un asemenea soclu.
Constructori
• MulticastSocket(int port) throws SocketException
Metode
• void joinGroup(InetAddress adresa) throws SocketException
Soclul se ”conecteaza” la grupul definit de adresa IP (de tip D, adica cuprinsıntre 224.0.0.0 si 239.255.255.255).
• void leaveGroup(InetAddress adresa) throws SocketException
Soclul se ”deconecteaza” la grupul definit de adresa IP.
• void close()
Pregatirea clientului ın vederea receptionarii datagramelor printr-un soclu de tipMulticastSocket consta din
MulticastSocket socket= new MulticastSocket(port);
InetAddress adresa=InetAddress.getByName("230.0.0.1");
socket.joinGroup(adresa);
In final, clientul se deconecteaza si ınchide soclul.
socket.leaveGroup(adresa);
socket.close();
Pachetele trimise de programul server trebuie sa se adreseze grupului, identificatprin adresa IP de tip D.
Astfel prin multicast serverul trimite pachete la o adresa de grup si la un portfixat. Pachetele emise de server sunt receptionate de orice client ce creaza un soclu detip MulticastSocket pentru portul la care emite serverul si care se alatura grupului.
Prin broadcast serverul emite datagrame catre orice calculator al retelei localela un anumit port. Faptul ca emiterea datagramelor este de tip broadcast se indicaprin
DatagramSocket.setBroadcast(true)
Orice client care ısi creaza un soclu la portul la care emite serverul receptioneazadatagramele trimise de server. Adresa utilizata de server la crearea datagramelortrebuie sa identifice reteaua.
Observatie. In cazul unui calculator ”izolat” este nevoie de instalarea driveruluiMicrosoft Loopback Adapter, care simuleaza existenta unei placi de retea active.
36 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA
Exemplul 2.5.3 Multicast si Broadcast: programele server emit din cinci ıncinci secunde ora exacta. Un client va receptiona cate cinci datagrame.
Codurile sunt date ın Fig. 2.1 si Fig. 2.2, respectiv pentru partea de server sicea de client.
2.6 Canale de comunicatie
Odata cu versiunea j2sdk1.4 apar clase noi pentru operatii de intrare - iesire ınpachetele java.nio si java.nio.channels. Pachetul java.nio.channels contineclase pentru comunicatia ın retea, si anume canalele de comunicatie.
Informatia transportata printr-un canal de comunicatie trebuie ınglobata ınobiecte container de tip Buffer.
2.6.1 Clasa java.nio.Buffer
Ierarhia claselor Buffer
abstract Buffer
ByteBuffer
ShortBuffer
IntBuffer
LongBuffer
FloatBuffer
DoubleBuffer
CharBuffer
Un obiect de tip typeBuffer este un tampon (container) care contine date detipul specificat de denumirea clasei.
Un obiect de tip Buffer este caracterizat de
• capacitate (capacity) numarul elementelor care pot fi ınmagazitate ın tampon;
• limita (limit) marginea superiora a indicelui;
• indice (position) valoarea curenta a indicelui, ce corespunde unui cursor ceindica ınceputul zonei unde se introduc sau de unde se extrag date din tampon.
Metode generale
• clear() permite unui obiect de tip Buffer sa fie reıncarcat. Fixeaza limita =capacitate si indice = 0.
• flip() pregateste obiectul de tip Buffer pentru consultare (citire). Fixeazalimita =numarul elementelor din tampon si indice = 0.
• rewind() pregateste obiectul de tip Buffer pentru re-citire.
2.6. CANALE DE COMUNICATIE 37
MulticastServer BroadcastServer
import java.io.*; import java.io.*;
import java.net.*; import java.net.*;
import java.util.*; import java.util.*;
import java.text.DateFormat; import java.text.DateFormat;
public class MulticastServer{ public class BroadcastServer{
public static void main(String[] args){ public static void main(String[] args){
long FIVE_SECONDS = 5000; long FIVE_SECONDS = 5000;
boolean sfarsit=false; boolean sfarsit=false;
DatagramSocket socket = null; DatagramSocket socket = null;
int serverPort=7000; int serverPort=7000;
int clientPort=7001; int clientPort=7001;
byte[] buf = new byte[256]; byte[] buf = new byte[256];
Date data=null; Date data = null;
DatagramPacket packet = null; DatagramPacket packet = null;
try{ try{
socket=new DatagramSocket(serverPort); socket=new DatagramSocket(serverPort);
} }
catch(SocketException e){ catch(SocketException e){
System.out.println(e.getMessage()); System.out.println(e.getMessage());
} }
while (! sfarsit){ while (! sfarsit) {
try{ try{
data=new Date(); data=new Date();
String df=DateFormat. String df=DateFormat.
getTimeInstance().format(data); getTimeInstance().format(data);
buf = df.getBytes(); buf = df.getBytes();
// send it
InetAddress group = InetAddress group =
InetAddress.getByName("230.0.0.1"); InetAddress.getByName("192.168.0.255");
packet=new DatagramPacket(buf, packet=new DatagramPacket(buf,
buf.length,group,clientPort); buf.length,group,clientPort);
socket.setBroadcast(true);
socket.send(packet); socket.send(packet);
// sleep for a while
Thread.sleep(FIVE_SECONDS); Thread.sleep(FIVE_SECONDS);
} }
catch (Exception e) { catch (Exception e) {
System.out.println(e.getMessage()); System.out.println(e.getMessage());
} }
} }
socket.close(); socket.close();
} }
} }
Table 2.1: Clasele server.
38 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA
MulticastClient BroadcastClient
import java.io.*; import java.io.*;
import java.net.*; import java.net.*;
public class MulticastClient { public class BroadcastClient {
public static void main(String[] args) public static void main(String[] args)
throws IOException { throws IOException {
DatagramPacket packet; DatagramPacket packet;
byte[] buf = new byte[256]; byte[] buf = new byte[256];
int clientPort=7001; int clientPort=7001;
MulticastSocket socket= DatagramSocket socket=
new MulticastSocket(clientPort); new DatagramSocket(clientPort);
InetAddress address=
InetAddress.getByName("230.0.0.1");
socket.joinGroup(address);
int i=-1; int i=-1;
do{ do{
i++; i++;
packet=new DatagramPacket(buf, buf.length); packet=new DatagramPacket(buf, buf.length);
socket.receive(packet); socket.receive(packet);
String received=new String(packet.getData()); String received=new String(packet.getData());
System.out.println("Am primit: "+received); System.out.println("Am primit: "+received);
} }
while(i<5); while(i<5);
socket.leaveGroup(address);
socket.close(); socket.close();
} }
} }
Table 2.2: Clasele client.
2.6. CANALE DE COMUNICATIE 39
2.6.2 Clasa java.nio.ByteBuffer
Instantierea unui obiect se obtine prin metoda statica
static ByteBuffer allocate(capacitate)
Introducerea si extragerea datelor din tampon se poate face ın mod
• relativ - implica modificarea indicelui tamponului;
• absolut - fara modificarea indicelui.
MetodeIntroducerea datelor ın mod relativ:
• ByteBuffer put(byte b)
• ByteBuffer putTip(tip x)
Extragerea datelor ın mod relativ:
• byte get()
• tip getTip()
Introducerea datelor ın mod absolut:
• ByteBuffer put(int index,byte b)
• ByteBuffer putTip(int index,tip x)
Extragerea datelor ın mod absolut:
• byte get(int index)
• tip getTip(int index)
unde tip poate fi char, short, int, long, float, double.
Alte metode
• public final boolean hasRemaining()
Daca indicele nu este egal cu limita atunci returneaza true, semnaland existentaın tampon a unor octeti.
• static ByteBuffer wrap(byte[] array)
• public static ByteBuffer wrap(byte[] array,int offset,int length)
Converteste sirul de octeti ıntr-un obiect Bytebuffer.
40 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA
• public final byte[] array()
Transformarea inversa, obiectul ByteBuffer este convertit ıntr-un sir de 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();
2.6.3 Clasa java.net.InetSocketAddress
Clasa InetSocketAddress extinde clasa SocketAddress si ıncapsuleaza adresaunui calculator din Internet ımpreuna cu un port ın vederea legarii la un ServerSocket.
Constructori:
• InetSocketAddress(InetAddress addr,int port)
• InetSocketAddress(String numeCalculator,int port)
• InetSocketAddress(int port)
2.6.4 Clasa java.nio.channels.ServerSocketChannel
Crearea unui obiect de tip ServerSocketChannel se realizeaza prin
static ServerSocketChannel open() throws IOException
Unui asemenea obiect i se asociaza un ServerSocket prin metoda
ServerSocket socket() throws IOException.
Obiectul de tip ServerSocket trebuie leagat la un port de comunicatie prin metoda
void bind(InetSocketAddress endpoint) throws IOException.
Sablonul de utilizare este
try{
ServerSocketChannel ssc=ServerSocketChannel.open();
ServerSocket ss=ssc.socket();
InetSocketAddress isa=new InetSocketAddress(addr,port);
ss.bind(isa);
}
catch(Exception e){. . .}
La apelul unui client, serverul trebuie sa genereze un obiect de tip Socket
Channel prin care se vor derula comunicatiile cu clientul. Acest canal de comunicatiese obtine cu metoda accept().
2.6. CANALE DE COMUNICATIE 41
2.6.5 Clasa java.nio.channels.SocketChannel
Crearea unui obiect de tip SocketChannel se realizeaza prin
static SocketChannel open() throws IOException
Acest obiect trebuie conectat la obiectul ServerSocketChannel al serverului cumetoda connect(InetSocketAddress addr).
Datele vehiculate printr-un SocketChannel sunt de tip ByteBuffer. Datele setransmit prin metoda
int write(ByteBuffer sursa)
si se receptioneaza prin metoda
int read(ByteBuffer destinatie)
Valoarea returnata de cele doua metode reprezinta numarul octetilor trimisi /receptionati.
Doar octetii unui obiect de tip ByteBuffer cuprinsi ıntre indice si limita sunttransmisi prin canal. Astfel, dupa ıncarcarea unui obiectului ByteBuffer cu metoderelative trebuie apelata metoda flip().
Canalul se ınchide cu metoda close().
Exemplul 2.6.1 Calculul celui mai mare divizor comun a doua numere naturale.
Aplicatie client-server bazat pe canale de comunicatie prin socluri are programulserver
1 import java . i o . ∗ ;2 import java . net . ∗ ;3 import java . n io . ∗ ;4 import java . n io . channe l s . ∗ ;5 import java . u t i l . ∗ ;
7 public class SocketChannelCmmdcServer {
9 private stat ic void s e r v i c i u ( ServerSocketChannel s s c ){10 SocketChannel sc = null ;11 try {12 sc=s s c . accept ( ) ;13 ByteBuf fer bb = ByteBuffer . a l l o c a t e ( 1 6 ) ;14 // LongBuffer l b = bb . asLongBuffer ( ) ;15 sc . read (bb ) ;16 // Varianta 117 long m=bb . getLong ( 0 ) ;18 long n=bb . getLong ( 8 ) ;19 // Varianta 220 // long m=l b . ge t ( 0 ) ;21 // long n=l b . g e t ( 1 ) ;22 App app=new App ( ) ;23 long r=app . cmmdc(m, n ) ;24 bb . c l e a r ( ) ;
42 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA
25 // Varianta 126 bb . putLong (0 , r ) ;27 // Varianta 228 // l b . put ( r ) ;29 sc . wr i t e (bb ) ;30 sc . c l o s e ( ) ;31 }32 catch ( Exception e ){33 System . out . p r i n t l n ( ” Server e r r o r : ”+e . getMessage ( ) ) ;34 }35 }
37 public stat ic void main ( St r ing [ ] a rgs ){38 int port =7999;39 ServerSocketChannel s s c=null ;40 try{41 s s c = ServerSocketChannel . open ( ) ;42 InetSocketAddress i s a=new InetSocketAddress ( port ) ;43 ServerSocket s s=s s c . socket ( ) ;44 s s . bind ( i s a ) ;45 }46 catch ( IOException e ){47 System . out . p r i n t l n ( ” ServerSocketChannelError : ”+e . getMessage ( ) ) ;48 System . e x i t ( 0 ) ;49 }50 System . out . p r i n t l n ( ” Server ready . . . ” ) ;51 while ( true ){52 s e r v i c i u ( s s c ) ;53 }54 }55 }
si clientul
1 import java . i o . ∗ ;2 import java . net . ∗ ;3 import java . n io . ∗ ;4 import java . n io . channe l s . ∗ ;5 import java . u t i l . Scanner ;
7 public class SocketChannelCmmdcClient {8 public stat ic void main ( St r ing [ ] a rgs ) {9 St r ing host=” l o c a l h o s t ” ;
10 int port =7999;11 i f ( args . length >0)12 host=args [ 0 ] ;13 i f ( args . length >1)14 port=I n t e g e r . pa r s e In t ( args [ 1 ] ) ;15 SocketChannel sc=null ;16 try{17 InetSocketAddress i s a=new InetSocketAddress ( host , port ) ;18 sc=SocketChannel . open ( ) ;19 sc . connect ( i s a ) ;20 }21 catch ( UnknownHostException e ) {22 System . e r r . p r i n t l n ( ” Server necunoscut : ”+host+” ”+e . getMessage ( ) ) ;23 System . e x i t ( 1 ) ;24 }25 catch ( IOException e ) {26 System . e r r . p r i n t l n ( ” Conectare i m p o s i b i l a l a : ”+
2.6. CANALE DE COMUNICATIE 43
27 host+” pe por tu l ”+port+” ”+e . getMessage ( ) ) ;28 System . e x i t ( 1 ) ;29 }30 Scanner scanner=new Scanner ( System . in ) ;31 long m, n , r ;32 System . out . p r i n t l n ( ”m=” ) ;33 m=scanner . nextLong ( ) ;34 System . out . p r i n t l n ( ”n=” ) ;35 n=scanner . nextLong ( ) ;
37 ByteBuffer bb=ByteBuffer . a l l o c a t e ( 1 6 ) ;38 // Varianta 139 bb . putLong (0 ,m) . putLong (8 , n ) ;40 // Varianta 241 // LongBuffer l b=bb . asLongBuffer ( ) ;42 // l b . put (0 ,m) . put (1 ,n ) ;43 try{44 sc . wr i t e (bb ) ;45 bb . c l e a r ( ) ;46 sc . read (bb ) ;47 // Varianta 148 r=bb . getLong ( 0 ) ;49 // Varianta 250 // r=l b . g e t ( 0 ) ;51 System . out . p r i n t l n ( ”Cmmdc : ”+r ) ;52 sc . c l o s e ( ) ;53 }54 catch ( Exception e ){55 System . e r r . p r i n t l n ( ” Eroare de comunicat ie ”+e . getMessage ( ) ) ;56 }57 }58 }
Varianta comentata corespunde cazului ın care se utilizeara clasa acoperitoare LongBuffer.
2.6.6 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. Daca port=0 atunci se alegealeator un port disponibil.
Transmiterea unui obiect ByteBuffer se face cu metoda
44 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA
public int send(ByteBuffer src, SocketAddress target) throws
IOException
Metoda returneaza numarul de octeti expediati. Receptia unui ByteBuffer se obtinecu metoda
public SocketAddress receive(ByteBuffer dst) throws IOException
Obiectul returnat reprezinta adresa expeditorului.
Exemplul 2.6.2 Calculul celui mai mare divizor comun a doua numere naturale.
1 import java . i o . ∗ ;2 import java . net . ∗ ;3 import java . n io . ∗ ;4 import java . n io . channe l s . ∗ ;5 import java . u t i l . ∗ ;
7 public class DatagramChannelCmmdcServer {8 public stat ic void main ( St r ing [ ] a rgs ){9 int port =7999;
10 DatagramChannel dc=null ;11 InetSocketAddress i s a=new InetSocketAddress ( port ) ;12 try{13 dc=DatagramChannel . open ( ) ;14 }15 catch ( IOException e ){16 System . out . p r i n t l n ( e . getMessage ( ) ) ;17 }18 DatagramSocket datagramSocket=dc . socke t ( ) ;19 try{20 datagramSocket . bind ( i s a ) ;21 }22 catch ( SocketExcept ion e ){23 System . out . p r i n t l n ( e . getMessage ( ) ) ;24 }25 System . out . p r i n t l n ( ” Server ready . . . ” ) ;26 boolean l i s t e n i n g=true ;
28 while ( l i s t e n i n g ){29 try{30 ByteBuffer bb=ByteBuffer . a l l o c a t e ( 1 6 ) ;31 // LongBuffer l b=bb . asLongBuffer ( ) ;32 SocketAddress c l i e n t=dc . r e c e i v e (bb ) ;33 // Varianta 134 long m=bb . getLong ( 0 ) ;35 long n=bb . getLong ( 8 ) ;36 // Varianta 237 // long m=l b . ge t ( 0 ) ;38 // long n=l b . g e t ( 1 ) ;39 App app=new App ( ) ;40 long r=app . cmmdc(m, n ) ;41 bb . c l e a r ( ) ;42 // Varianta 143 bb . putLong (0 , r ) ;44 // Varianta 2
2.6. CANALE DE COMUNICATIE 45
45 // l b . put (0 , r ) ;46 dc . send (bb , c l i e n t ) ;47 }48 catch ( Exception e ){49 System . out . p r i n t l n ( ” Eroare s e r v e r : ”+e . getMessage ( ) ) ;50 System . e x i t ( 1 ) ;51 }52 }53 }54 }
1 import java . i o . ∗ ;2 import java . net . ∗ ;3 import java . n io . ∗ ;4 import java . n io . channe l s . ∗ ;5 import java . u t i l . Scanner ;
7 public class DatagramChannelCmmdcClient {8 public stat ic void main ( St r ing [ ] a rgs ) throws IOException {9 St r ing se rverHost=” l o c a l h o s t ” ;
10 int port =7999;11 i f ( args . length >0)12 se rverHost=args [ 0 ] ;13 i f ( args . length >1)14 port=I n t e g e r . pa r s e In t ( args [ 1 ] ) ;15 InetSocketAddress s e r v e r=null , i s a=null ;16 try{17 s e r v e r=new InetSocketAddress ( InetAddress . getByName( se rverHost ) , port ) ;18 }19 catch ( UnknownHostException e ){20 System . out . p r i n t l n ( ”Unknown host : ”+e . getMessage ( ) ) ;21 System . e x i t ( 1 ) ;22 }23 i s a=new InetSocketAddress ( 0 ) ;24 DatagramChannel dc=null ;25 try {26 dc=DatagramChannel . open ( ) ;27 DatagramSocket socke t = dc . socket ( ) ;28 socke t . bind ( i s a ) ;29 }30 catch ( IOException e ) {31 System . e r r . p r i n t l n ( ”Couldn ’ t open the DatagramChannel ”+ e . getMessage ( ) ) ;32 System . e x i t ( 1 ) ;33 }34 long m, n , r ;35 Scanner scanner=new Scanner ( System . in ) ;36 System . out . p r i n t l n ( ”m=” ) ;37 m=scanner . nextLong ( ) ;38 System . out . p r i n t l n ( ”n=” ) ;39 n=scanner . nextLong ( ) ;40 ByteBuffer bb=ByteBuffer . a l l o c a t e ( 1 6 ) ;41 // Varianta 142 bb . putLong (0 ,m) . putLong (8 , n ) ;43 // Varianta 244 // LongBuffer l b=bb . asLongBuffer ( ) ;45 // l b . put (0 ,m) . put (1 ,n ) ;46 try{47 dc . send (bb , s e r v e r ) ;48 bb . c l e a r ( ) ;
46 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA
49 dc . r e c e i v e (bb ) ;50 // Varianta 151 r=bb . getLong ( 0 ) ;52 // Varianta 253 // r=l b . g e t ( 0 ) ;54 System . out . p r i n t l n ( ”Cmmdc = ”+r ) ;55 }56 catch ( Exception e ){57 System . e r r . p r i n t l n ( ” C l i en t e r r o r : ”+e . getMessage ( ) ) ;58 }59 f ina l ly {60 i f ( dc !=null ) dc . d i s connec t ( ) ;61 }62 }63 }
2.7 Conexiuni HTTP
Clasa java.net.URL permite realizarea unei conexiuni cu un server Web1 potrivitprotocolului HTTP (Hyper Text Transport Protocol) si accesarea fisierelor - uzualhtml - din zona publica.
Constructori
• URL(String spec) throws MalformedURLException
Creaza un obiect URL legat de resursa specificata de spec, care trebuie sa fie oreferinta URL valida.
Metode
• InputStream openStream() throws IOException
Returneaza fluxul de intrare pentru citirea resursei.
Exemplul 2.7.1 Pe baza referintei catre un fisier html dintr-un catalog vizibil alunui server Web, sa se afiseze continutul fisierului.
In codul reprodus mai jos, fisierul Hello.html se afla pe un server apache-tomcat,ın catalogul webapps\myservlet.
1 import java . net . ∗ ;2 import java . i o . ∗ ;
4 public class ReadHTTP{5 public stat ic void main ( St r ing [ ] a rgs ){6 try{7 St r ing adr=” http :// l o c a l h o s t :8080/ myserv let / He l lo . html” ;8 //System . se tProper ty (” h t t p . proxyHost ” , ”10 .3 . 5 . 133”) ;9 //System . se tProper ty (” h t t p . proxyPort ” ,”3128”);
1apache-tomcat, apache, Micrsoft IIS (Internet Information Services), etc.
2.7. CONEXIUNI HTTP 47
10 URL u r l=new URL( adr ) ;11 InputStream in=u r l . openStream ( ) ;12 InputStreamReader i s r=new InputStreamReader ( in ) ;13 BufferedReader br=new BufferedReader ( i s r ) ;14 St r ing s ;15 do{16 s=br . readLine ( ) ;17 i f ( s !=null )18 System . out . p r i n t l n ( s ) ;19 }20 while ( s !=null ) ;21 br . c l o s e ( ) ;22 i s r . c l o s e ( ) ;23 in . c l o s e ( ) ;24 }25 catch ( Exception e ){26 System . out . p r i n t l n ( e . getMessage ( ) ) ;27 }28 }29 }
48 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA
Capitolul 3
Regasirea obiectelor prinservicii de nume
Oricarui obiect ıi sunt asociate un nume si o referinta. Regasirea / cautareaobiectului se face pornind de la numele obiectului, prin referinta se ajunge la obiect.
Exemple date prin sablonul (Nume ⇒ Referinta ⇒ Obiect)
1. Accesul la o carte ıntr-o biblioteca:
Titlul cartii ⇒ Referinta cartii din biblioteca ⇒ Carte
2. Contactul telefonic cu o persoana:
Nume persoana ⇒ Numar telefon ⇒ Persoana
Un serviciu de nume contine asocieri dintre nume de obiecte si obiecte si poateoferi facilitati de regasire a obiectelor.
3.1 Java Naming and Directory Interface
Java Naming and Directory Interface - JNDI este o interfata de programare (Ap-plication Programming Interface - API ) care descrie functionalitatea unui serviciude nume.
Cuvantul servici este utilizat ın sens comun, entitate care pune la dispozitiefacilitati de folosire.
Alaturi de interfata JNDI, arhitectura JNDI mai contine interfata Service ProviderInterface - SPI. Implementarea interfetei SPI de un furnizor de servicii JNDI are caefect independenta programului Java de furnizorul de servicii JNDI.
JNDI este implementat de serviciile de nume:
• Filesystem are ca obiect asocierea dintre numele de fisier sau catalog cu obiec-tul corespunzator.
49
50 CAPITOLUL 3. REGASIREA OBIECTELOR PRIN SERVICII DE NUME
• DNS - Domain Name System are ca obiect asocierea dintre adresa Internet cuadresa IP.
• RMI registry utilizat ın aplicatii RMI, din Java. Are ca obiect asocierea ıntreun nume de serviciu de invocare ale obiectelor la distanta cu un delegat alserviciului (stub).
• COS - Common Object Service Naming utilizat ın aplicatii CORBA. Are caobiect asocierea ıntre numele unui serviciu de invocare ale obiectelor la distantacu referinta la serviciu.
• LDAP - Lightweight Directory Access Protocol defineste un protocol pentruaccesarea datelor retinute ıntr-un catalog LDAP (LDAP directory, informa-tion directory). Un catalog LDAP permite retinerea si regasirea referintelorobiectelor definite pe un calculator.
Interfata javax.naming.Context
Printr-un context se va ıntelege o multime de asocieri nume - obiect. Core-spunzator unui context, JNDI defineste interfata Context, cu metodele
• void bind(String nume,Object object)
• void rebind(String nume,Object object)
• void unbind(String nume)
• Object lookup(String nume)
• NamingEnumeration list(String nume)
Returneaza lista cu nume obiectelor ımpreuna cu tipul lor.
• NamingEnumeration listBindings(String nume)
Returneaza lista cu nume obiectelor ımpreuna cu tipul si locatia acestora.
Specificatiile JNDI prevad definirea unui context initial, implementat prin clasajavax.naming.InitialContext, clasa ce implementeaza interfata Context.
Constructori.
• public InitialContext() throws NamingException
• public void InitialContext(Hashtable<?,?> environment)throwsNamingException
3.1. JAVA NAMING AND DIRECTORY INTERFACE 51
Pentru crearea contextului initial trebuie specificata clasa care creaza contextulinitial prin parametrul java.naming.factory.initial sau constantaContect.INITIAL CONTEXT FACTORY.
Acest parametru se poate da ın mai multe moduri:
• Includerea ın obiectul Hashtable care apare ın constructorul clasei InitalContext.
Hashtable env=new Hashtable()
env.put("java.naming.factory.initial",...);
Context ctx=InitialContext(env);
sau
Hashtable env=new Hashtable()
env.put(Context.INITIAL_CONTEXT_FACTORY,...);
Context ctx=new InitialContext(env);
• Ca parametru de sistem furnizat la lansarea programului Java, prin
java -Djava.naming.factory.initial=... ClasaJava
Parametrul se poate da ın interiorul programului prin
System.setProperty("java.naming.factory.initial",...);
sau
System.setProperty(Context.INITIAL_CONTEXT_FACTORY,...);
• Atribut ın fisierul de proprietati jndi.properties.
In aceste ultime doua cazuri, contextul initial se creaza prin
Context ctx=new InitialContext();
Functie de serviciul de nume, clasa care creaza contextul initial este dat ın tabelul
Serviciul de nume Clasa
Filesystem com.sun.jndi.fscontect.RefFSContextFactory
COS com.sun.jndi.cosnaming.CNCtxFactory
RMI com.sun.jndi.rmi.registry.RegistryContextFactory
DNS com.sun.jndi.dns.DnsContextFactory
LDAP com.sun.jndi.ldap.LdapCtxFactory
52 CAPITOLUL 3. REGASIREA OBIECTELOR PRIN SERVICII DE NUME
Exemplul 3.1.1 Utilizand serviciul JNDI Filesystem se creaza un context prin in-termediul careia se afiseaza continutul unui catalog indicat de client.
1 import javax . naming . ∗ ;2 import java . i o . F i l e ;3 import java . u t i l . Hashtable ;4 import java . u t i l . Scanner ;
6 class Lookup{7 public stat ic void main ( St r ing [ ] a rgs ) {8 Context ctx=null ;9 /∗
10 // Varianta 111 Hashtab le env = new Hashtab le (11 ) ;12 env . put ( Context .INITIAL CONTEXT FACTORY,13 ”com. sun . jnd i . f s c on t e x t . RefFSContextFactory ” ) ;14 t r y {15 c t x = new In i t i a lCon t e x t ( env ) ;16 }17 catch (NamingException e ) {18 System . out . p r i n t l n (” In i t i a lCon t e x tEr ro r : ”+e . getMessage ( ) ) ;19 }20 ∗/21 /∗22 // Varianta 223 System . se tProper ty (” java . naming . f a c t o r y . i n i t i a l ” ,24 ”com. sun . jnd i . f s c on t e x t . RefFSContextFactory ” ) ;25 t r y {26 c t x = new In i t i a lCon t e x t ( ) ;27 }28 catch (NamingException e ) {29 System . out . p r i n t l n (” In i t i a lCon t e x tEr ro r : ”+e . getMessage ( ) ) ;30 }31 ∗/
33 // Varianta 334 try{35 ctx = new I n i t i a l C o n t e x t ( ) ;36 }37 catch ( NamingException e ) {38 System . out . p r i n t l n ( ” I n i t i a l C o n t e x t E r r o r : ”+e . getMessage ( ) ) ;39 }
41 Scanner scanner=new Scanner ( System . in ) ;42 System . out . p r i n t l n ( ” I n t r o d u c e t i r e f e r i n t a abso luta a unui ca ta l og : ” ) ;43 St r ing myName=scanner . next ( ) ;44 try{45 System . out . p r i n t l n ( ”\n ctx . lookup ( ”+myName+” ) produce ” ) ;46 System . out . p r i n t l n ( ctx . lookup (myName ) ) ;
48 System . out . p r i n t l n ( ”\nContinutul c a t a l o g u l u i ”+myName+” e s t e :\n” ) ;49 NamingEnumeration l s t=ctx . l i s t (myName) ;50 while ( l s t . hasMore ( ) ){51 NameClassPair nc = ( NameClassPair ) l s t . next ( ) ;52 System . out . p r i n t l n ( nc ) ;53 }
55 System . out . p r i n t l n ( ”\nContinutul c a t a l o g u l u i ”+myName+” e s t e :\n” ) ;
3.1. JAVA NAMING AND DIRECTORY INTERFACE 53
56 NamingEnumeration l s t 1 = ctx . l i s t B i n d i n g s (myName) ;57 while ( l s t 1 . hasMore ( ) ) {58 Binding bd = ( Binding ) l s t 1 . next ( ) ;59 System . out . p r i n t l n (bd ) ;60 }61 ctx . c l o s e ( ) ;62 }63 catch ( NamingException e ) {64 System . out . p r i n t l n ( ”Lookup f a i l e d : ” + e . getMessage ( ) ) ;65 }66 }67 }
Apelarea clasei, ın varianta data, consta din
java -Djava.naming.factory.initial=com.sun.jndi.fscontext.RefFSContextFactory Lookup
sau
java Lookup
caz, ın care, ın catalogul curent se gaseste fisierul jndi.properties cu continutul
java.naming.factory.initial=com.sun.jndi.fscontext.RefFSContextFactory
Serviciul de nume Filesystem este dat de fisierele: fscontext.jar siproviderutil.jar.
3.1.1 LDAP
LDAP poate fi privit ca un sistem de gestiune a unei baze de date (ne relational).Baza de date este alcatuita din atribute ale caror nume este precizat de protocolulLDAP.
Punctele de intrare (radacinile) sunt date de DN (Distinguished Name). UzualDN se defineste printr-una din variantele
1. o=”organization”,c=”country”
2. o=”organization”
3. dc=”domain content 1”,c=”domain content 2”
De exemplu, dc=”example”,dc=”com”
Un utilizator este caracterizat prin atributul cn - common name si are acces laLDAP prin precizarea simultana a atributelor DN si cn.
Vom utiliza produsul OpenDS (Directory Service), ce implementeaza protocolulLDAP.
Instalarea consta din:
1. dezarhivarea distributiei;
54 CAPITOLUL 3. REGASIREA OBIECTELOR PRIN SERVICII DE NUME
2. se completeaza sursa fisierului OpenDS-*\setup.bat cuset OPENDS JAVA HOME=... ca prima linie;
3. se executa OpenDS-*\setup.bat. Prin intermediul unei interfete grafice sefixeaza
• o parola pentru cn=Directory Manager. Fie 1q2w3e aceasta parola.
• un punct de intrare, fie acesta DN: dc=example,dc=com.
Implicit, serverul OpenDS utilizeaza portul 389.Operatiile de configurare se fac utilizand interfata grafica a componentei OpenDS
Directory Server Control Panel, lansat prin
set OPENDS_JAVA_HOME=. . .
set OpenDS_HOME=. . .\OpenDS-*
%OpenDS_HOME%\bat\control-panel.bat
Declararea unui utilizator se face prin Manage Entries → Entries → New User,urmat de completarea datelor cerute.
Schimbarea parolei unui utilizator se face tot din Manage Entries urmat de clic-dreapta pe DN si Reset User Password.
Prin aceasta componenta se poate porni si opri serverul OpenDS, ambele operatiiputand fi executate si apeland start-ds, stop-ds din catalogulOpenDS HOME\bat.
Exemplul 3.1.2 Program pentru ınregistrarea si stergerea referintei unui obiect detip Cmmdc.
Prin intermediul OpenDS Directory Server Control Panel se creaza se creazao intrare/utilizator care va fi legat de un obiect Cmmdc. Presupunem ca aceastaintrare este cn=info.
1 import java . u t i l . Hashtable ;2 import java . u t i l . Scanner ;3 import javax . naming . Context ;4 import javax . naming . NamingException ;5 import javax . naming . d i r e c t o r y . DirContext ;6 import javax . naming . d i r e c t o r y . I n i t i a l D i r C o n t e x t ;
8 public class LDAPServerCmmdc {9 public stat ic void main ( St r ing [ ] a rgs ) {
10 Hashtable env = new Hashtable ( ) ;11 env . put ( Context . INITIAL CONTEXT FACTORY,12 ”com . sun . j n d i . ldap . LdapCtxFactory” ) ;13 env . put ( Context .PROVIDER URL,14 ” ldap :// l o c a l h o s t :389/ cn=in fo , dc=example , dc=com” ) ;15 env . put ( Context .SECURITY PRINCIPAL, ”cn=Direc tory Manager” ) ;16 env . put ( Context .SECURITY CREDENTIALS, ”1q2w3e” ) ; // paro la17 DirContext ctx = null ;
19 Scanner scanner=new Scanner ( System . in ) ;
3.1. JAVA NAMING AND DIRECTORY INTERFACE 55
20 System . out . p r i n t l n ( ” A l e g e t i ope ra t i a : 1− bind ; 2− unbind” ) ;21 int oper=scanner . next Int ( ) ;22 System . out . p r i n t l n ( ” I n t r o d u c e t i va loa rea a t r i b u t u l u i \”cn\”” +23 ” a o b i e c t u l u i Cmmdc” ) ;24 System . out . p r i n t l n ( ”cn=” ) ;25 St r ing cmmdcObj=scanner . next ( ) . tr im ( ) ;
27 try {28 ctx = new I n i t i a l D i r C o n t e x t ( env ) ;29 ctx . unbind ( ”cn=”+cmmdcObj ) ;30 i f ( oper==1){31 Cmmdc obj=new Cmmdc( ) ;32 St r ing s t r=”cn=”+cmmdcObj ;33 ctx . bind ( s t r , obj ) ;34 }35 ctx . c l o s e ( ) ;36 }37 catch ( NamingException e ) {38 System . out . p r i n t l n ( ”LDAPserverCmmdc : ”+e . getMessage ( ) ) ;39 }40 }41 }
Codul clasei Cmmdc este
1 public class Cmmdc implements java . i o . S e r i a l i z a b l e {2 public long cmmdc( long a , long b) {3 while (b != 0) {4 long r = a % b ;5 a = b ;6 b = r ;7 }8 return a ;9 }
10 }
Exemplul 3.1.3 Utilizarea unui obiect de tip Cmmdc regasit pe baza referintei dinserverul LDAP.
1 import java . u t i l . Hashtable ;2 import javax . naming . Context ;3 import javax . naming . NamingException ;4 import javax . naming . d i r e c t o r y . DirContext ;5 import javax . naming . d i r e c t o r y . I n i t i a l D i r C o n t e x t ;6 import java . u t i l . Scanner ;
8 public class LDAPClientCmmdc {9 public stat ic void main ( St r ing [ ] a rgs ) {
10 Hashtable env = new Hashtable ( ) ;11 env . put ( Context . INITIAL CONTEXT FACTORY,12 ”com . sun . j n d i . ldap . LdapCtxFactory” ) ;13 env . put ( Context .PROVIDER URL,14 ” ldap :// l o c a l h o s t :389/ cn=in fo , dc=example , dc=com” ) ;15 env . put ( Context .SECURITY PRINCIPAL, ”cn=Direc tory Manager” ) ;16 env . put ( Context .SECURITY CREDENTIALS, ”1q2w3e” ) ;17 DirContext ctx = null ;18 try {
56 CAPITOLUL 3. REGASIREA OBIECTELOR PRIN SERVICII DE NUME
19 ctx=new I n i t i a l D i r C o n t e x t ( env ) ;20 i f ( ctx != null ) {21 Scanner scanner=new Scanner ( System . in ) ;22 System . out . p r i n t l n ( ” I n t r o d u c e t i va loa rea a t r i b u t u l u i \”cn\”” +23 ” a o b i e c t u l u i Cmmdc” ) ;24 System . out . p r i n t l n ( ”cn=” ) ;25 St r ing cmmdcObj=scanner . next ( ) . tr im ( ) ;26 Object ob j e c t = ctx . lookup ( ”cn=”+cmmdcObj ) ;27 System . out . p r i n t l n ( ”Primul numar” ) ;28 long a=scanner . next Int ( ) ;29 System . out . p r i n t l n ( ”Al d o i l e a numar” ) ;30 long b=scanner . next Int ( ) ;31 Cmmdc obj=(Cmmdc) ob j e c t ;32 System . out . p r i n t l n ( ” Rezu l ta tu l cmmdc e s t e : ”+obj . cmmdc( a , b ) ) ;33 }34 }35 catch ( NamingException e ) {36 System . out . p r i n t l n ( ”LDAPClientCmmdc : ”+e . getMessage ( ) ) ;37 }38 }39 }
Capitolul 4
Invocarea procedurilor ladistanta
Invocarea procedurilor la distanta (Remote Procedure Call – RPC ) ınseamnaapelarea unei metode a unui obiect aflat pe un alt calculator ca si cum acesta s-arafla pe calculatorul local.
Se vor prezenta doua cazuri:
• Invocarea procedurilor la distanta ın cazul mediului omogen Java. Denumireatehnologiei ın acest caz este Invocarea metodelor la distanta – Remote MethodInvocation (RMI). Prin mediu omogen se ıntelege faptul ca atat compontentaserver cat si componenta client sunt programate ın acelasi limbaj de progra-mare, Java ın cazul de fata.
• Invocarea procedurilor la distanta ın cazul medii neomogene. Solutia ın acestcaz este dat de Common Object Request Broker Arhitecture (CORBA).
4.1 Remote Method Invocation
Regasirea obiectelor la distanta. Ideea gasirii unui obiect la distanta este caserverul ınscrie un reprezentant al sau – numit stub (ciot) – ıntr-un obiect registry -registru. Acest obiect se creaza cu programul rmiregistry.exe din distributia javasi se lanseaza ın executie prin
start rmiregistry [port ]
unde valoarea implicita a portului este 1099. Comanda start apartine sistemuluide operare. rmiregistry este un serviciu de nume JNDI.
Un client obtine din registry stub-ul serverului, prin intermediul caruia realizeazacomunicatia cu programul server.
57
58 CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANTA
Cand un obiect al clientului apeleaza o metoda a unui obiect aflat la distanta,se va face, de fapt, un apel de metoda a unui obiect care reprezinta serverul. Acestaeste stub-ul, aflat pe aceasi masina cu clientul.
Rolul acestui obiect este sa ımpacheteze (marshalling) parametrii de apel aimetodei ıntr-un mesaj ce va fi transferat prin retea. Impachetarea se face ıntr-omaniera independenta de calculator, mai precis sirurile de caractere si obiecte sunttransmise ıntr-un format care nu se bazeaza pe referinte. Pentru obiecte se utilizeazaserializarea obiectelor Java.
Serializarea datelor reprezinta transformarea acestora din tipuri de date diferiteıntr-un sir de octeti care va fi transportat prin retea fara interpretare, dar carepastreaza informatiile despre structura initiala a datelor.
Deserializarea este procesul invers de refacere a structurilor trimise prin retea.
Mesajul asamblat este transmis catre server, care stie sa desfaca mesajul receptionatinvocand ın mod corespunzator metoda referita de client.
Atunci cand clientul face apel la o metoda aflata pe o alta masina, este invo-cat stub-ul client, care ıncepe conversatia cu serverul. Acest lucru este complettransparent utilizatorului, care are impresia ca invoca o metoda locala.
Metodele apelate la distanta trebuie declarate ca apartinand unei interfete ceextinde interfata java.rmi.Remote. Fiecare asemenea metoda trebuie sa arunce oexceptie java.rmi.RemoteException. Obiectele care circula prin retea trebuie saimplementeze interfata java.io.Serializable.
Structura unei aplicatii RMI. O aplicatie RMI este alcatuita din trei com-ponente:
1. O interfata la distanta (remote) ın care se declara serviciile puse la dispozitiede server;
2. Aplicatia server care poate implementa serviciile interfetei la distanta si ınscrieın registry stub-ul corespunzator;
3. Aplicatia client ce apeleaza unul sau mai multe servicii ale serverului.
Nici o clipa nu trebuie scapat din vedere faptul ca cele trei componente evolueazape calculatoare diferite.
Registrul rmiregistry implementeaza interfata java.rmi.registry.Registry1.Metodele oferite sunt:
• void bind(String numeServiciu, Remote obj)throwsRemoteException, AlreadyBoundException, AccessException
Inregistreaza ın registry obiectul obj ce implementeaza interfata Remote subnumele numeServiciu.
1Varianta directa, fara a folosi facilitatile JNDI pentru rmiregistry.
4.1. REMOTE METHOD INVOCATION 59
• void rebind(String numeServiciu, Remote obj)throwsRemoteException, AccessException
Reınregistreaza ın registry obiectul obj ce implementeaza interfata Remote subnumele numeServiciu.
Aceasta metoda poate fi apelata doar daca programul care face ınregistrarease afla pe aceasi masina ca registrul registry.
• String[] list()throws RemoteException, AccessException
Returneaza o lista a tuturor serviciilor ınregistrate ın registry.
• Remote lookup(String numeServiciu)throwsRemoteException, NotBoundException, AccessException
Returneaza stub-ul serviciului ınregistrat sub numele numeServiciu.
• void unbind(String numeServiciu)throwsRemoteException, NotBoundException, AccessException
Sterge din registru serviciul.
Localizarea registrului se obtine utilizand metoda statica getRegistry a claseijava.rmi.registry.LocateRegistry.
• public static Registry getRegistry() throws RemoteException
• public static Registry getRegistry(String host)throws RemoteException
• public static Registry getRegistry(int port)throws RemoteException
• public static Registry getRegistry(String host,int port)throws RemoteException
Metoda public static Registry createRegistry(int port)throws RemoteException creaza un registru la portul specificat pe calculatorullocal.
Ansamblul (host,port) determina ın mod univoc o aplicatie / serviciu.
Interfata Remote serveste la marcarea interfetelor ale caror metode urmeaza a fiapelate de pe alta masina virtuala Java.
Un obiect de tip java.rmi.server.UnicastRemoteObject mijloceste transmitereaobiectelor si serveste la generarea unui stub unui serviciu. Generarea stub-ului unuiserviciu se obtine prin intermediul metodei statice
static Remote UnicastRemoteObject.exportObject(Remote obj,int port)
60 CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANTA
Inregistrarea stub-ului unui serviciu descris de interfata IService si imple-mentat de clasa ServiceImpl ın registry se face prin
ServiceImpl obj=new ServiceImpl();
IService stub=(IService)UnicastRemoteObject.exportObject(obj,0);
// Varianta cu apel rmiregistry direct
/*
Registry registry=LocateRegistry.getRegistry(host,port);
registry.bind("MyServiceName",stub);
*/
// Varianta JNDI
String sPort=(new Integer(port)).toString();
System.setProperty(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.rmi.registry.RegistryContextFactory");
System.setProperty(Context.PROVIDER_URL,"rmi://"+host+":"+sPort);
Context ctx=new InitialContext();
ctx.bind("MyServiceName",stub);
Un client care doreste sa foloseasca trebuie sa cunoasca :
• calculatorul pe care se gaseste obiectul registry si portul la care asculta servi-ciul;
• numele sub care serviciul s-a ınregistrat ın registry;
• metodele puse la dispozitie de serviciu.
4.1.1 Crearea unei aplicatii RMI
Exemplificam construirea unei aplicatii RMI ın care serviciul asigurat de servereste calculul celui mai mare divizor comun a doua numere naturale.
Pentru exemplele2 care urmeaza, presupunem ca textele sursa se retin ın subcat-aloage ale unui catalog src, la care are acces doar programatorul, iar clasele obtinuteprin compilare se depun ın subcataloagele unui catalog public\classes, accesibilprin retea.
Dezvoltarea unei aplicatii se va face pe un calculator. In acest sens, celor 3componente li se asociaza cataloagele \i - pentru interfata la distanta, \s - pentrucomponenta server si \c - pentru componenta client. Pasi necesari compilarii sidesfasurarii componentelor aplicatiei se vor realiza prin intermediul lui ant.
Pentru fiecare componenta se vor executa succesiv obiectivele:
1. Install - creaza o structura de cataloage src si public\classes.2Sistemul de operare utilizat este Windows
4.1. REMOTE METHOD INVOCATION 61
2. Init - creaza structura de cataloage specifica aplicatiei.
3. Compile - compileaza programele sursa.
Dezvoltarea unei aplicatii RMI consta din parcurgerea urmatorilor pasi:
1. Definitea interfetei la distanta.
1 package cmmdc ;2 public interface ICmmdc extends java . rmi . Remote{3 long cmmdc( long a , long b) throws java . rmi . RemoteException ;4 }
Presupunem ca programatorul interfetei retine textul sursaICmmdc.java ın catalogul \i\src\cmmdc.
2. Compilarea si arhivarea interfetei se poate realiza fisierul ant-build
1 <project name=” I n t e r f a c e ” d e f a u l t=” I n s t a l l ” ba s ed i r=” . ”>2 <description> I n t e r f a c e a c t i o n s </description>3 < !−− s e t g l o b a l p r op e r t i e s f o r t h i s b u i l d −−>
5 <property name=” package ” value=”cmmdc”/>
7 <target name=” I n s t a l l ”>8 < !−− Create the b u i l d d i r e c t o r y s t r u c t u r e used by compile −−>9 <delete d i r=” s r c ”/>
10 <mkdir d i r=” s r c ”/>11 <delete d i r=” pub l i c ”/>12 <mkdir d i r=” pub l i c ”/>13 <delete d i r=” pub l i c / c l a s s e s ”/>14 <mkdir d i r=” pub l i c / c l a s s e s ”/>15 </target>
17 <target name=” I n i t ”>18 < !−− Create the time stamp −−>19 <tstamp/>20 <mkdir d i r=” s r c /${package}”/>21 <mkdir d i r=” pub l i c / c l a s s e s /${package}”/>22 </target>
24 <target name=”Compile” depends=” I n i t ”25 description=” compile the source ” >26 <javac s r c d i r=” s r c ” i n c l u d e s=”${package }/∗∗”27 d e s t d i r=” pub l i c / c l a s s e s ”/>28 <jar based i r=” pub l i c / c l a s s e s ”29 d e s t f i l e=” pub l i c / c l a s s e s /${package }/${ package } . j a r ”30 i n c l u d e s=”${package }/∗ . c l a s s ” />31 </target>32 </project>
3. Implementarea interfetei remote prin construirea aplicatiei server.
62 CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANTA
1 package s e r v e r ;
3 import cmmdc . ∗ ;4 import java . rmi . ∗ ;5 import java . rmi . s e r v e r . ∗ ;6 // Varianta d i r e c t a7 // import java . rmi . r e g i s t r y . ∗ ;8 // Varianta JNDI9 import javax . naming . ∗ ;
11 public class CmmdcImpl implements ICmmdc{
13 public long cmmdc( long a , long b ) { . . .}
15 public stat ic void main ( St r ing args [ ] ) {16 St r ing host=” l o c a l h o s t ” ;17 int port =1099;18 i f ( args . length >0)19 host=args [ 0 ] ;20 i f ( args . length >1)21 port=I n t e g e r . pa r s e In t ( args [ 1 ] ) ;22 try {23 CmmdcImpl obj=new CmmdcImpl ( ) ;24 ICmmdc stub=(ICmmdc) UnicastRemoteObject . exportObject ( obj , 0 ) ;
26 // Varianta d i r e c t a27 /∗28 Reg i s t ry r e g i s t r y=LocateReg is t ry . g e tReg i s t r y ( host , por t ) ;29 r e g i s t r y . bind (”CmmdcServer” , s tub ) ;30 ∗/
32 // Varianta JNDI33 St r ing sPort=(new I n t e g e r ( port ) ) . t oS t r i ng ( ) ;34 System . se tProper ty ( Context . INITIAL CONTEXT FACTORY,35 ”com . sun . j n d i . rmi . r e g i s t r y . RegistryContextFactory ” ) ;36 System . se tProper ty ( Context .PROVIDER URL, ”rmi : // ”+host+” : ”+sPort ) ;37 Context ctx=new I n i t i a l C o n t e x t ( ) ;38 ctx . bind ( ”CmmdcServer” , stub ) ;
40 System . out . p r i n t l n ( ”CmmdcServer ready ” ) ;41 }42 catch ( Exception e ) {43 System . out . p r i n t l n ( ”CmmdcImpl e r r : ” + e . getMessage ( ) ) ;44 }45 }46 }
Textul sursa al programului server CmmdcImpl.java se retine ın catalogul\s\src\server
4. (a) Compilarea programului server;
(b) Crearea obiectului registry ;
(c) Lansarea serverului ın lucru
se obtin cu ant cu
4.1. REMOTE METHOD INVOCATION 63
1 <project name=” Server ” d e f a u l t=” I n s t a l l ” ba s ed i r=” . ”>2 <description>3 Server a c t i o n s4 </description>5 < !−− s e t g l o b a l p r op e r t i e s f o r t h i s b u i l d −−>
7 <property name=” package ” value=” s e r v e r ”/>8 <property name=” i n t e r f a c e−j a r ” location=”/ i / pub l i c / c l a s s e s /cmmdc” />9 <property name=” jar− f i l e ” va lue=”cmmdc . j a r ” />
10 <property name=” s e r v i c e−c l a s s ” value=”CmmdcImpl” />11 <property name=” host ” value=” l o c a l h o s t ” />12 <property name=” port ” value=”1099” />
14 <target name=” I n s t a l l ”>15 < !−− Create the time stamp −−>16 <tstamp/>17 < !−− Create the b u i l d d i r e c t o r y s t r u c t u r e used by compile −−>18 <delete d i r=” s r c ”/>19 <mkdir d i r=” s r c ”/>20 <delete d i r=” pub l i c ”/>21 <mkdir d i r=” pub l i c ”/>22 <delete d i r=” pub l i c / c l a s s e s ”/>23 <mkdir d i r=” pub l i c / c l a s s e s ”/>24 </target>
26 <target name=” I n i t ”>27 <mkdir d i r=” s r c /${package}”/>28 <mkdir d i r=” pub l i c / c l a s s e s /${package}”/>29 <copy f i l e=”${ i n t e r f a c e−j a r }/${ ja r− f i l e }” t o d i r=” pub l i c / c l a s s e s ” />30 </target>
32 <target name=”Compile” depends=” I n i t ”33 description=” compile the source ” >34 <javac s r c d i r=” s r c ”35 i n c l u d e s=”${package }/∗∗” d e s t d i r=” pub l i c / c l a s s e s ”36 classpath=” pub l i c / c l a s s e s /${ ja r− f i l e }” />37 <unjar src=” pub l i c / c l a s s e s /${ ja r− f i l e }” dest=” pub l i c / c l a s s e s ” />38 </target>
40 <target name=”Rmi”>41 <exec executab l e=” r m i r e g i s t r y ”>42 <arg value=”1099” />43 </exec>44 </target>
46 <target name=” Server ”>47 <java classname=”${package } . ${ s e r v i c e−c l a s s }”48 classpath=”/ s / pub l i c / c l a s s e s ” f o rk=” true ”>49 <jvmarg50 value=”−Djava . rmi . s e r v e r . codebase= f i l e : / s / pub l i c / c l a s s e s /” />51 <arg l i n e=”${ host } ${ port }” />52 </ java>53 </target>54 </project>
Parametrul -Djava.rmi.server.codebase fixeaza locatia interfetei la distantade pe calculatorul server.
64 CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANTA
Obiectivele Rmi si Server se lanseaza ın ferestre dos distincte care ramanactive pe durata de viata a aplicatiei server.
5. Realizarea programului client
1 package c l i e n t ;
3 import cmmdc . ∗ ;4 import java . u t i l . Scanner ;5 // Varianta d i r e c t a6 // import java . rmi . r e g i s t r y . ∗ ;7 // Varianta JNDI8 import javax . naming . ∗ ;
10 public class CmmdcClient {11 public stat ic void main ( St r ing args [ ] ) {12 St r ing host=” l o c a l h o s t ” ;13 int port =1099;14 i f ( args . length >0)15 host=args [ 0 ] ;16 i f ( args . length >1)17 port=I n t e g e r . pa r s e In t ( args [ 1 ] ) ;18 Scanner scanner=new Scanner ( System . in ) ;19 System . out . p r i n t l n ( ”Primul numar : ” ) ;20 long m=Long . parseLong ( scanner . next ( ) ) ;21 System . out . p r i n t l n ( ”Al d o i l e a numar : ” ) ;22 long n=Long . parseLong ( scanner . next ( ) ) ;23 long x=0;24 try {25 // Varianta d i r e c t a26 /∗27 Reg i s t ry r e g i s t r y=LocateReg is t ry . g e tReg i s t r y ( host , por t ) ;28 ICmmdc ob j=(ICmmdc) r e g i s t r y . lookup (”CmmdcServer ” ) ;29 ∗/30 // Varianta JNDI31 St r ing sPort=(new I n t e g e r ( port ) ) . t oS t r i ng ( ) ;32 System . se tProper ty ( Context . INITIAL CONTEXT FACTORY,33 ”com . sun . j n d i . rmi . r e g i s t r y . RegistryContextFactory ” ) ;34 System . se tProper ty ( Context .PROVIDER URL, ”rmi : // ”+host+” : ”+sPort ) ;35 Context ctx=new I n i t i a l C o n t e x t ( ) ;36 ICmmdc obj=(ICmmdc) ctx . lookup ( ”CmmdcServer” ) ;
38 x=obj . cmmdc(m, n ) ;39 System . out . p r i n t l n ( ”Cmmdc=”+x ) ;40 }41 catch ( Exception e ) {42 System . out . p r i n t l n ( ”CmmdcClient except ion : ”+e . getMessage ( ) ) ;43 }44 }45 }
Sursa programului client CmmdcClient.java apartine catalogului\c\src\client
6. Compilarea programului client si lansarea acestuia ın executie.
4.1. REMOTE METHOD INVOCATION 65
1 <project name=” Cl i en t ” d e f a u l t=” I n s t a l l ” ba s ed i r=” . ”>2 <description> Cl i en t a c t i o n s </description>3 < !−− s e t g l o b a l p r op e r t i e s f o r t h i s b u i l d −−>
5 <property name=” package ” value=” c l i e n t ”/>6 <property name=” i n t e r f a c e−j a r ” location=”/ i / pub l i c / c l a s s e s /cmmdc”/>7 <property name=” jar− f i l e ” va lue=”cmmdc . j a r ” />8 <property name=” host ” value=” l o c a l h o s t ” />9 <property name=” port ” value=”1099” />
10 <property name=” c l i e n t−c l a s s ” value=”CmmdcClient” />
12 <target name=” I n s t a l l ”>13 < !−− Create the b u i l d d i r e c t o r y s t r u c t u r e used by compile −−>14 <delete d i r=” s r c ”/>15 <mkdir d i r=” s r c ”/>16 <delete d i r=” c l a s s e s ”/>17 <mkdir d i r=” c l a s s e s ”/>18 </target>
20 <target name=” I n i t ”>21 < !−− Create the time stamp −−>22 <tstamp/>23 <mkdir d i r=” s r c /${package}”/>24 <mkdir d i r=” c l a s s e s /${package}”/>25 <copy f i l e=”${ i n t e r f a c e−j a r }\${ ja r− f i l e }” t o d i r=” c l a s s e s ” />26 </target>
28 <target name=”Compile” depends=” I n i t ”29 description=” compile the source ”>30 <javac s r c d i r=” s r c ”31 i n c l u d e s=”${package }/∗ . java ” d e s t d i r=” c l a s s e s ”32 classpath=” c l a s s e s \${ j a r− f i l e }” />33 </target>
35 <target name=”Run” depends=”Compile”36 description=” Star t thr c l i e n t ”>37 <java classname=”${package } . ${ c l i e n t−c l a s s }” f o rk=” true ”>38 <classpath>39 <pathelement location=” c l a s s e s /${ j a r− f i l e }” />40 <pathelement path=” c l a s s e s ” />41 </classpath>42 <arg l i n e=”${ host } ${ port }” />43 </ java>44 </target>45 </project>
4.1.2 Tipare de programare
Fabrica de obiecte
Tiparul fabrica de obiecte va permite crearea dinamica a unui server, fapt carenu este posibil pe schema prezentata ın paragraful precedent. Prin aceea schema,se va crea o clasa - fabrica de obiecte - care implementeaza cate o metoda get, cereturneaza o instanta de server. Aceste metode sunt declarate ıntr-o interfata la
66 CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANTA
distanta. Un client, apeland o asemenea metoda, va instantia serverul dorit si vaobtine stub-ul corespunzator.
Programarea unui server care poate fi lansat dinamic trebuie sa satisfaca restrictiile:
• Clasa serverului extinde clasa UnicastRemoteObject.
• Exista un constructor fara argumente ce arunca exceptia java.rmi.Remote
Exception.
Pentru exemplificarea tehnicii de lucru reluam aplicatia pentru calculul celui maimare divizor comun a doua numere naturale, considerand interfata
1 package cmmdc0 ;2 import java . rmi . ∗ ;3 pub l i c i n t e r f a c e ICmmdc0 extends Remote{4 pub l i c long compute ( long m, long n) throws RemoteException ;5 }
Aceasa interfata va fi implementata de clasa ServerCmmdc. Metoda computeeste o metoda de calcul a celui mai mare divizor comun a doua numere.
Obiecte de tip ServerCmmdc se creaza, de la distanta prin fabrica de obiecteFabObiecte, o clasa ce implementeaza interfata
1 package cmmdc0 ;2 import java . rmi . ∗ ;3 pub l i c i n t e r f a c e IFabObiecte extends Remote{4 pub l i c ICmmdc0 getCmmdc ( ) throws RemoteException ;5 }
Codurile claselor ServerCmmdc si FabObiecte sunt
1 package cmmdc0 ;2 import java . rmi . ∗ ;3 import java . rmi . s e r v e r . ∗ ;4 import java . i o . ∗ ;5 import java . u t i l . ∗ ;
7 pub l i c c l a s s ServerCmmdc extends UnicastRemoteObject implements ICmmdc0{
9 pub l i c ServerCmmdc ( ) throws RemoteException{}
11 pub l i c long compute ( long m, long n) throws RemoteException{12 . . .13 }14 }
respectiv
1 package cmmdc0 ;2 import java . rmi . ∗ ;3 import java . rmi . s e r v e r . ∗ ;4 import java . rmi . r e g i s t r y . ∗ ;
6 pub l i c c l a s s FabObiecte implements IFabObiecte {
4.1. REMOTE METHOD INVOCATION 67
8 pub l i c ICmmdc0 getCmmdc ( ) throws RemoteException{9 ServerCmmdc cmmdc=new ServerCmmdc ( ) ;
10 r e turn cmmdc ;11 }
13 pub l i c s t a t i c void main ( S t r ing args [ ] ) {14 St r ing host=” l o c a l h o s t ” ;15 i n t port =1099;16 i f ( a rgs . length >0)17 host=args [ 0 ] ;18 i f ( a rgs . length >1)19 port=I n t e g e r . pa r s e In t ( args [ 1 ] ) ;20 t ry {21 FabObiecte obj=new FabObiecte ( ) ;22 IFabObiecte stub=(IFabObiecte ) UnicastRemoteObject . exportObject ( obj , 0 ) ;23 Reg i s t ry r e g i s t r y=LocateReg i s t ry . g e tReg i s t ry ( host , port ) ;24 r e g i s t r y . bind ( ” ObjectFactory ” , stub ) ;25 System . out . p r i n t l n ( ” ObjectFactory ready ” ) ;26 }27 catch ( Exception e ){28 System . out . p r i n t l n ( ” Factory e r r ”+e . getMessage ( ) ) ;29 }30 }31 }
Aplicatia client se compune din doua clase
1. RemoteClient
Clientul obtine stub-ul serviciului, prin intermediul caruia apeleaza metadagetCmmdc() a fabricii de obiecte, obtinand un obiect remote de tip Server-Cmmdc, ce implementeaza interfata la distanta ICmmdc0.
1 package cmmdc0 ;2 import java . rmi . ∗ ;3 import java . rmi . s e r v e r . ∗ ;4 import java . rmi . r e g i s t r y . ∗ ;
6 pub l i c c l a s s RemoteClient extends UnicastRemoteObject{
8 ICmmdc0 remote=n u l l ;
10 pub l i c RemoteClient ( ) throws RemoteException{}
12 pub l i c RemoteClient ( S t r ing host , i n t port ) throws RemoteException{13 IFabObiecte f a b r i c a=n u l l ;14 t ry {15 Reg i s t ry r e g i s t r y=LocateReg i s t ry . g e tReg i s t ry ( host , port ) ;16 IFabObiecte obj=(IFabObiecte ) r e g i s t r y . lookup ( ” ObjectFactory ” ) ;17 remote=obj . getCmmdc ( ) ;18 }19 catch ( Exception e ){20 System . out . p r i n t l n ( ” C l i en tExcept i on : ”+e . getMessage ( ) ) ;21 }22 }23 }
68 CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANTA
2. ClientCmmdc0
Apeleaza metoda compute a obiectului remote.
1 package cmmdc0 ;2 import java . u t i l . Scanner ;
4 pub l i c c l a s s ClientCmmdc0{
6 pub l i c s t a t i c void main ( St r ing args [ ] ) {7 St r ing host=” l o c a l h o s t ” ;8 i n t port =1099;9 i f ( a rgs . length >0)
10 host=args [ 0 ] ;11 i f ( a rgs . length >1)12 port=I n t e g e r . pa r s e In t ( args [ 1 ] ) ;13 Scanner scanner=new Scanner ( System . in ) ;14 t ry {15 RemoteClient ct=new RemoteClient ( host , port ) ;16 System . out . p r i n t l n ( ”m=” ) ;17 long m=scanner . nextLong ( ) ;18 System . out . p r i n t l n ( ”n=” ) ;19 long n=scanner . nextLong ( ) ;20 long x=ct . remote . compute (m, n ) ;21 System . out . p r i n t l n ( ”Cmmdc=”+x ) ;22 }23 catch ( Exception e ){24 System . out . p r i n t l n ( ” C l i en tExcept i on : ”+e . getMessage ( ) ) ;25 }26 System . e x i t ( 0 ) ;27 }28 }
Apelul invers – Callback
Se numeste apel invers apelarea de catre programul server a unei metode a clien-tului.
In RMI realizarea unui apel invers presupune:
1. definirea unei interfete la distanta ce va fi implementat de programul client;
2. programul client ce implementeaza interfata extinde clasa UnicastRemote Object
si are un constructor ce arunca o exceptie java.rmi.RemoteException.
Extindem aplicatia anterioara cu posibilitatea suplimentara a serverului (Server-Cmmdc) de a alege metoda de calcul a celui mai mare divizor comun dintre variantanerecursiva si cea recursiva a algorimului lui Euclid.
Extindem interfata ICmmdc0 cu metoda
public void setMethod(ICallbackCmmdc obj)throws RemoteException;
1 package cmmdc0 ;2 import java . rmi . ∗ ;
4.1. REMOTE METHOD INVOCATION 69
3 pub l i c i n t e r f a c e ICmmdc0 extends Remote{4 pub l i c long compute ( long m, long n) throws RemoteException ;5 pub l i c void setMethod ( ICallbackCmmdc obj ) throws RemoteException ;6 }
unde ICallbackCmmdc este interfata
1 package cmmdc0 ;2 import java . rmi . ∗ ;3 pub l i c i n t e r f a c e ICallbackCmmdc extends Remote{4 pub l i c S t r ing getMethod ( ) throws RemoteException ;5 }
ce va fi implementata ın clasa RemoteClient.Programul ServerCmmdc devine
1 package cmmdc0 ;2 import java . rmi . ∗ ;3 import java . rmi . s e r v e r . ∗ ;4 import java . i o . ∗ ;
6 pub l i c c l a s s ServerCmmdc extends UnicastRemoteObject7 implements ICmmdc0{8 p r i v a t e S t r ing method=n u l l ;
10 pub l i c ServerCmmdc ( ) throws RemoteException{}
12 pub l i c long compute ( long m, long n){13 long x=0;14 i f ( method . equa l s ( ”NERECURSIV” ) )15 x=n e r e c u r s i v (m, n ) ;16 i f ( method . equa l s ( ”RECURSIV” ) )17 x=r e c u r s i v (m, n ) ;18 r e turn x ;19 }
21 pub l i c void setMethod ( ICallbackCmmdc obj ) throws RemoteException{22 method=obj . getMethod ( ) ;23 }
25 p r i v a t e long r e c u r s i v ( long a , long b){26 i f ( a==b)27 r e turn a ;28 e l s e29 i f ( a<b)30 r e turn r e c u r s i v ( a , b−a ) ;31 e l s e32 r e turn r e c u r s i v ( a−b , b ) ;33 }
35 p r i v a t e long n e r e c u r s i v ( long m, long n){36 long r , c ;37 do{38 c=n ;39 r=m%n ;40 m=n ;41 n=r ;42 }43 whi le ( r !=0) ;
70 CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANTA
44 r e turn c ;45 }46 }
Dupa obtinerea stub-ului, clientul apeleaza metoda setMethod a serverului re-mote, care, prin apel invers, apeleaza metoda getMethod din RemoteClient. Clientulstabileste metoda de calcul si apeleaza metoda compute a lui remote.
Programele client devin
1 package cmmdc0 ;2 import java . rmi . ∗ ;3 import java . rmi . s e r v e r . ∗ ;4 import java . rmi . r e g i s t r y . ∗ ;5 import java . u t i l . Scanner ;
7 pub l i c c l a s s RemoteClient extends UnicastRemoteObject8 implements ICallbackCmmdc{9 ICmmdc0 remote=n u l l ;
11 pub l i c RemoteClient ( ) throws RemoteException{}
13 pub l i c S t r ing getMethod ( ){14 Scanner scanner=new Scanner ( System . in ) ;15 System . out . p r i n t l n ( ” A l e g e t i va r i anta a l g o r i t m u l u i l u i Eucl id ” ) ;16 System . out . p r i n t l n ( ”1 − a l go r i tmu l ne−r e c u r s i v ” ) ;17 System . out . p r i n t l n ( ”2 − a l go r i tmu l r e c u r s i v ” ) ;18 i n t x=scanner . next Int ( ) ;19 St r ing method=n u l l ;20 i f ( x==1)21 method=”NERECURSIV” ;22 e l s e23 method=”RECURSIV” ;24 r e turn method ;25 }
27 pub l i c RemoteClient ( S t r ing host , i n t port ) throws RemoteException{28 IFabObiecte f a b r i c a=n u l l ;29 t ry {30 Reg i s t ry r e g i s t r y=LocateReg i s t ry . g e tReg i s t ry ( host , port ) ;31 IFabObiecte obj=(IFabObiecte ) r e g i s t r y . lookup ( ” ObjectFactory ” ) ;32 remote=obj . getCmmdc ( ) ;33 }34 catch ( Exception e ){35 System . out . p r i n t l n ( ” C l i en tExcept i on : ”+e . getMessage ( ) ) ;36 }37 }38 }
si
1 package cmmdc0 ;2 import java . u t i l . Scanner ;
4 pub l i c c l a s s ClientCmmdc0{5 pub l i c s t a t i c void main ( S t r ing args [ ] ) {6 St r ing host=” l o c a l h o s t ” ;7 i n t port =1099;8 i f ( a rgs . length >0)
4.1. REMOTE METHOD INVOCATION 71
9 host=args [ 0 ] ;10 i f ( a rgs . length >1)11 port=I n t e g e r . pa r s e In t ( args [ 1 ] ) ;12 Scanner scanner=new Scanner ( System . in ) ;13 t ry {14 RemoteClient ct=new RemoteClient ( host , port ) ;15 ct . remote . setMethod ( ct ) ;16 System . out . p r i n t l n ( ”m=” ) ;17 long m=scanner . nextLong ( ) ;18 System . out . p r i n t l n ( ”n=” ) ;19 long n=scanner . nextLong ( ) ;20 long x=ct . remote . compute (m, n ) ;21 System . out . p r i n t l n ( ”Cmmdc=”+x ) ;22 }23 catch ( Exception e ){24 System . out . p r i n t l n ( ” C l i en tExcept i on : ”+e . getMessage ( ) ) ;25 }26 System . e x i t ( 0 ) ;27 }28 }
4.1.3 Obiect activabil la distanta
O instanta a clasei UnicastRemoteObject reprezinta un obiect la distanta careruleaza ın permanenta, folosind resursele masinii server.
Incepand cu versiunea JDK 1.2, prin ıntroducerea clasei java.rmi.activa-tion.Activatable si a programului rmid (...\jdk...\bin\rmid.exe) se pot crea pro-grame care ınregistreaza informatii despre obiecte la distanta ce vor fi create siexecutate la cerere.
Invocarea de la distanta a unei metode apartinand unui asemenea obiect are caefect activarea obiectului.
Pe fiecare masina virtuala Java exista un grup de activare (activation group),care realizeaza activarea. Activarea este facuta de un activator. Un activator contineo tabela care face legatura dintre clasa obiectului cu URL-ul acestuia si eventual, cudate necesare initializarii obiectului. Atunci cand activatorul constata ca nu existaun obiect referit, face apel la grupul de activare care va produce activarea obiectului.
Din punctul de vedere al clientului utilizarea mecanismului de activare la distantanu implica modificari. Modificarile intervin numai din punctul de vedere al serveruluisi al ınregistrarii sale.
Reluam aplicatia dezvoltata la ınceputul capitolului, privind calculul celui maimare divizor comun a doua numere naturale.
Aplicatia server este compusa din doua clase
1. o clasa ce implementeaza interfata ICmmdc : CmmdcActivabil;
2. clasa Setup, cu metoda main, care face posibila mecanismul de activare siınscrie serviciul ın registry. Aceasta clasa este preluata din tutorialul dedicatactivarii a documentatiei ce ınsoteste distributia Java.
72 CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANTA
Clasa ce implementeaza interfata la distanta trebuie
1. sa extinda clasa Activatable;
2. sa aiba un constructor ce are doi parametrii
(a) un identificator al grupului de activare, de tip ActivationID, utilizat dedemonul de activare rmid;
(b) un obiect de tip MarshalledObject cu date de initializare a obiectuluiactivabil. In cazul nostru, acest parametru nu va fi folosit.
Codul sursa al clasei CmmdcActivabil este
1 package acmmdc ;2 import java . rmi . ∗ ;3 import java . rmi . a c t i v a t i o n . ∗ ;4 import cmmdc . ∗ ;
6 pub l i c c l a s s CmmdcActivabil extends Act ivatab l e7 implements ICmmdc{
9 pub l i c CmmdcActivabil ( Act ivat ionID id , Marshal ledObject data )10 throws RemoteException{11 super ( id , 0 ) ;12 }
14 pub l i c long cmmdc( long m, long n ) { . . .}15 }
Clasa Setup necesita o serie de date furnizare ca proprietati:
1. drepturile de securitate ale grupului de activare
myactivation.policy=group.policy;
cu continutul
grant codeBase "${myactivation.impl.codebase}" {
// permission to read and write object’s file
permission java.io.FilePermission "${myactivation.file}","read,write";
// permission to listen on an anonymous port
permission java.net.SocketPermission "*:1024-","accept";
};
2. java.class.path=no.classpath
ceea ce previne grupul de activare sa ıncarce o clasa din classpath-ul local;
3. localizarea (URL) clasei ce implementeaza interfata
myactivation.impl.codebase;
4.1. REMOTE METHOD INVOCATION 73
4. localizarea unui fisier cu date de initializare a obiectului activabil
myactivation.file;
5. numele sub care ınregistreaza serviciul ın registry
myactivation.name.
Programul Setup realizeaza:
1. Construirea unui descriptor al grupului de activare. Grupul de activare esteun container ce gestioneaza obiectele activabile continute.
2. Inregistrarea descriptorului grupului de activare si obtinerea unui identificatoral grupului de activare.
3. Construirea descriptorului de activare. Trebuie cunoscute
• idendificatorul grupului de activare;
• numele clasei ce implementeaza interfata la distanta;
• localizarea (URL) clasei ce implementeaza interfata la distanta;
• obiectul de tip MarshalledObject, cu datele de initializare a obiectuluiactivabil.
4. Inregistrarea descriptorului de activare, ın urma careia se obtine stub-ul obiec-tului activabil.
5. Inregistrarea stub-ului ımpreuna cu numele serviciului ın registry.
Codul clasei setup este
1 package acmmdc ;
3 import java . rmi . ∗ ;4 import java . rmi . a c t i v a t i o n . ∗ ;5 import java . rmi . r e g i s t r y . ∗ ;6 import java . u t i l . P r o p e r t i e s ;
8 pub l i c c l a s s Setup{
10 p r i v a t e Setup ( ) {}
12 pub l i c s t a t i c void main ( S t r ing [ ] a rgs ) throws Exception {
14 // Argumentul l i n i e i de comanda15 St r ing implClass = ”” ;16 i f ( a rgs . l ength < 1) {17 System . out . p r i n t l n ( ” usage : ” ) ;18 System . out . p r i n t l n ( ” java [ opt ions ] examples . a c t i v a t i o n . Setup <implClass>” ) ;19 System . e x i t ( 1 ) ;20 }21 e l s e {
74 CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANTA
22 implClass = args [ 0 ] ;23 }
25 // Const ru i rea d e s c r i p t o r u l u i g rupu lu i de a c t i v a r e26 St r ing p o l i c y=System . getProperty ( ” myact ivat ion . p o l i c y ” , ”group . p o l i c y ” ) ;27 St r ing implCodbase=System . getProperty ( ” myact ivat ion . impl . codebase ” ) ;28 St r ing filename=System . getProperty ( ” myact ivat ion . f i l e ” , ”” ) ;29 P r o p e r t i e s props = new P r o p e r t i e s ( ) ;30 props . put ( ” java . s e c u r i t y . p o l i c y ” , p o l i c y ) ;31 props . put ( ” java . c l a s s . path” , ” no c l a s spa th ” ) ;32 props . put ( ” myact ivat ion . impl . codebase ” , implCodebase ) ;33 i f ( filename != n u l l && ! filename . equals ( ”” ) ) {34 props . put ( ” myact ivat ion . f i l e ” , filename ) ;35 }36 ActivationGroupDesc groupDesc = new ActivationGroupDesc ( props , n u l l ) ;
38 // I n r e g i s t r a r e a grupu lu i de a c t i v a r e pentr ob t ine r ea39 // i d e n t i f i c a t o r u l u i de a c t i v a r e40 ActivationGroupID groupID=41 ActivationGroup . getSystem ( ) . r eg i s t e rGroup ( groupDesc ) ;42 System . e r r . p r i n t l n ( ” Act ivat ion group d e s c r i p t o r r e g i s t e r e d . ” ) ;
44 // Const ru i rea d e s c r i p t o r u l u i de a c t i v a r e45 Marshal ledObject data = n u l l ;46 i f ( filename != n u l l && ! filename . equals ( ”” ) ) {47 data = new Marshal ledObject ( filename ) ;48 }
50 Act ivat ionDesc desc=51 new Act ivat ionDesc ( groupID , implClass , implCodebase , data ) ;
53 // I n r e g i s t r a r e a d e s c r i p t o r u l u i de a c t i v a r e54 Remote stub = Act ivatab l e . r e g i s t e r ( desc ) ;55 System . e r r . p r i n t l n ( ” Act ivat ion d e s c r i p t o r r e g i s t e r e d . ” ) ;
57 // I n r e g i s t r a r e a s e r v i c i u l u i in r e g i s t r y58 St r ing name = System . getProperty ( ” myact ivat ion . name” ) ;59 LocateReg i s t ry . g e tReg i s t ry ( ) . reb ind (name , stub ) ;60 System . e r r . p r i n t l n ( ”Stub bound in r e g i s t r y . ” ) ;61 }62 }
Sursele celor doua programe CmmdcActivabil.java si respectiv Setup.java suntın catalogul \c\src\acmmdc.
Lansarea serverului ın executie consta din
1. Pornirea demon-ului rmid
start rmid -J-Djava.security.policy=rmid.policy
-J-Dmyactivation.policy=group.policy
unde rmid.policy este
grant {
// allow activation groups to use certain system properties
permission com.sun.rmi.rmid.ExecOptionPermission
4.2. CORBA 75
"-Djava.security.policy=${myactivation.policy}";
permission com.sun.rmi.rmid.ExecOptionPermission
"-Djava.class.path=no_classpath";
permission com.sun.rmi.rmid.ExecOptionPermission
"-Dmyactivation.impl.codebase=*";
permission com.sun.rmi.rmid.ExecOptionPermission
"-Dmyactivation.file=*";};
iar group.policy are codul
grant codeBase "${myactivation.impl.codebase}" {
// permission to read and write object’s file
permission java.io.FilePermission "${myactivation.file}","read,write";
// permission to listen on an anonymous port
permission java.net.SocketPermission "*:1024-","accept";
};
2. Pornirea registry-ului
start rmiregistry
3. Lansarea programului Setup
set classpath=\s\public\classes\cmmdc.jar;\s\public\classes
java -Djava.rmi.server.codebase=file:/s/public/classes/
-Dmyactivation.impl.codebase=file:/s/public/classes/
-Dmyactivation.name=CmmdcServer
-Dmyactivation.file=""
-Dmyactivation.policy=group.policy
acmmdc.Setup acmmdc.CmmdcActivabil
Localizarea (URL) interfetei la distanta se precizeaza prinjava.rmi.server.codebase;
Drept client se utilizeaza programul realizat ın sectiunea 4.1.
4.2 CORBA
Retelele de calculatoare sunt eterogene ın timp ce majoritatea interfetelor deprogramare a aplicatiilor sunt orientate spre platforme omogene.
Pentru a facilita integrarea unor sisteme dezvoltate separat, ıntr-un singur mediudistribuit eterogen, OMG (Object Management Group – consortiu cuprinzand peste800 de firme) a elaborat standardul CORBA (Common Object Request Broker Arhi-tecture): un cadru de dezvoltare a aplicatiilor distribuite ın medii eterogene.
La CORBA au aderat toate marile firme de software - cu exceptia Microsoft,firma care a dezvoltat propriul sau model DCOM (Distributed Component ObjectModel), incompatibil CORBA.
76 CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANTA
CORBA contine programe client care utilizeaza diferite obiecte distribuite ınsistem. Deoarece ın multe sisteme de operare prelucrarile trebuie sa evolueze ıntr-un proces, orice obiect trebuie sa evolueze ıntr-un proces. In alte cazuri, obiectelepot evolua ın fire de executie sau ın biblioteci dll. CORBA omogenizeaza acesteposibilitati prin precizarea ca obiectele exista ın servere. Fiecare obiect este asociatcu un singur server.
Interconectarea obiectelor. Implementarea si localizarea unui obiect sunt as-cunse clientului. Comunicarea ıntre client si obiect este facilitata de Object Request
Broker (ORB) – care permite obiectelor sa se regaseaca unele pe altele ın retea. Elajuta obiectele sa faca cereri si sa primeasca raspunsuri de la alte obiecte aflateın retea. Acestea se desfasoara transparent pentru client – care nu stie unde estelocalizat obiectul, care este mecanismul utilizat pentru a comunica cu el, cum esteactivat sau memorat acesta.
ORB este un pachet de servicii, independent de aplicatii, dar care permit aplicatiilorsa interactioneze prin retea. ORB face parte din middleware – un intermediar ıntresoftul de retea si cel de aplicatie.
Un ORB se poate executa local pe un singur calculator sau poate fi conectatcu oricare alt ORB din Internet, folosind protocolul IIOP -- Internet Inter ORB
Protocol, definit de CORBA 2.CORBA face o separare ıntre interfata unui obiect si implementarea sa si foloseste
un limbaj neutru pentru definirea interfetelor: IDL -- Interface Definition Language.
IDL permite realizarea descrierii de interfete independent de limbajul de pro-gramare si de sistemul de operare folosit. O interfata IDL defineste legatura dintreclient si server.
4.2.1 Conexiunea RMI - CORBA
Firma Oracle - Sun Microsystems a dezvoltat o solutie prin care programele RMIpot fi adaptate pentru a putea accesa obiecte CORBA. Aceasta este cunoscuta subnumele de solutia RMI-IIOP, concretizata printr-o serie de pachete din distributiajdk. In acest fel nu mai este necesar utilizarea limbajului IDL pentru descriereainterfetelor la distanta.
Instrumente necesare utilizarii solutiei RMI-IIOP:
• compilatorul rmic
Optiunea -iiop genereaza stub-ul si legatura (tie) din partea serverului.
Cu optiunea -d se specifica catalogul ın care aceste fisiere sunt scrise.
• serviciul ORB care asigura regasirea resurselor CORBA. Acest server se lanseazaın executie prin
start orbd -ORBInitialPort [port ]
Programele orbd, rmic sunt ın distributia jdk.
4.2. CORBA 77
Transformarea unui program RMI ıntr-un program RMI-IIOP
Exemplificam prin aplicatia care implementeaza un serviciu de calcul a celui maimare divizor comun a doua numere naturale. Etapele realizarii aplicatiei sunt:
1. Elaborarea interfetei este identica cu cea a aplicatiei RMI.
2. Implementarea interfetei
1 package cmmdciiop ;2 import javax . rmi . PortableRemoteObject ;3 import cmmdc . ∗ ;4 import java . rmi . ∗ ;
6 // Se ext inde c l a s a PortableRemoteObject7 // s i nu UnicastRemoteObject
9 pub l i c c l a s s CmmdcImpl extends PortableRemoteObject implements ICmmdc{10 // Const ructoru l c l a s e i11 pub l i c CmmdcImpl ( ) throws RemoteException {}
13 pub l i c long cmmdc( long a , long b ) { . . .}14 }
3. Realizarea programului server.
1 package cmmdciiop ;2 import javax . naming . I n i t i a l C o n t e x t ;3 import javax . naming . Context ;
6 pub l i c c l a s s CmmdcServer {7 pub l i c s t a t i c void main ( S t r ing [ ] a rgs ) {8 St r ing host=” l o c a l h o s t ” ;9 St r ing port=”1050” ;
10 i f ( a rgs . length >0)11 host=args [ 0 ] ;12 i f ( a rgs . length >1)13 port=args [ 1 ] ;14 t ry {15 // 1 : Crearea unei i n s t a n t e CmmdcImpl16 CmmdcImpl cmmdcRef = new CmmdcImpl ( ) ;
18 // 2 : I n r e g i s t r a r e a unei r e f e r i n t e a s e r v i c i u l u i19 // u t i l i z a n d JNDI API20 System . se tProper ty ( ” java . naming . f a c t o r y . i n i t i a l ” ,21 ”com . sun . j n d i . cosnaming . CNCtxFactory” ) ;22 System . se tProper ty ( ” java . naming . prov ide r . u r l ” ,23 ” i i o p : //”+host+” : ”+port ) ;24 Context ctx = new I n i t i a l C o n t e x t ( ) ;25 ctx . reb ind ( ”CmmdcService” , cmmdcRef ) ;26 System . out . p r i n t l n ( ”Cmmdc S e r v e r : Ready . . . ” ) ;27 }28 catch ( Exception e ) {
78 CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANTA
29 System . out . p r i n t l n ( ”CmmdcServer: ” + e . getMessage ( ) ) ;30 }31 }32 }
4. Compilarea programelor CmmdcImpl.java si CmmdcServer.java.
5. Generarea stub-ului cmmdc. ICmmdc Stub.class corespunzator interfetei ICm-mdc si a fisierului Tie cmmdciiop. CmmdcImpl Tie.class corespunzator claseiCmmdcImpl. Acestea se obtin ruland utilitarul rmic - din distrubutia Java –cu optiunea -iiop
rmic -iiop cmmdciiop.CmmdcImpl
6. Pornirea serverului CORBA de regasire a serviciilor
start orbd -ORBInitialPort 1050
7. Lansarea serverului ın executie.
Activitatile legate de server se obtin prin ant cu fisierul build
1 <project name=” Server ” d e f a u l t=” I n s t a l l ” ba s ed i r=” . ”>2 <description>Server a c t i o n s</description>3 < !−− s e t g l o b a l p r op e r t i e s f o r t h i s b u i l d −−>
5 <property name=” package ” value=”cmmdciiop”/>6 <property name=” i n t e r f a c e−package ” value=”cmmdc” />7 <property name=” i n t e r f a c e−j a r ” location=”/ i / pub l i c / c l a s s e s /cmmdc” />8 <property name=” jar− f i l e ” va lue=”cmmdc . j a r ” />9 <property name=” s e r v i c e−c l a s s ” value=”CmmdcServer” />
10 <property name=” implementation−c l a s s ” value=”CmmdcImpl” />11 <property name=” host ” value=” l o c a l h o s t ” />12 <property name=” port ” value=”1050” />
14 <target name=” I n s t a l l ”>15 < !−− Create the time stamp −−>16 <tstamp/>17 < !−− Create the b u i l d d i r e c t o r y s t r u c t u r e used by compile −−>18 <delete d i r=” s r c ”/>19 <mkdir d i r=” s r c ”/>20 <delete d i r=” pub l i c ”/>21 <mkdir d i r=” pub l i c ”/>22 <delete d i r=” pub l i c / c l a s s e s ”/>23 <mkdir d i r=” pub l i c / c l a s s e s ”/>24 </target>
26 <target name=” I n i t ”>27 <mkdir d i r=” s r c /${package}”/>28 <mkdir d i r=” pub l i c / c l a s s e s /${package}”/>29 <copy f i l e=”${ i n t e r f a c e−j a r }/${ ja r− f i l e }” t o d i r=” pub l i c / c l a s s e s ” />30 <unjar src=” pub l i c / c l a s s e s /${ ja r− f i l e }” dest=” pub l i c / c l a s s e s ” />31 <delete d i r=” pub l i c / c l a s s e s /META−INF” />
4.2. CORBA 79
32 </target>
34 <target name=”Compile” depends=” I n i t ”35 description=” compile the source ” >36 <javac s r c d i r=” s r c ” d e s t d i r=” pub l i c / c l a s s e s ”37 i n c l u d e s=”${package }\∗∗”38 classpath=” pub l i c \ c l a s s e s \${ ja r− f i l e }” />39 <rmic classname=”${package }\${ implementation−c l a s s }”40 sourcebase=” s r c ”41 i i o p=” yes ”42 base=” pub l i c / c l a s s e s ”43 classpath=” pub l i c / c l a s s e s ” />44 </target>
46 <target name=”Orb”>47 <exec executab l e=”orbd”>48 <arg l i n e=”−ORBInit ia lPort ${ port } −ORBInitialHost ${ host }” />49 </exec>50 </target>
52 <target name=” Server ” description=” Star t thr s e r v e r ” >53 <java classname=”${package } . ${ s e r v i c e−c l a s s }” f o rk=” true ”>54 <classpath>55 <pathelement location=” pub l i c / c l a s s e s /${ ja r− f i l e }” />56 <pathelement path=” pub l i c / c l a s s e s ” />57 </classpath>58 <arg l i n e=”${ host } ${ port }” />59 </ java>60 </target>61 </project>
8. Editarea programului client.
1 package cmmdciiop ;2 import java . rmi . ∗ ;3 import javax . rmi . ∗ ;4 import java . net . MalformedURLException ;5 import javax . naming . ∗ ;6 import java . u t i l . Scanner ;7 import cmmdc . ∗ ;
9 public class CmmdcClient {10 public stat ic void main ( St r ing args [ ] ) {11 St r ing host=” l o c a l h o s t ” ;12 St r ing port=”1050” ;13 i f ( args . length >0)14 host=args [ 0 ] ;15 i f ( args . length >1)16 port=args [ 1 ] ;
18 Scanner scanner=new Scanner ( System . in ) ;19 System . out . p r i n t l n ( ”Primul numar : ” ) ;20 long m=Long . parseLong ( scanner . next ( ) ) ;21 System . out . p r i n t l n ( ”Al d o i l e a numar : ” ) ;22 long n=Long . parseLong ( scanner . next ( ) ) ;23 try {
80 CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANTA
24 System . se tProper ty ( ” java . naming . f a c t o r y . i n i t i a l ” ,25 ”com . sun . j n d i . cosnaming . CNCtxFactory” ) ;26 System . se tProper ty ( ” java . naming . prov ide r . u r l ” ,27 ” i i o p :// ”+host+” : ”+port ) ;28 Context ctx = new I n i t i a l C o n t e x t ( ) ;
30 // STEP 1: Get the Object r e f e r ence from the Name Servc txe31 // using JNDI c a l l .32 Object o b j r e f = ctx . lookup ( ”CmmdcService” ) ;33 System . out . p r i n t l n ( ” C l i en t : Obtained a r e f . to Cmmdc s e r v e r . ” ) ;
35 // STEP 2: Narrow the o b j e c t r e f e r ence to the concre te type and36 // invoke the method .37 ICmmdc obj = (ICmmdc) PortableRemoteObject . narrow ( ob j r e f , ICmmdc . class ) ;38 long x=obj . cmmdc(m, n ) ;39 System . out . p r i n t l n ( ”Cmmdc=”+x ) ;40 }41 catch ( Exception e ) {42 System . out . p r i n t l n ( ” Exception ” + e . getMessage ( ) ) ;43 }44 }45 }
9. Compilarea si lansarea clientului ın executie. Clientul trebuie sa dispuna defisierul stub (cmmdc. ICmmdc Stub.class) si bineınteles de interfata ICmmdc.jar.
Fisierul buildfile pentru executarea clientului:
1 <project name=” Cl i en t ” d e f a u l t=” I n s t a l l ” ba s ed i r=” . ”>2 <description>Cl i en t a c t i o n s</description>3 < !−− s e t g l o b a l p r op e r t i e s f o r t h i s b u i l d −−>
5 <property name=” package ” value=”cmmdciiop”/>6 <property name=” i n t e r f a c e−j a r ” location=”/ i / pub l i c / c l a s s e s /cmmdc” />7 <property name=” jar− f i l e ” va lue=”cmmdc . j a r ” />8 <property name=” server−package ” value=”cmmdciiop” />9 <property name=” i n t e r f a c e−package ” value=”cmmdc” />
10 <property name=” i n t e r f a c e−stub−l o c a t i o n ”11 location=”/ s / pub l i c / c l a s s e s /${ i n t e r f a c e−package}” />12 <property name=”stub−c l a s s ” value=”∗ Stub . c l a s s ” />13 <property name=” host ” value=” l o c a l h o s t ” />14 <property name=” port ” value=”1050” />15 <property name=” c l i e n t−c l a s s ” value=”CmmdcClient” />
17 <target name=” I n s t a l l ”>18 < !−− Create the b u i l d d i r e c t o r y s t r u c t u r e used by compile −−>19 <delete d i r=” s r c ”/>20 <mkdir d i r=” s r c ”/>21 <delete d i r=” c l a s s e s ”/>22 <mkdir d i r=” c l a s s e s ”/>23 </target>
25 <target name=” I n i t ”>26 < !−− Create the time stamp −−>27 <tstamp/>28 <mkdir d i r=” s r c /${package}”/>29 <mkdir d i r=” c l a s s e s /${package}”/>30 <delete d i r=” c l a s s e s /${ s e rver−package}” />
4.2. CORBA 81
31 <mkdir d i r=” c l a s s e s /${ s e rver−package}”/>32 <delete d i r=” c l a s s e s /${ i n t e r f a c e−package}” />33 <mkdir d i r=” c l a s s e s /${ i n t e r f a c e−package} ”/>34 <copy f i l e=”${ i n t e r f a c e−j a r }\${ ja r− f i l e }” t o d i r=” c l a s s e s ” />35 <copy t o d i r=” c l a s s e s /${ i n t e r f a c e−package}” >36 <f i l e s e t d i r=”${ i n t e r f a c e−stub−l o c a t i o n }”37 i n c l u d e s=”${ stub−c l a s s }” />38 </copy>39 <unjar src=” c l a s s e s /${ j a r− f i l e }” dest=” c l a s s e s ” />40 <delete d i r=” c l a s s e s /META−INF” />41 </target>
43 <target name=”Compile” depends=” I n i t ”44 description=” compile the source ” >45 <javac s r c d i r=” s r c ” d e s t d i r=” c l a s s e s ”46 i n c l u d e s=”${package }\∗ . java ” classpath=” c l a s s e s ” />47 </target>
49 <target name=”Run” depends=”Compile” description=”Run the c l i e n t ” >50 <java classname=”${package } . ${ c l i e n t−c l a s s }” f o rk=” true ”>51 <classpath>52 <pathelement location=” c l a s s e s /${ ja r− f i l e }” />53 <pathelement path=” c l a s s e s ” />54 </classpath>55 <arg l i n e=”${ host } ${ port }”/>56 </ java>57 </target>58 </project>
4.2.2 Aplicatie Java prin CORBA
Scopul acestei sectiuni este prezentarea dezvoltarii unei aplicatii pe baza uneiinterfete bazat pe IDL.
Pentru dezvoltarea aplicatiilor ın limbajul de programare Java, translatareainterfetei IDL ın Java se realizeaza cu utilitarul idlj din distributia jdk.
Corespondenta ıntre entitatile IDL si Java este data ın Tabelul 4.1
Legarea cererii unui client de codul serviciului care satisface cererea utilizeazacomponenta CORBA Portable Object Adapter (POA).
Model cu server temporal
Exemplificam dezvoltarea unei aplicatii distribuite CORBA ın cazul ın care ser-viciul pus la dispozitie de server este calculul celui mai mare divizor comun a douanumere naturale.
Dezvoltarea unei aplicatii distribuite CORBA cu mediul nativ Java presupuneparcurgerea urmatoarelor pasi:
1. Realizarea interfetei IDL care ınseamna
(a) Editarea programului de interfata:
82 CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANTA
Tip IDL Tip Java
module packageboolean booleanchar, wchar charoctet bytestring, wstring java.lang.Stringshort, unsigned short shortlong, unsigned long intlong long, unsigned long long longfloat floatdouble doublefixed java.math.BigDecimalenum, struct, union classsequence, array arrayinterface (non-abstract) signature interface,
operations interface,helper class, holder class
Any org.omg.CORBA.Any
Table 4.1: Entitati IDL si Java
1 module CmmdcApp{2 interface Cmmdc{3 long long cmmdc( in long long a , in long long b ) ;4 } ;5 } ;
Salvam acest text ıntr-un fisier denumit Cmmdc.idl.
Cmmdc va fi numele serviciului cautat de un client si implementat deserver. Serviciul contine o singura metoda cmmdc.
(b) Translatarea ın Java
idlj -fall Cmmdc.idl
Programul idlj creaza un subcatalog CmmdcApp cu un pachet Java CmmdcApp
continand fisierele:
• Cmmdc.java
• CmmdcPOA.java ;
• CmmdcOperations.java;
4.2. CORBA 83
• CmmdcStub.java;
• CmmdcHelper.java;
• CmmdcHolder.java.
2. Realizarea programelor server. Punem ın evidenta programul servant Cmmd-cImpl.java ce implementeaza interfata Cmmdc.
1 import CmmdcApp . ∗ ;2 import org . omg .CORBA. ∗ ;
4 pub l i c c l a s s CmmdcImpl extends CmmdcPOA {5 p r i v a t e ORB orb ;
7 pub l i c CmmdcImpl(ORB orb ){8 t h i s . orb = orb ;9 }
11 pub l i c long cmmdc( long a , long b ) { . . .}12 }
si programul CmmdcServer.java, care ınscrie ın registrul ORB referintele ser-vantului. Activitatile ce trebuie ıntreprinse sunt declarate prin comentarii ıntextul sursa al programului
1 import CmmdcApp . ∗ ;2 import org . omg . CosNaming . ∗ ;3 import org . omg . CosNaming . NamingContextPackage . ∗ ;4 import org . omg .CORBA. ∗ ;5 import org . omg . Por tab l eServer . ∗ ;
7 pub l i c c l a s s CmmdcServer {8 pub l i c s t a t i c void main ( S t r ing args [ ] ) {9 t ry {
10 // c r ea r ea s i i n i t i a l i z a r e a ORB11 ORB orb = ORB. i n i t ( args , n u l l ) ;
13 // obt ine r ea unei r e f e r i n t e rootpoa s i a c t i v a r e a managerului POAManager14 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” ) ) ;15 rootpoa . the POAManager ( ) . a c t i v a t e ( ) ;
17 // c r ea r ea unui se rvant18 CmmdcImpl cmmdcImpl = new CmmdcImpl( orb ) ;
20 // obt ine r ea unei r e f e r i n t e a s e r v a n t u l u i21 org . omg .CORBA. Object r e f = rootpoa . s e r v a n t t o r e f e r e n c e ( cmmdcImpl ) ;22 Cmmdc h r e f = CmmdcHelper . narrow ( r e f ) ;
24 // Obtinerea s e r v i c i u l u i NameService25 org . omg .CORBA. Object objRef =26 orb . r e s o l v e i n i t i a l r e f e r e n c e s ( ”NameService” ) ;27 NamingContextExt ncRef = NamingContextExtHelper . narrow ( objRef ) ;
29 // l e g a r e a r e f e r i n t e i s e r v a n t u l u i in s e r v i c i u l NameService30 St r ing name = ”CmmdcService” ;31 NameComponent path [ ] = ncRef . to name ( name ) ;32 ncRef . reb ind ( path , h r e f ) ;
84 CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANTA
34 System . out . p r i n t l n ( ”CmmdcServer ready and wai t ing . . . ” ) ;
36 // in a s t ep ta r ea c l i e n t i l o r37 orb . run ( ) ;38 }39 catch ( Exception e ) {40 System . e r r . p r i n t l n ( ”ERROR: ” + e ) ;41 e . pr intStackTrace ( System . out ) ;42 }43 System . out . p r i n t l n ( ”CmmdcServer Ex i t ing . . . ” ) ;44 }45 }
3. Realizarea programului client CmmdcClient.java:
1 import CmmdcApp . ∗ ;2 import org . omg . CosNaming . ∗ ;3 import org . omg . CosNaming . NamingContextPackage . ∗ ;4 import org . omg .CORBA. ∗ ;5 import java . u t i l . Scanner ;
7 pub l i c c l a s s CmmdcClient{8 s t a t i c Cmmdc cmmdcImpl ;
10 pub l i c s t a t i c void main ( St r ing args [ ] ) {11 t ry {12 // c r ea r ea s i i n i t i a l i z a r e a unui r eprezentant ORB13 ORB orb = ORB. i n i t ( args , n u l l ) ;
15 // obt ine r ea unei r e f e r i n t e pentru s e r v i c i u l denumir i l o r16 // s e r v i c i i l o r i n r e g i s t r a t e17 org . omg .CORBA. Object objRef =18 orb . r e s o l v e i n i t i a l r e f e r e n c e s ( ”NameService” ) ;19 NamingContextExt ncRef = NamingContextExtHelper . narrow ( objRef ) ;
21 // obt ine r ea unei r e f e r i n t e l a s e r v i c i u l d o r i t22 St r ing name = ”CmmdcService” ;23 cmmdcImpl = CmmdcHelper . narrow ( ncRef . r e s o l v e s t r (name ) ) ;
25 System . out . p r i n t l n ( ”Obtained a handle on s e r v e r o b j e c t : ” + cmmdcImpl ) ;26 Scanner scanner=new Scanner ( System . in ) ;27 long m, n ;28 System . out . p r i n t l n ( ”m=” ) ;29 m=scanner . nextLong ( ) ;30 System . out . p r i n t l n ( ”n=” ) ;31 n=scanner . nextLong ( ) ;32 System . out . p r i n t l n ( ”Cmmdc=”+cmmdcImpl . cmmdc(m, n ) ) ;33 }34 catch ( Exception e ) {35 System . out . p r i n t l n ( ”ERROR : ” + e ) ;36 e . pr intStackTrace ( System . out ) ;37 }38 }39 }
Programele se compileaza
4.2. CORBA 85
javac CmmdcApp\*.java
4. Pornirea serviciului de intregistrare a numelor cu programul orbd.exe dindistributia jdk.
start orbd -ORBInitialHost localhost -ORBInitialPort 1050
5. Pornirea programului server prin
start java CmmdcServer -ORBInitialHost localhost -ORBInitialPort 1050
6. Lansarea programului client prin
java CmmdcClient -ORBInitialHost localhost -ORBInitialPort 1050
Model cu server persistent
Se considera aceasi interfata Cmmdc.idl.Partea de server este alcatuita din clasa servant CmmdcImpl.java care imple-
menteaza interfata Cmmdc -prezentat ın sectiunea anterioara si clasa PersistentServercare asigura
• legatura cu serviciile ORB;
• accesul la clasa servantului.
1 import java . u t i l . P r o p e r t i e s ;2 import org . omg .CORBA. ∗ ;3 import org . omg . CosNaming . ∗ ;4 import org . omg . Por tab l eServer . ∗ ;
6 pub l i c c l a s s P e r s i s t e n t S e r v e r {7 pub l i c s t a t i c void main ( St r ing args [ ] ) {8 P r o p e r t i e s p r o p e r t i e s = System . g e t P r o p e r t i e s ( ) ;9 p r o p e r t i e s . put ( ” org . omg .CORBA. ORBInitialHost ” , ” l o c a l h o s t ” ) ;
10 p r o p e r t i e s . put ( ” org . omg .CORBA. ORBInit ia lPort ” , ”1050” ) ;11 t ry {12 // Pas 1 : I n s t a n t i e r e ORB13 ORB orb = ORB. i n i t ( args , p r o p e r t i e s ) ;
15 // Pas 2 : I n s t a n t i e r e a s e r v a n t u l u i16 CmmdcImpl se rvant = new CmmdcImpl( orb ) ;
18 // Pas3 3 : Crearea unui o b i e c t POA cu s e c u r i t a t e a P e r s i s t e n t Po l i cy19 // ∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗20 // Pas 3−1 : Obtinerea r a d a c i n i i rootPOA
86 CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANTA
21 POA rootPOA = POAHelper . narrow ( orb . r e s o l v e i n i t i a l r e f e r e n c e s ( ”RootPOA” ) ) ;22 // Pas 3−2 : Create s e c u r i t a t i i P e r s i s t e n t Po l i cy23 Pol i cy [ ] p e r s i s t e n t P o l i c y = new Po l i cy [ 1 ] ;24 p e r s i s t e n t P o l i c y [ 0 ] = rootPOA . c r e a t e l i f e s p a n p o l i c y (25 Li f e spanPo l i cyVa lue .PERSISTENT) ;26 // Pas 3−3 : Crearea o b i e c t u l u i POA cu s e c u r i t a t e a the P e r s i s t e n t Po l i cy27 POA persistentPOA = rootPOA . create POA ( ”childPOA” , nu l l , p e r s i s t e n t P o l i c y ) ;28 // Pas 3−4 : Act ivarea managerului PersistentPOA POAManager ,29 persistentPOA . the POAManager ( ) . a c t i v a t e ( ) ;30 // ∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗
32 // Pas 4 : Asoc i e rea s e r v a n t u l u i cu PersistentPOA33 persistentPOA . a c t i v a t e o b j e c t ( se rvant ) ;
35 // Pas 5 : Fixarea 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 i36 // Numele s e r v i c i u l u i ORBD : ’ NameService ’37 // Numele s e r v a n t u l u i ’ PersistentCmmdcServer ’
39 org . omg .CORBA. Object obj = orb . r e s o l v e i n i t i a l r e f e r e n c e s ( ”NameService” ) ;40 NamingContextExt rootContext = NamingContextExtHelper . narrow ( obj ) ;41 NameComponent [ ] nc = rootContext . to name ( ” PersistentCmmdcServer ” ) ;42 rootContext . reb ind ( nc , persistentPOA . s e r v a n t t o r e f e r e n c e ( se rvant ) ) ;
44 // Pas 6 : Gata pentru r e c e p t i a c e r e r i l o r c l i e n t i l o r45 orb . run ( ) ;46 }47 catch ( Exception e ) {48 System . e r r . p r i n t l n ( ” Exception in P e r s i s t e n t Server Startup ” + e ) ;49 }50 }51 }
Programul client
1 import java . u t i l . P r o p e r t i e s ;2 import org . omg .CORBA. ∗ ;3 import org . omg . CosNaming . ∗ ;4 import org . omg . Por tab l eServer .POA;
6 import CmmdcApp. CmmdcHelper ;7 import CmmdcApp.Cmmdc;8 import java . u t i l . Scanner ;
10 pub l i c c l a s s P e r s i s t e n t C l i e n t {11 pub l i c s t a t i c void main ( S t r ing args [ ] ) {12 St r ing host=” l o c a l h o s t ” ;13 St r ing port=”1050” ;14 i f ( a rgs . length >0)15 host=args [ 0 ] ;16 i f ( a rgs . length >1)17 port=args [ 1 ] ;18 t ry {19 // Pas 1 : I n i t i a l i z a r e ORB20 ORB orb = ORB. i n i t ( args , n u l l ) ;
22 // Pas 2 : Rezolvarea p e r s i s t e n t e i23 // S e r v i c i u l NameService ru l ea za pe host cu por tu l port24 // Numele s e r v i c i u l u i c e rut l u i NameService e s t e25 // ” PersistentCmmdcServer ”26 org . omg .CORBA. Object obj = orb . s t r i n g t o o b j e c t (
4.2. CORBA 87
27 ” corbaname: : ”+host+” : ”+port+”#PersistentCmmdcServer ” ) ;28 Cmmdc cmmdc=CmmdcHelper . narrow ( obj ) ;
30 // Pas 3 : U t i l i z a r e a s e r v i c i u l u i31 Scanner scanner=new Scanner ( System . in ) ;32 System . out . p r i n t l n ( ” Ca l l i ng P e r s i s t e n t Server . . ” ) ;33 i n t m, n , r ;34 System . out . p r i n t l n ( ”m=” ) ;35 m=scanner . next Int ( ) ;36 System . out . p r i n t l n ( ”n=” ) ;37 n=scanner . next Int ( ) ;38 System . out . p r i n t l n (cmmdc . cmmdc(m, n ) ) ;39 }40 catch ( Exception e ) {41 System . e r r . p r i n t l n ( ” Exception in P e r s i s t e n t C l i e n t . java . . . ” + e ) ;42 e . pr intStackTrace ( ) ;43 }44 }45 }
Serverul trebuie sa fie pe acelasi calculator pe care ruleaza orbd. Executareaaplicatiei presupune:
1. Pornirea serviciului de intregistrare a numelor cu programul orbd.exe dindistributia jdk.
start orbd -ORBInitialPort 1050 -serverPollingTime 200
2. Activarea serverului:
(a) Se lanseaza utilitarul servertoolservertool -ORBInitialPort 1050
(b) Se ınregistreaza serverul ımpreuna cu numele serviciului pe care ıl ındeplineste:
servertool > register -server PersistentServer
-applicationName PersistentCmmdcServer
-classpath cale_catre_fisierele_server\
Indeplinirea actiunii de ınregistrare a serverului este indicat printr-un mesajde forma server registered (serverid=257).
Serviciul se sterge prin comandaservertool > unregister -serverid 257
Programul de ınregistrare servertool se ınchide prinservertool > quit
88 CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANTA
3. Executarea clientului
java PersistentClient [hostORB [portORB]]
Capitolul 5
Mesaje ın Java
Comunicatia prin apelul la distanta - inclusiv RMI - este sincron: programulapelant se blocheaza si asteapta ca metoda apelata sa se termine si sa furnizezerezultatul cerut. Cu alte cuvinte apelul de procedura la distanta cere atat clientuluicat si serverului sa fie simultan disponibile.
Comunicatiile asincrone ıntre programe permit realizarea unor sisteme de pro-grame cu un grad mult mai scazut de cuplare. Asemenea aplicatii se pot realizaprin comunicatii de mesaje, mesaje care sunt retinute de un intermediar (serviciude mesagerie, server, broker, messaging middleware).
In prezent protocolul pentru realizarea aplicatiilor bazate pe comunicatii demesaje este Advanced Message Queue Protocol - AMQP. AMQP este un proto-col dezvoltat de mai multe firme bazat pe standardele World Wide Web Consortium(W3C) si Internet Engineering Task Force (IETF) pentru comunicare cu mesaje prinintermediul unui serviciu de mesagerie si care se doreste independent de limbajul deprogramare.
Modelul AMQP ınglobeaza standardul Java Message Servuce - JMS, dezvoltatde Oracle - Sun Microsystems.
Comunicatia se realizeaza prin socluri TCP.
5.1 Java Message Service (JMS)
JMS defineste un cadru de programare Java (API) pentru realizarea aplicatiilorbazate pe comunicatii asincrone. Exista mai multe implementari JMS, dintre caresemnalam:
• Open Message Queue a firmei Oracle. Numele anterior al produsului a fostSun Java System Message Queue
• ActiveMQ realizata de fundatia apache.
• qpid realizata de fundatia apache.
89
90 CAPITOLUL 5. MESAJE IN JAVA
O aplicatie JMS este alcatuita din
• un furnizor JMS (provider JMS) : un sistem de mesagerie ce implementeazaspecificatiile JMS;
• client JMS : aplicatie Java care trimite si receptioneaza mesaje;
• mesaje : obiecte utilizate ın schimbul de informatii de clienti JMS;
• obiecte administrator : obiecte (resurse) create de administrator pentru a fiutilizate de clientii JMS, precum fabrica de conexiuni, obiectele destinatieımpreuna cu resursele lor.
Modele de comunicatie:
• Comunicatii punctuale : Un mesaj este generat de un producator (expeditor)si la care va avea acces un singur consumator (destinatar). Mesajul este depusıntr-o coada, de unde este preluat de catre consumatorul care s-a legat decoada. Daca de coada nu se leaga nici un consumator, atunci mesajul estepastrat ın coada.
• Comunicatii axate pe subiect (topic) : Mesajele sunt depuse (publicate) ındestinatii specifice subiectului. Consumatorii ce au subscris la acel subiectau acces la mesajele respective. Mai multi producatori pot genera mesajespecifice unui subiect, mesaje care pot fi accesate de consumatorii care ausubscris subiectului.
Structura unui mesaj Un mesaj este alcatuit din
• Antet (header) : contine informatii pentru identificarea destinatiei cat si pentruidentificarea mesajului.
• Proprietati : au caracter optional si sunt sub forma (nume, valoare). Pro-prietatile ajuta consumatorii sa selecteze mesajele.
• Corpul mesajului : optional. Potrivit specificatiilor JMS exista 6 tipuri demesaje.
– Message : mesaj fara corp;
– StreamMessage : corpul mesajului contine un flux Java de date de tippredefinit;
– ByteMessage :
– MapMessage : corpul mesajului contine o familie de perechi (nume, val-oare);
– TextMessage : corpul mesajului contine un string;
– ObjectMessage : corpul mesajului contine un obiect serializat.
5.2. OPEN MESSAGE QUEUE 91
5.2 Open Message Queue
Instalarea. Functie de resursa descarcata, ın mediul Windows, instalarea constadin
• Se dezarhiveaza fisierul openmq* *-installer-WINNT.zip si se lanseaza ın executieprogramul de instalare.
• Se dezarhiveaza fisierul openmq* *-binary-WINNT.zip si se fixeaza atributelefisierului mq\etc\imqenv.conf.
Lansarea serviciului JMS. Orice aplicatie JMS necesita functionarea servici-ului JMS. Serviciul JMS se instaleaza prin
imqbrokerd -tty
Optiunea -tty are ca efect afisarea mesajelor pe ecran. Functionarea corecta esteindicata prin mesajul
imqbroker@hostname:7676 ready
Daca se doreste schimbarea portului atunci se foloseste optiunea -port port.
Pe un calculator pot coexista mai multe servicii JMS doar daca folosesc porturidistincte si au nume diferite. In acest caz, lansarea unui nou serviciu se face prin
imqbrokerd -tty -port port -name name
Cu utilitarul imqsvcadmin putem
• dezinstala : imqsvcadmin remove
• verifica : imqsvcadmin query
• instala : imqsvcadmin install
serviciul JMS ca serviciu Windows. Dezinstalarea si instalarea are efect odata curepornirea calculatorului.
Compilarea si executarea unui program necesita completarea variabilei sistemclasspath cu fisierele
• JMS HOME\lib\jms.jar
• JMS HOME\lib\imq.jar
5.3 Apache ActiveMQ
Instalarea se face dezarhivand fisierul descarcat ıntr-un catalog ACTIVEMQ HOME.
Acest fisier este specific sistemului de operare utilizat, Windows sau Linux.
Lansarea serverului JMS se obtine prin
92 CAPITOLUL 5. MESAJE IN JAVA
set JAVA_HOME=. . .
set ACTIVEMQ_HOME=. . .
%ACTIVEMQ_HOME%\bin\activemq
In cazul unui calculator izolat este nevoie de instalarea driver-ului Microsoft loopbackAdaptor care sinuleaza existenta functonarii unei placi de retea active.
Distributia apache-activemq-5.*.* contine, ca exemplu, clasa EmbeddedBroker.javacare lanseaza serverul JMS ın lucru.
Compilarea unui program necesita prezenta ın variabila de sistem classpath areferintei catre fisierul ACTIVEMQ HOME\activemq-all-*.*.*.jar. Pentru executie,variabila de sistem classpath nevoie sa contina referintele catre fisierele jar dincatalogul ACTIVEMQ HOME\lib.
5.4 Elemente de programare - JMS
5.4.1 Trimiterea unui mesaj
Trimiterea unui mesaj necesita:
1. Generarea unei fabrici de conexiuni. Fabrica de conexiuni este un obiect ad-ministrator. Aceasta operatie este specifica distributiei JMS.
• In cazul de fata folosim obiectele create prin MessageQueue.
Se poate obtine prin
ConnectionFactory cf=
new com.sun.messaging.ConnectionFactory();
Clasa com.sun.messaging.ConnectionFactory contine metodasetProperty( String name, String value) prin intermediul careia seprecizeaza calculatorul si portul furnizorului de servicii JMS, fixand atributele"imqBrokerHostName" si respectiv "imqBrokerHostPort".
• Utilizand apache-activemq, fabrica de conexiuni se obtine prin
org.apache.activemq.ActiveMQConnectionFactory cf=
new org.apache.activemq.ActiveMQConnectionFactory
("tcp://host:61616");
2. Generarea conexiunii.
Se realizeaza prin
Connection conn=cf.createConnection();
Pentru realizarea acestui obiectiv se utilizeaza metoda createConnection,
dupa caz, dintr-una din clasele
5.4. ELEMENTE DE PROGRAMARE - JMS 93
class ConnectionFactory{
Connection createConnection() throws JMSException;
Connection createConnection(String userName,String password)
throws JMSException;
}
class QueueConnectionFactory{
QueueConnection createQueueConnection() throws JMSException;
QueueConnection createQueueConnection(String userName,
String password) throws JMSException;
}
class TopicConnectionFactory{
TopicConnection createTopicConnection() throws JMSException;
TopicConnection createTopicConnection(String userName,
String password) throws JMSException;
}
unde Connection, QueueConnection, TopicConnection sunt interfete dinjavax.jms.
Amintim urmatoarele metode ale unei interfete Connection
interface Connection{
Session createSession(boolean transacted,
int acknowledgeMode) throws JMSException;
void start() throws JMSException;
void close() throws JMSException;
}
interface QueueConnection{
QueueSession createQueueSession(boolean transacted,
int acknowledgeMode) throws JMSException;
void start() throws JMSException;
void close() throws JMSException;
}
interface TopicConnection{
TopicSession createTopicSession(boolean transacted,
int acknowledgeMode) throws JMSException;
void start() throws JMSException;
void close() throws JMSException;
}
Un obiect ce implementeaza interfata Connection asigura legatura clientuluicu furnizorul JMS. Acest obiect este creat de fabrica de conexiuni.
94 CAPITOLUL 5. MESAJE IN JAVA
Un client JMS trebuie sa ınchida conexiunile create.
Metoda start() asigura pornirea sau repornirea conexiunii ın vederea receptionariimesajelor sosite.
3. Crearea unei sesiuni de lucru se face cu o metoda createSession().
Session session=conn.createSession(false,
Session.AUTO_ACKNOWLEDGE);
Primul argument asigura (true) sau nu (false) caracterul indivizibil al unitatiide lucru, adica al unei sesiuni.
Al doilea argument indica modul de confirmare al receptarii mesajului.
Un obiect de tip Session defineste un context format dintr-un singur fir deexecutie ın care are loc producerea si consumul de mesaje.
Sunt definite
interface Session{
| MessageProducer createProducer(Destination destination);
| MessageConsumer createConsumer(Destination destination);
| Message createMessage();
| TextMessage createTextMessage();
| TextMessage createTextMessage(String s);
| StreamMessage createStreamMessage();
| MapMessage createMapMessage();
| ObjectMessage createObjectMessage();
| ObjectMessage createObjectMessage(Serializable object);
| BytesMessage createBytesMessage();
| }
|->interface QueueSession{
| QueueSender createQueueSender(Queue queue);
| QueueReceiver createQueueReceiver(Queue queue);
| }
|->interface TopicSession{
TopicPublisher createPublisher(Topic topic);
TopicSubscriber createSubscriber(Topic topic);
TopicSubscriber createDurableSubscriber(Topic topic,
String name);
}
4. Generarea obiectului destinatie.
In cazul comunicatiilor punctuale obiectul destinatie este de tip Queue, iarcrearea se face prin
5.4. ELEMENTE DE PROGRAMARE - JMS 95
Destination numeDestinatie=sesssion.createQueue(String numeCoada)
iar pentru comunicatii axate pe subiect obiectul destinatie, de tip Topic seinstantiaza prin
Destination numeDestinatie=sesssion.createTopic(String numeSubiect)
Sunt definite arborescentele:
interface Destination
|
|->interface Queue
|
|->interface Topic
class Destination implements Destination
|
|->class Queue implements Destination, Queue, Serializable
|
|->class Topic implements Destination, Topic, Serializable
Utilizand Oracle-Sun Java System Message Queue obiecte de tip Queue sauTopic se pot crea si prin
Queue q=new com.sun.messaging.Queue(String numeCoada);
Topic t=new com.sun.messaging.Topic(String numeSubiect);
5. Generarea producatorului de mesaje. Se realizeaza prin
MessageProducer producer=session.createProducer(obiectDestinatie);
Sunt definite interfetele
interface MessageProducer{
void send(Message mesaj);
}
interface QueueSender{
void send(Message mesaj);
}
interface TopicPublisher{
void publish(Message mesaj);
}
96 CAPITOLUL 5. MESAJE IN JAVA
6. Generarea mesajelor. Un mesaj de tip TextMessage se poate crea prin
TextMessage m=session.createTextMessage();
m.setText(string);
7. Expedierea mesajelor se face cu metoda send(...) a producatorului demesaje.
Exemplul 5.4.1 Clasa urmatoare genereaza ıntr-un fir de executie, un numar demesaje de tip TextMessage ıntr-o comunicatie punctuala. Sfarsitul expedierii mesajelorse indica prin generarea unui mesaj de tip Message. Numarul mesajelor este indicatde un parametru al constructorului.
1 import javax . jms . ∗ ;
3 public class MsgSenderT extends Thread{4 int n ;5 St r ing queueName ;
7 MsgSenderT ( St r ing queueName , int n){8 this . queueName=queueName ;9 this . n=n ;
10 }
12 public void run ( ){13 try{14 // Varianta Oracle−Sun Message Queue15 com . sun . messaging . QueueConnectionFactory c f=16 new com . sun . messaging . QueueConnectionFactory ( ) ;
18 // se tProper ty e s t e metoda a c l a s e i19 // com. sun . messaging . QueueConnnectionFactory20 // ce implementeaza i n t e r f a t a QueueConnectionFactory21 // dar nu a i n t e r f e t e i QueueConnectionFactory .22 // c f . se tProper ty (” imqBrokerHostName” ,” hos t ” ) ;23 // c f . se tProper ty (” imqBrokerHostPort ” ,”7676”);
25 // Varianta Apache−MessageQueue26 // org . apache . act ivemq . ActiveMQConnectionFactory c f=27 //new org . apache . act ivemq .28 // ActiveMQConnectionFactory (” tcp :// l o c a l h o s t :61616”) ;29 Connection conn=c f . c reateConnect ion ( ) ;30 Se s s i on s e s s i o n=conn . c r e a t e S e s s i o n ( false , S e s s i on .AUTOACKNOWLEDGE) ;
32 Dest inat i on q=s e s s i o n . createQueue ( queueName ) ;
34 MessageProducer producer=s e s s i o n . c reateProducer ( q ) ;
36 TextMessage m=s e s s i o n . createTextMessage ( ) ;37 for ( int i =0; i<n ; i ++){38 m. setText ( ” He l lo ”+i ) ;39 producer . send (m) ;40 }41 // indicam s f a r s i t u l t r i m i t e r i i mesa je lor
5.4. ELEMENTE DE PROGRAMARE - JMS 97
42 producer . send ( s e s s i o n . createMessage ( ) ) ;43 s e s s i o n . c l o s e ( ) ;44 conn . c l o s e ( ) ;45 }46 catch ( Exception e ){47 System . out . p r i n t l n ( ”JMSException : ”+e . getMessage ( ) ) ;48 }49 System . out . p r i n t l n ( ” Sender f i n i s h e d ” ) ;50 }51 }
5.4.2 Receptia sincrona a unui mesaj
Primele patru actiuni sunt identice cu cele de la trimiterea unui mesaj, adica
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 realizeaza prin
MessageConsumer consumer=session.createConsumer(q);
q desemnand obiectul destinatie.
Sunt definite 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)
• Message receiveNoWait()
98 CAPITOLUL 5. MESAJE IN JAVA
Exemplul 5.4.2 Receptia de tip sincron a mesajelor ıntr-un fir de executie esteefectuat de clasa urmatoare:
1 import javax . jms . ∗ ;
3 public class SyncMsgReceiverT extends Thread{4 St r ing queueName ;
6 SyncMsgReceiverT ( St r ing queueName){7 this . queueName=queueName ;8 }
10 public void run ( ){11 try{12 // Varianta Oracle−Sun Message Queue13 com . sun . messaging . QueueConnectionFactory c f=14 new com . sun . messaging . QueueConnectionFactory ( ) ;15 // se tProper ty e s t e metoda a c l a s e i QueueConnnectionFactory16 // ce implementeaza i n t e r f a t a QueueConnectionFactory17 // dar nu e s t e a i n t e r f e t e i .18 // c f . se tProper ty (” imqBrokerHostName” ,” hos t ” ) ;19 // c f . se tProper ty (” imqBrokerHostPort ” ,”7676”);
21 // Varianta Apache−MessageQueue22 //org . apache . act ivemq . ActiveMQConnectionFactory c f=23 //new org . apache . act ivemq .24 // ActiveMQConnectionFactory (” tcp :// l o c a l h o s t :61616”) ;25 Connection conn=c f . c reateConnect ion ( ) ;26 Se s s i on s e s s i o n=conn . c r e a t e S e s s i o n ( false , S e s s i on .AUTOACKNOWLEDGE) ;27 Dest inat i on q=s e s s i o n . createQueue ( queueName ) ;28 MessageConsumer consumer=s e s s i o n . createConsumer ( q ) ;29 conn . s t a r t ( ) ;30 Message msg=null ;31 while ( ( msg=consumer . r e c e i v e ( ) ) != null ){32 i f (msg instanceof TextMessage ){33 TextMessage m=(TextMessage )msg ;34 System . out . p r i n t l n (m. getText ( ) ) ;35 }36 else37 break ;38 }39 s e s s i o n . c l o s e ( ) ;40 conn . c l o s e ( ) ;41 }42 catch ( Exception e ){43 System . out . p r i n t l n ( ”JMSException : ”+e . getMessage ( ) ) ;44 }45 System . out . p r i n t l n ( ”Consumer f i n i s h e d ” ) ;46 }47 }
Exemplul 5.4.3 Trimiterea si receptia mesajelor se face prin aplicatia
1 class MsgHelloT{2 public stat ic void main ( St r ing [ ] a rgs ){3 int n=3;
5.4. ELEMENTE DE PROGRAMARE - JMS 99
4 St r ing queueName=”MyQueue” ;5 i f ( args . length >0)6 queueName=args [ 0 ] ;7 i f ( args . length >1)8 n=I n t e g e r . pa r s e In t ( args [ 1 ] ) ;9 MsgSenderT sender=new MsgSenderT (queueName , n ) ;
10 SyncMsgReceiverT r e c e i v e r =new SyncMsgReceiverT ( queueName ) ;11 r e c e i v e r . s t a r t ( ) ;12 sender . s t a r t ( ) ;13 }14 }
5.4.3 Receptia asincrona a unui mesaj
Receptia asincrona a mesajelor presupune implementarea interfeteiMessageListener ce contine o singura metoda
public void onMessage(Message mesaj);
care fixeaza prelucrarea mesajului.Metoda MessageConsumer.setMessageListener(MessageListener obj) fixeaza
obiectul ce implementeaza interfata Messagelistener.
Astfel, caracterul asincron consta din faptul ca mesajele sunt preluate de as-cultator - adica obiectul ce implementeaza interfata MessageListener si nu declientul JMS.
Exemplul 5.4.4 In ideea exemplelor anterioare, un consumator de tip asincron almesajelor este dat ın clasa urmatoare:
1 import javax . jms . ∗ ;2 public class AsyncMsgReceiverT extends Thread{3 St r ing queueName ;
5 AsyncMsgReceiverT ( St r ing queueName){6 this . queueName=queueName ;7 }
9 public void run ( ){10 try{11 // Varianta Oracle−Sun Message Queue12 com . sun . messaging . QueueConnectionFactory c f=13 new com . sun . messaging . QueueConnectionFactory ( ) ;14 // se tProper ty e s t e metoda a c l a s e i QueueConnnectionFactory15 // ce implementeaza i n t e r f a t a QueueConnectionFactory16 // dar nu e s t e a i n t e r f e t e i .17 // c f . se tProper ty (” imqBrokerHostName” ,” hos t ” ) ;18 // c f . se tProper ty (” imqBrokerHostPort ” ,”7676”);
20 // Varianta Apache−MessageQueue21 //org . apache . act ivemq . ActiveMQConnectionFactory c f=22 //new org . apache . activemq .23 // ActiveMQConnectionFactory (” tcp :// l o c a l h o s t :61616”) ;
100 CAPITOLUL 5. MESAJE IN JAVA
25 Connection conn=c f . c reateConnect ion ( ) ;26 Se s s i on s e s s i o n=conn . c r e a t e S e s s i o n ( false , S e s s i on .AUTOACKNOWLEDGE) ;27 Dest inat i on q==s e s s i o n . createQueue ( queueName ) ;28 MessageConsumer consumer=s e s s i o n . createConsumer ( q ) ;29 TextLi s tener t e x t L i s t e n e r=new TextLi s tener ( ) ;30 consumer . s e tMessageL i s t ene r ( t e x t L i s t e n e r ) ;31 conn . s t a r t ( ) ;32 t e x t L i s t e n e r . run ( ) ;33 conn . c l o s e ( ) ;34 }35 catch ( Exception e ){36 System . out . p r i n t l n ( e . getMessage ( ) ) ;37 }38 System . out . p r i n t l n ( ”Consumer f i n i s h e d ” ) ;39 }40 }
ımpreuna cu ascultatorul
1 import javax . jms . ∗ ;2 public class TextLi s tener implements MessageListener {3 boolean s f a r s i t=fa l se ;4 public void onMessage ( Message message ){5 i f ( message instanceof TextMessage ){6 TextMessage m=(TextMessage ) message ;7 try{8 System . out . p r i n t l n (m. getText ( ) ) ;9 }
10 catch ( JMSException e ){11 System . out . p r i n t l n ( e . getMessage ( ) ) ;12 }13 }14 else15 s f a r s i t=true ;16 }
18 public void run ( ){19 while ( ! s f a r s i t ) ;20 }21 }
5.4.4 Publicarea mesajelor
Publicarea mesajelor corespunzatoare unui subiect se face asemanator cu trans-miterea mesajelor ın comunicatia punctuala, dar folosind instante ale claselor dedi-cate acestui tip de comunicatie.
Exemplul 5.4.5
1 import javax . jms . ∗ ;
3 public class MsgPublisherT extends Thread{4 int n ;5 St r ing s u b i e c t ;
5.4. ELEMENTE DE PROGRAMARE - JMS 101
7 MsgPublisherT ( St r ing sub iec t , int n){8 this . n=n ;9 this . s u b i e c t=s u b i e c t ;
10 }
12 public void run ( ){13 try{14 // Varianta Oracle−Sun Message Queue15 com . sun . messaging . TopicConnectionFactory c f=16 new com . sun . messaging . TopicConnectionFactory ( ) ;17 // c f . se tProper ty (” imqBrokerHostName” ,” hos t ” ) ;18 // c f . se tProper ty (” imqBrokerHostPort ” ,”7676”);
20 // Varianta Apache−MessageQueue21 // org . apache . activemq . ActiveMQConnectionFactory c f=22 // new org . apache . act ivemq .23 // ActiveMQConnectionFactory (” tcp :// l o c a l h o s t :61616”) ;
25 TopicConnection conn=c f . createTopicConnect ion ( ) ;26 TopicSess ion s e s s i o n =27 conn . c r ea t eTop i cSe s s i on ( false , S e s s i on .AUTOACKNOWLEDGE) ;28 Dest inat i on t = s e s s i o n . c reateTopic ( s u b i e c t ) ;29 MessageProducer producer = s e s s i o n . c reateProducer ( t ) ;
31 //Topic t=new com. sun . messaging . Topic ( s u b i e c t ) ;32 //TopicPub l i sher pu b l i s h e r=se s s i on . c r ea t ePub l i s h e r ( t ) ;
34 TextMessage m=s e s s i o n . createTextMessage ( ) ;35 for ( int i =0; i<n ; i ++){36 m. setText ( ”Despre ”+s u b i e c t+” ”+i ) ;37 producer . send (m) ;38 // pub l i s h e r . pu b l i s h (m) ;39 }40 producer . send ( s e s s i o n . createMessage ( ) ) ;41 // pub l i s h e r . pu b l i s h ( s e s s i on . createMessage ( ) ) ;42 s e s s i o n . c l o s e ( ) ;43 conn . c l o s e ( ) ;44 }45 catch ( Exception e ){46 System . out . p r i n t l n ( ”JMSException : ”+e . getMessage ( ) ) ;47 }48 System . out . p r i n t l n ( ” Pub l i she r f i n i s h e d ” ) ;49 }50 }
Varianta comentata este o solutie specifica implementarii Oracle-Sun Java Sys-tem Message Queue.
5.4.5 Subscrierea si receptia mesajelor
Daca t este obiectul de tip Destination, clientii se aboneaza - subscriu - unuisubiect prin
TopicSubscriber consumer=session.createSubscriber((Topic)t);
102 CAPITOLUL 5. MESAJE IN JAVA
Subscrierea este este valabila atata timp cat clientul este activ. Pentru a primi toatemesajele specifice subiectului, chiar si cand clientul este inactiv, acesta trebuie sa fiedurabil, adica crearea consumatorului sa se faca prin
conn.setClientID("myID");
TopicSubscriber consumer=
session.createDurableSubscriber((Topic)t,"nameClient");
In ambele cazuri, clientul primeste doar mesajele publicate din momentul subscrierii.
Exemplul 5.4.6
1 import javax . jms . ∗ ;
3 public class MsgSubscriberT extends Thread{4 St r ing s u b i e c t ;5 St r ing c l i e n t I D ;6 St r ing cl ientName ;
8 MsgSubscriberT ( St r ing sub iec t , S t r ing c l i en t ID , S t r ing cl ientName ){9 this . s u b i e c t=s u b i e c t ;
10 this . c l i e n t I D=c l i e n t I D ;11 this . c l ientName=clientName ;12 }
14 public void run ( ){15 try{16 // Varianta Oracle−Sun Message Queue17 com . sun . messaging . TopicConnectionFactory c f=18 new com . sun . messaging . TopicConnectionFactory ( ) ;19 // c f . se tProper ty (” imqBrokerHostName” ,” hos t ” ) ;20 // c f . se tProper ty (” imqBrokerHostPort ” ,”7676”);
22 // Varianta Apache−MessageQueue23 //org . apache . act ivemq . ActiveMQConnectionFactory c f=24 //new org . apache . act ivemq .25 // ActiveMQConnectionFactory (” tcp :// l o c a l h o s t :61616”) ;
27 TopicConnection conn=c f . createTopicConnect ion ( ) ;28 conn . s e tC l i en t ID ( c l i e n t I D ) ;29 TopicSess ion s e s s i o n=30 conn . c r ea t eTop i cSe s s i on ( false , S e s s i on .AUTOACKNOWLEDGE) ;31 Dest inat i on t = s e s s i o n . c reateTop ic ( s u b i e c t ) ;32 TopicSubscr iber consumer=33 s e s s i o n . c r ea t eDurab l eSubsc r ibe r ( ( Topic ) t , cl ientName ) ;34 conn . s t a r t ( ) ;35 Message msg=null ;36 while ( ( msg=consumer . r e c e i v e ( ) ) != null ){37 i f (msg instanceof TextMessage ){38 TextMessage m=(TextMessage )msg ;39 System . out . p r i n t l n ( cl ientName+” r e c e i v e d : ”+m. getText ( ) ) ;40 }41 else42 break ;43 }44 s e s s i o n . c l o s e ( ) ;
5.5. MESAJE SOAP PRIN JAVA MESSAGE SERVICE 103
45 conn . c l o s e ( ) ;46 }47 catch ( Exception e ){48 System . out . p r i n t l n ( ”JMSException : ”+e . getMessage ( ) ) ;49 }50 }51 }
Apelarea celor doua activitati se face prin
Exemplul 5.4.7
1 class MsgPS{2 public stat ic void main ( St r ing [ ] a rgs ){3 St r ing s u b i e c t=”JMS” ;4 int n=3,noAbonati =3;5 i f ( args . length >0)6 s u b i e c t=args [ 0 ] ;7 i f ( args . length >1)8 n=I n t e g e r . pa r s e In t ( args [ 1 ] ) ;9 MsgPublisherT p u b l i s h e r=new MsgPublisherT ( sub iec t , n ) ;
10 MsgSubscriberT [ ] abonat=new MsgSubscriberT [ noAbonati ] ;11 p u b l i s h e r . s t a r t ( ) ;12 for ( int i =0; i<noAbonati ; i ++){13 abonat [ i ]=new MsgSubscriberT ( sub i ec t , ”ID”+i , ” id ”+i ) ;14 abonat [ i ] . s t a r t ( ) ;15 }16 }17 }
5.5 Mesaje SOAP prin Java Message Service
Rezultatele acestei sectiuni sunt valabile doar ın cazul pachetului Oracle-SunJava System Message Queue.
5.5.1 SOAP
SOAP - Simple Object Access Protocol - este un protocol de comunicatii ıntreaplicatii. In prezent SOAP este protocolul standard pentru servicii Web prin Inter-net. SOAP este independent de platforma de calcul si de limbajul de programare.
SOAP se bazeaza pe XML (eXtended Markup Language) si este un standardW3C (World Wide Web Consortium).
Executia programelor utilizand resurse SOAP necesita declararea ın variabila desistem classpath a referintei catre saaj-impl.jar.
5.5.2 Mesaje SOAP
Un mesaj SOAP este un document XML constand din
• o ınvelitoare (envelope) care poate contine
104 CAPITOLUL 5. MESAJE IN JAVA
• un numar arbitrar de antete (header);
• un corp (body);
• un numar variabil de obiecte atasate (attachments) MIME (Multipurpose In-ternet Mail Exchange).
Astfel un mesaj SOAP apare sub forma documentului XML
<?xml version="1.0" encoding="UTF-8"?>
<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
<Header/>
<Body>
<Fault/>
</Body>
</Envelope>
Facilitatile Java de manipulare a mesajelor SOAP sunt continute ın pachetuljavax.xml.soap, din distributia jdk.
In acesta sectiune vom crea mesaje SOAP, le transformam ın mesaje JMS pecare le trimitem furnizorului JMS, de unde un client le receptioneaza, dupa caretransforma mesajul JMS ın mesaj SOAP si regaseste datele expediate. Solutia estespecifica implementarii Oracle-Sun Java System Message Queue.
Crearea unui mesaj SOAP
MessageFactory mf=MessageFactory.newInstance();
SOAPMessage soapMsg=mf.createMessage();
Mesajul creat are definita structura de baza a mesajului SOAP: invelitoarea, unantetul si corpul. Aceste elemente pot fi accesate prin
SOAPPart part=soapMsg.getSOAPPart();
SOAPEnvelope envelope=part.getEnvelope();
SOAPHeader header=envelope.getHeader();
SOAPBody body=envelope.getBody();
Completarea corpului unui mesaj SOAP
Generam numele elementului, ”e1” ın cazul exemplului,
Name n1=envelope.createName("e1");
In body un element se poate include, pe baza numelui creat prin
SOAPElement e1=body.addBodyElement(n1);
5.5. MESAJE SOAP PRIN JAVA MESSAGE SERVICE 105
In general, un element se include ın elementul parinte, care pote fi chiar si body, prinmetoda clasei SOAPElement
SOAPElement addChildElement(Name name)
Completam elementul e1 cu un text: ”primul”, prin
e1.addTextNode("primul");
Exemplul 5.5.1 Mesajul SOAP
1 <SOAP−ENV:Envelope2 xmlns:SOAP−ENV=” h t t p : // schemas . xmlsoap . org / soap / enve l ope /”>3 <SOAP−ENV:Header/>4 <SOAP−ENV:Body>5 <e1>6 pr imul7 <e11>8 a l t r e i l e a9 </e11>
10 </e1>11 <e2>12 a l d o i l e a13 </e2>14 </SOAP−ENV:Body>15 </SOAP−ENV:Envelope>
se obtine cu programul
1 import javax . xml . soap . ∗ ;2 import java . i o . ∗ ;
4 public class MsgSOAP{5 public stat ic void main ( St r ing [ ] a rgs ){6 Name name=null ;7 try{8 MessageFactory mf=MessageFactory . newInstance ( ) ;9 SOAPMessage soapMsg=mf . createMessage ( ) ;
10 SOAPPart part=soapMsg . getSOAPPart ( ) ;11 SOAPEnvelope enve lope=part . getEnvelope ( ) ;12 SOAPBody body=enve lope . getBody ( ) ;13 Name n1=enve lope . createName ( ”e1” ) ;14 SOAPElement e1=body . addBodyElement ( n1 ) ;15 e1 . addTextNode ( ” primul ” ) ;16 Name n2=enve lope . createName ( ”e2” ) ;17 SOAPElement e2=body . addBodyElement ( n2 ) ;18 e2 . addTextNode ( ” a l d o i l e a ” ) ;19 Name n11 =enve lope . createName ( ”e11 ” ) ;20 SOAPElement e11=e1 . addChildElement ( n11 ) ;21 e11 . addTextNode ( ” a l t r e i l e a ” ) ;22 FileOutputStream f=new FileOutputStream ( ”MySOAPMessage . xml” ) ;23 soapMsg . writeTo ( f ) ;24 }25 catch ( Exception e ){26 System . out . p r i n t l n ( ” Exception : ”+e . getMessage ( ) ) ;27 }28 }29 }
106 CAPITOLUL 5. MESAJE IN JAVA
Un mesaj SOAP se poate salva ıntr-un fisier text cu
FileOutputStream f=new FileOutputStream(. . .);
soapMsg.writeTo(f);
Transformarea unui mesaj SOAP ın mesaj JMS
SOAPMessage soapMsg=. . .
Message msg=
MessageTransformer.SOAPMessageIntoJMSMessage(soapMsg,session);
Transformarea unui mesaj JMS ın mesaj SOAP
MessageFactory mf=. . .
Message msg=. . .
SOAPMessage soapMsg =
MessageTransformer.SOAPMessageFromJMSMessage(msg,mf);
Preluarea elementelor din corpul unui mesaj SOAP
SOAPBody body=. . .
SOAPBodyElement element=null;
Iterator iterator=body.getChildElements();
while(iterator.hasNext()){
element=(SOAPBodyElement)iterator.next();
String name=element.getElementName();
if(name.getLocalName().equals("numeCamp")){
String s=element.getValue();
. . .
}
}
Exemplul 5.5.2 Un client introduce ıntr-un mesaj SOAP doua numere ıntregi,transmite mesajul altui program care calculeaza cel mai mare divizor comun al celordoua numere si transmite clientului rezultatul tot sub forma unui mesaj SOAP.
Activitatea clientului este se compune din
• Transmiterea catre server a cererii. Mesajul este alcatuit din cele doua numeresi un topic, indicativ dupa care se va gasi raspunsul.
1 import javax . jms . ∗ ;2 import javax . xml . soap . ∗ ;3 import com . sun . messaging . xml . MessageTransformer ;4 import java . u t i l . ∗ ;
6 public class MsgSOAPClientSender{
5.5. MESAJE SOAP PRIN JAVA MESSAGE SERVICE 107
8 long a , b ;9 St r ing top i cRe su l t ;
10 St r ing c l i en t ID , cl ientName ;
12 MsgSOAPClientSender ( S t r ing c l i en t ID , S t r ing cl ientName ){13 this . c l i e n t I D=c l i e n t I D ;14 this . c l ientName=clientName ;15 Scanner scanner=new Scanner ( System . in ) ;16 System . out . p r i n t l n ( ” I n t r o d u c e t i m : ” ) ;17 a=scanner . nextLong ( ) ;18 System . out . p r i n t l n ( ” I n t r o d u c e t i n : ” ) ;19 b=scanner . nextLong ( ) ;20 System . out . p r i n t l n ( ” I n t r o d u c e t i ’ Topic ’−ul ra spunsu lu i ” ) ;21 t op i cRe su l t=scanner . next ( ) ;22 }
24 public void s e r v i c e ( ){25 MessageFactory mf=null ;26 SOAPMessage soapMsg=null ;27 SOAPPart part=null ;28 SOAPEnvelope enve lope=null ;29 SOAPBody body=null ;30 SOAPElement elem=null ;31 Name name=null ;32 try{33 com . sun . messaging . TopicConnectionFactory c f=34 new com . sun . messaging . TopicConnectionFactory ( ) ;35 // c f . se tProper ty (” imqBrokerHostName” ,” a t l a n t i s ” ) ;36 // c f . se tProper ty (” imqBrokerHostPort ” ,”7676”);37 TopicConnection conn=c f . createTopicConnect ion ( ) ;38 conn . s e tC l i en t ID ( c l i e n t I D ) ;39 TopicSess ion s e s s i o n =40 conn . c r ea t eTop i cSe s s i on ( false , S e s s i on .AUTOACKNOWLEDGE) ;41 Dest inat i on tDate=s e s s i o n . c reateTopic ( ”Cmmdc” ) ;42 MessageProducer producer=s e s s i o n . c reateProducer ( tDate ) ;43 mf=MessageFactory . newInstance ( ) ;44 soapMsg=mf . createMessage ( ) ;45 part=soapMsg . getSOAPPart ( ) ;46 enve lope=part . getEnvelope ( ) ;47 body=enve lope . getBody ( ) ;48 name=enve lope . createName ( ”n1” ) ;49 elem=body . addChildElement (name ) ;50 elem . addTextNode ( (new Long ( a ) ) . t oS t r i ng ( ) ) ;51 name=enve lope . createName ( ”n2” ) ;52 elem=body . addChildElement (name ) ;53 elem . addTextNode ( (new Long (b ) ) . t oS t r i ng ( ) ) ;54 name=enve lope . createName ( ” t op i c ” ) ;55 elem=body . addChildElement (name ) ;56 elem . addTextNode ( top i cRe su l t ) ;57 Dest inat i on tResu l t=s e s s i o n . c reateTop ic ( t op i cRe su l t ) ;58 TopicSubscr iber consumer=59 s e s s i o n . c r ea t eDurab l eSubsc r ibe r ( ( Topic ) tResult , cl ientName ) ;60 Message m=61 MessageTransformer . SOAPMessageIntoJMSMessage ( soapMsg , s e s s i o n ) ;62 producer . send (m) ;63 FileOutputStream f=new FileOutputStream ( ”MySOAPMessage . xml” ) ;64 soapMsg . writeTo ( f ) ;65 conn . c l o s e ( ) ;
108 CAPITOLUL 5. MESAJE IN JAVA
66 }67 catch ( Exception e ){68 System . out . p r i n t l n ( ” Exception : ”+e . getMessage ( ) ) ;69 }70 System . out . p r i n t l n ( ” Sender f i n i s h e d ” ) ;71 }
73 public stat ic void main ( St r ing [ ] a rgs ){74 i f ( args . length <2){75 System . out . p r i n t l n ( ”Usage : ” ) ;76 System . out . p r i n t l n ( ” java MsgSOAPClientSender c l i e n t I D clientName ” ) ;77 System . e x i t ( 0 ) ;78 }79 MsgSOAPClientSender c l i e n t=new MsgSOAPClientSender ( args [ 0 ] , a rgs [ 1 ] ) ;80 c l i e n t . s e r v i c e ( ) ;81 }82 }
• Receptionarea raspunsului.
1 import javax . jms . ∗ ;2 import javax . xml . soap . ∗ ;3 import com . sun . messaging . xml . MessageTransformer ;4 import java . u t i l . ∗ ;
6 public class MsgSOAPClientReceiver{
8 St r ing top i cRe su l t ;9 St r ing c l i en t ID , cl ientName ;
11 MsgSOAPClientReceiver ( S t r ing c l i en t ID , S t r ing cl ientName ){12 this . c l i e n t I D=c l i e n t I D ;13 this . c l ientName=clientName ;14 Scanner scanner=new Scanner ( System . in ) ;15 System . out . p r i n t l n ( ” I n t r o d u c e t i ’ Topic ’−ul ra spunsu lu i ” ) ;16 t op i cRe su l t=scanner . next ( ) ;17 }
19 public void s e r v i c e ( ){20 MessageFactory mf=null ;21 SOAPMessage soapMsg=null ;22 SOAPPart part=null ;23 SOAPEnvelope enve lope=null ;24 SOAPBody body=null ;25 SOAPBodyElement element=null ;26 Name name=null ;27 try{28 com . sun . messaging . TopicConnectionFactory c f=29 new com . sun . messaging . TopicConnectionFactory ( ) ;30 // c f . se tProper ty (” imqBrokerHostName” ,” a t l a n t i s ” ) ;31 // c f . se tProper ty (” imqBrokerHostPort ” ,”7676”);32 TopicConnection conn=c f . createTopicConnect ion ( ) ;33 conn . s e tC l i en t ID ( c l i e n t I D ) ;34 TopicSess ion s e s s i o n=conn . c r ea t eTop i cSe s s i on ( false ,35 Se s s i on .AUTOACKNOWLEDGE) ;36 Dest inat i on tResu l t=s e s s i o n . c reateTop ic ( t op i cRe su l t ) ;37 TopicSubscr iber consumer=38 s e s s i o n . c r ea t eDurab l eSubsc r ibe r ( ( Topic ) tResult , cl ientName ) ;39 mf=MessageFactory . newInstance ( ) ;
5.5. MESAJE SOAP PRIN JAVA MESSAGE SERVICE 109
40 conn . s t a r t ( ) ;41 Message msg=consumer . r e c e i v e ( ) ;42 soapMsg=MessageTransformer . SOAPMessageFromJMSMessage (msg , mf ) ;43 System . out . p r i n t l n ( ” C l i en t Mesaj SOAP r e c e p t i o n a t ” ) ;44 part=soapMsg . getSOAPPart ( ) ;45 enve lope=part . getEnvelope ( ) ;46 body=enve lope . getBody ( ) ;47 I t e r a t o r i t e r a t o r=body . getChi ldElements ( ) ;48 St r ing s=”” ;49 while ( i t e r a t o r . hasNext ( ) ){50 element=(SOAPBodyElement) i t e r a t o r . next ( ) ;51 name=element . getElementName ( ) ;52 i f (name . getLocalName ( ) . equa l s ( ”cmmdc” ) )53 s=element . getValue ( ) ;54 }55 System . out . p r i n t l n ( ”Cmmdc: ”+s ) ;56 conn . c l o s e ( ) ;57 }58 catch ( Exception e ){59 System . out . p r i n t l n ( ” Exception : ”+e . getMessage ( ) ) ;60 }61 System . out . p r i n t l n ( ” Rece iver f i n i s h e d ” ) ;62 }
64 public stat ic void main ( St r ing [ ] a rgs ){65 i f ( args . length <2){66 System . out . p r i n t l n ( ”Usage : ” ) ;67 System . out . p r i n t l n ( ” java MsgSOAPClientReceiver c l i e n t I D clientName ” ) ;68 System . e x i t ( 0 ) ;69 }70 MsgSOAPClientReceiver c l i e n t=new MsgSOAPClientReceiver ( args [ 0 ] , a rgs [ 1 ] ) ;71 c l i e n t . s e r v i c e ( ) ;72 }73 }
Programul server este
1 import javax . jms . ∗ ;2 import javax . xml . soap . ∗ ;3 import com . sun . messaging . xml . MessageTransformer ;4 import java . u t i l . I t e r a t o r ;
6 public class MsgSOAPCmmdcServer{
8 long cmmdc( long m, long n ) { . . .}
10 public void s e r v i c e ( ){11 MessageFactory mf=null ;12 SOAPMessage soapMsg=null ;13 SOAPPart part=null ;14 SOAPEnvelope enve lope=null ;15 SOAPBody body=null ;16 SOAPBodyElement element=null ;17 SOAPElement elem=null ;18 Name name=null ;19 try{20 com . sun . messaging . TopicConnectionFactory21 c f=new com . sun . messaging . TopicConnectionFactory ( ) ;22 // c f . se tProper ty (” imqBrokerHostName” ,” a t l a n t i s ” ) ;
110 CAPITOLUL 5. MESAJE IN JAVA
23 // c f . se tProper ty (” imqBrokerHostPort ” ,”7676”);24 TopicConnection conn=c f . createTopicConnect ion ( ) ;25 TopicSess ion s e s s i o n=conn . c r ea t eTop i cSe s s i on ( false ,26 Se s s i on .AUTOACKNOWLEDGE) ;27 Dest inat i on tDate=s e s s i o n . c reateTopic ( ”Cmmdc” ) ;28 TopicSubscr iber consumer=s e s s i o n . c r e a t e S u b s c r i b e r ( ( Topic ) tDate ) ;29 conn . s t a r t ( ) ;30 Message msg=null ;31 mf=MessageFactory . newInstance ( ) ;32 while ( true ){33 msg=consumer . r e c e i v e ( ) ;34 soapMsg=MessageTransformer . SOAPMessageFromJMSMessage (msg , mf ) ;35 System . out . p r i n t l n ( ” Server Mesaj SOAP r e c e p t i o n a t ” ) ;36 part=soapMsg . getSOAPPart ( ) ;37 enve lope=part . getEnvelope ( ) ;38 body=enve lope . getBody ( ) ;39 I t e r a t o r i t e r a t o r=body . getChi ldElements ( ) ;40 St r ing sn1=”” , sn2=”” , t op i cRe su l t=”” ;41 while ( i t e r a t o r . hasNext ( ) ){42 element=(SOAPBodyElement) i t e r a t o r . next ( ) ;43 name=element . getElementName ( ) ;44 i f (name . getLocalName ( ) . equa l s ( ”n1” ) )45 sn1=element . getValue ( ) ;46 i f (name . getLocalName ( ) . equa l s ( ”n2” ) )47 sn2=element . getValue ( ) ;48 i f (name . getLocalName ( ) . equa l s ( ” t op i c ” ) )49 t op i cResu l t=element . getValue ( ) ;50 }51 System . out . p r i n t l n ( sn1+” : ”+sn2+” : ”+top i cRe su l t ) ;52 long a=Long . parseLong ( sn1 ) ;53 long b=Long . parseLong ( sn2 ) ;54 long c=cmmdc( a , b ) ;55 soapMsg=mf . createMessage ( ) ;56 part=soapMsg . getSOAPPart ( ) ;57 enve lope=part . getEnvelope ( ) ;58 body=enve lope . getBody ( ) ;59 name=enve lope . createName ( ”cmmdc” ) ;60 elem=body . addChildElement (name ) ;61 elem . addTextNode ( (new Long ( c ) ) . t oS t r i ng ( ) ) ;62 Message m=63 MessageTransformer . SOAPMessageIntoJMSMessage ( soapMsg , s e s s i o n ) ;64 Dest inat i on tResu l t=s e s s i o n . c reateTop ic ( t op i cRe su l t ) ;65 MessageProducer producer=s e s s i o n . c reateProducer ( tResu l t ) ;66 producer . send (m) ;67 }68 }69 catch ( Exception e ){70 System . out . p r i n t l n ( ” Exception : ”+e . getMessage ( ) ) ;71 }72 System . out . p r i n t l n ( ” Server f i n i s h e d ” ) ;73 }
75 public stat ic void main ( St r ing [ ] a rgs ){76 MsgSOAPCmmdcServer s e r v e r=new MsgSOAPCmmdcServer ( ) ;77 s e r v e r . s e r v i c e ( ) ;78 }79 }
Mesajul SOAP utilizat de client, pentru n1 = 45, n2 = 35 si topic = nume este
5.5. MESAJE SOAP PRIN JAVA MESSAGE SERVICE 111
<soap-env:Envelope
xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/">
<soap-env:Header/>
<soap-env:Body>
<n1>45</n1>
<n2>35</n2>
<topic>nume</topic>
</soap-env:Body>
</soap-env:Envelope>
5.5.3 Atasamente SOAP
Crearea atasamentelor
1. Crearea mesajului SOAP
MessageFactory mf=MessageFactory.newInstance();
SOAPMessage soapMsg=mf.createMessage();
2. • Atasament text
(a) Crearea unui obiect de tip AttachmentPart
AttachmentPart attachment=soapMsg.createAttachmentPart();
(b) Completarea continutuluiString stringContent=. . .
attachment.setContent(stringContent, "text/plain");
Continutului i se poate atasa un cod de identificareattachment.setContentId("Text1");
• Atasament imagine jpeg/png
(a) Crearea unui obiect de tip AttachmentPart cu ıncarcarea imaginii.
URL url=new URL("file://localhost/c:\\. . .\\***.jpg");
DataHandler dataHandler = new DataHandler(url);
AttachmentPart attachment =
soapMsg.createAttachmentPart(dataHandler);
attachment.setContentId("Imagine1");
• Atasament cu sunet ın format mp3.
(a) Crearea unui obiect de tip AttachmentPart cu ıncarcarea fisieruluimp3.
URL url=new URL("file://localhost/c:\\. . .\\***.mp3");
DataHandler dataHandler=new DataHandler(url);
AttachmentPart attachment =
soapMsg.createAttachmentPart(dataHandler);
attachment.setContentId("attached_mp3");
112 CAPITOLUL 5. MESAJE IN JAVA
• Atasament video.
(a) Fisierele video au de obicei dimensiuni mari. Pentru a putea in-clude asemenea fisiere trebuie marita dimensiunea maxima a unuiatasament prin includerea setariiimq.autocreate.destination.maxBytesPerMsg=35M
ın fisierul mq\lib\props\broker\install.properties.
(b) Crearea unui obiect de tip AttachmentPart cu ıncarcarea fisieruluicu 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 continutuluivideo, informatie data de extensia fisierului video. Aceata data estefurnizata prin metoda setContentId.
File videoFile = new File(video_location);
String fileName = videoFile.getName();
int index=fileName.lastIndexOf(".");
String ext=fileName.substring(index+1);
attachment.setContentId("attached_video"+ext);
3. Includerea atasamentului ın mesajul SOAP
soapMsg.addAttachmentPart(attachment);
Extragerea atasamentelor
Tipul unui atasament se poate deduce din rezultatul metodei getContentId saugetContentType a clasei AttachmentPart.
Iterator iterator = soapMsg.getAttachments();
while (iterator.hasNext()) {
AttachmentPart attached =
(AttachmentPart)iterator.next();
// Codul de identificare
String id = attached.getContentId();
// Tipul atasamentului
String type = attached.getContentType();
// Preluarea unui string
if (type.equals("text/plain")) {
Object content = attached.getContent();
5.5. MESAJE SOAP PRIN JAVA MESSAGE SERVICE 113
. . .
}
// Preluarea unei imagini
if (type.equals("image/jpeg")){
Image image=(Image)attached.getContent();
. . .
}
// Preluarea unei inregistrari mp3
if(type.equals("audio/x-wav")){
System.out.println("Play MP3");
MP3Player mp3Player=new MP3Player(attached.getRawContent());
mp3Player.play();
}
// Preluarea continutului video
if(id.startsWith("attached_video")){
String videoFileName = "videoFile."+id.substring(14);
// Salvarea continutului video intr-un fisier local
InputStream inputStream = attached.getRawContent();
File f=new File(videoFileName);
OutputStream out=new FileOutputStream(f);
byte buf[]=new byte[1024];
int len;
while((len=inputStream.read(buf))>0) out.write(buf,0,len);
out.close();
// Redarea continutului video utilizand FMJ
String[]arguments = new String[1];
arguments[0]=URLUtils.createUrlStr(f);
System.out.println("Video show");
FmjStudio.main(arguments);
}
Valoarea rezultata din metoda getContentType ın cazul unui atasament video diferade tipul acesteia. Astfel pentru tipul avi valoarea retunata este application/x-troff-msvideo,iar pentru wmv se obtine content/unknown. Redarea continutului video se face uti-lizand produsul Free Media for Java - FMJ.
Exemplul 5.5.3 Crearea unui mesaj SOAP cu atasamente text, imagine, muzicamp3 si video. Textul, imaginea, muzica mp3 si continutul video sunt continute ınfisiere. Caile catre aceste fisiere se vor da ca proprietati.
114 CAPITOLUL 5. MESAJE IN JAVA
1 import javax . jms . ∗ ;2 import javax . xml . soap . ∗ ;3 import com . sun . messaging . xml . MessageTransformer ;4 import java . i o . ∗ ;5 import javax . a c t i v a t i o n . DataHandler ;6 import java . net .URL;
8 public class MsgSOAPPublisher extends Thread{
10 St r ing f i l e l o c a t i o n , image locat ion , mp3 locat ion , v i d e o l o c a t i o n ;11 MsgSOAPPublisher ( S t r ing f i l e l o c a t i o n , S t r ing image locat ion ,12 St r ing mp3 locat ion , S t r ing v i d e o l o c a t i o n ){13 this . f i l e l o c a t i o n=f i l e l o c a t i o n ;14 this . image l o ca t i on=image l o ca t i on ;15 this . mp3 locat ion=mp3 locat ion ;16 this . v i d e o l o c a t i o n=v i d e o l o c a t i o n ;17 }
19 public void run ( ){20 try{21 com . sun . messaging . TopicConnectionFactory c f=22 new com . sun . messaging . TopicConnectionFactory ( ) ;23 // c f . se tProper ty (” imqBrokerHostName” ,” jonathan ”) ;24 // c f . se tProper ty (” imqBrokerHostPort ” ,”7676”);25 TopicConnection conn=c f . createTopicConnect ion ( ) ;26 TopicSess ion s e s s i o n=27 conn . c r ea t eTop i cSe s s i on ( false , S e s s i on .AUTOACKNOWLEDGE) ;28 //Topic t=new com. sun . messaging . Topic (”Date ” ) ;29 //TopicPub l i sher pu b l i s h e r=se s s i on . c r ea t ePub l i s h e r ( t ) ;30 Dest inat i on t=s e s s i o n . c reateTop ic ( ”Date” ) ;31 MessageProducer producer=s e s s i o n . c reateProducer ( t ) ;
33 MessageFactory mf=MessageFactory . newInstance ( ) ;34 SOAPMessage soapMsg=mf . createMessage ( ) ;35 SOAPPart part=soapMsg . getSOAPPart ( ) ;36 SOAPEnvelope enve lope=part . getEnvelope ( ) ;37 SOAPBody body=enve lope . getBody ( ) ;38 Name bodyName=enve lope . createName ( ” v e r i f ” ) ;39 SOAPElement element=body . addBodyElement (bodyName ) ;40 element . addTextNode ( ”MyAttachment” ) ;
42 // Crearea atasamentu lu i de t i p t e x t
44 AttachmentPart attachment1=soapMsg . createAttachmentPart ( ) ;
46 Fi leReader f r = new Fi leReader (new F i l e ( f i l e l o c a t i o n ) ) ;47 BufferedReader br = new BufferedReader ( f r ) ;
49 St r ing s t r ingContent = ”” ;50 St r ing l i n e = br . readLine ( ) ;51 while ( l i n e != null ) {52 s t r ingContent = str ingContent . concat ( l i n e ) ;53 s t r ingContent = str ingContent . concat ( ”\n” ) ;54 l i n e = br . readLine ( ) ;55 }
57 attachment1 . setContent ( str ingContent , ” t ext / p l a i n ” ) ;58 attachment1 . setContentId ( ” a t ta ched t ex t ” ) ;59 soapMsg . addAttachmentPart ( attachment1 ) ;
5.5. MESAJE SOAP PRIN JAVA MESSAGE SERVICE 115
61 // Crearea atasamentu lu i de t i p imagine62 URL u r l = new URL( ” f i l e : // ”+image l o ca t i on ) ;63 DataHandler dataHandler = new DataHandler ( u r l ) ;64 AttachmentPart attachment2 =65 soapMsg . createAttachmentPart ( dataHandler ) ;
67 attachment2 . setContentId ( ” attached image ” ) ;68 soapMsg . addAttachmentPart ( attachment2 ) ;
70 // Crearea unui atasament de t i p mp371 u r l=new URL( ” f i l e : // ”+mp3 locat ion ) ;72 dataHandler= new DataHandler ( u r l ) ;73 AttachmentPart attachment3 =74 soapMsg . createAttachmentPart ( dataHandler ) ;
76 attachment3 . setContentId ( ” attached mp3 ” ) ;77 soapMsg . addAttachmentPart ( attachment3 ) ;
79 // Crearea unui atasament v ideo80 u r l=new URL( ” f i l e : // ”+v i d e o l o c a t i o n ) ;81 dataHandler= new DataHandler ( u r l ) ;82 AttachmentPart attachment4 =83 soapMsg . createAttachmentPart ( dataHandler ) ;84 F i l e v i d e o F i l e = new F i l e ( v i d e o l o c a t i o n ) ;85 St r ing f i leName = v i d e o F i l e . getName ( ) ;86 int index=fi leName . la s t IndexOf ( ” . ” ) ;87 St r ing ext=fi leName . s ub s t r i ng ( index +1);88 attachment4 . setContentId ( ” at tached v ideo ”+ext ) ;89 soapMsg . addAttachmentPart ( attachment4 ) ;
91 Message m=92 MessageTransformer . SOAPMessageIntoJMSMessage ( soapMsg , s e s s i o n ) ;93 // pub l i s h e r . pu b l i s h (m) ;94 producer . send (m) ;95 FileOutputStream f=new FileOutputStream ( ”MySOAPMessage . xml” ) ;96 soapMsg . writeTo ( f ) ;97 conn . c l o s e ( ) ;98 }99 catch ( Exception e ){
100 System . out . p r i n t l n ( ” Exception : ”+e . getMessage ( ) ) ;101 }102 System . out . p r i n t l n ( ” Pub l i she r f i n i s e d ” ) ;103 }104 }
Exemplul 5.5.4 Consumarea unui mesaj SOAP cu atasamente
1 import javax . jms . ∗ ;2 import javax . xml . soap . ∗ ;3 import com . sun . messaging . xml . MessageTransformer ;4 import java . u t i l . I t e r a t o r ;5 import java . i o . ∗ ;6 import java . awt . ∗ ;7 import net . s f . fmj . u t i l i t y . URLUtils ;8 import net . s f . fmj . u i . FmjStudio ;
116 CAPITOLUL 5. MESAJE IN JAVA
10 public class MsgSOAPSubscriber extends Thread{
12 public void run ( ){13 try{14 com . sun . messaging . TopicConnectionFactory c f=15 new com . sun . messaging . TopicConnectionFactory ( ) ;16 // c f . se tProper ty (” imqBrokerHostName” ,” jonathan ”) ;17 // c f . se tProper ty (” imqBrokerHostPort ” ,”7676”);18 TopicConnection conn=c f . createTopicConnect ion ( ) ;19 TopicSess ion s e s s i o n=20 conn . c r ea t eTop i cSe s s i on ( false , S e s s i on .AUTOACKNOWLEDGE) ;21 //Topic t=new com. sun . messaging . Topic (”Date ” ) ;22 Dest inat i on t=s e s s i o n . c reateTop ic ( ”Date” ) ;23 TopicSubscr iber consumer=s e s s i o n . c r e a t e S u b s c r i b e r ( ( Topic ) t ) ;
25 conn . s t a r t ( ) ;26 Message msg=null ;27 MessageFactory mf=MessageFactory . newInstance ( ) ;28 while ( ( msg=consumer . r e c e i v e ( ) ) != null ){29 SOAPMessage soapMsg =30 MessageTransformer . SOAPMessageFromJMSMessage (msg , mf ) ;31 System . out . p r i n t l n ( ”Mesaj SOAP r e c e p t i o n a t ” ) ;32 // Extragerea atasamente lor33 I t e r a t o r i t e r a t o r = soapMsg . getAttachments ( ) ;34 while ( i t e r a t o r . hasNext ( ) ) {35 AttachmentPart attached=(AttachmentPart ) i t e r a t o r . next ( ) ;36 St r ing id = attached . getContentId ( ) ;37 St r ing type = attached . getContentType ( ) ;38 System . out . p r i n t l n ( ”Attachment ” + id +39 ” has content type ” + type ) ;40 i f ( type . equa l s ( ” t ext / p l a i n ” ) ) {41 St r ing content = ( St r ing ) attached . getContent ( ) ;42 System . out . p r i n t l n ( ”Attachment conta in s :\n” + content ) ;43 }44 i f ( type . equa l s ( ” image/ jpeg ” ) ){45 Image image=(Image ) attached . getContent ( ) ;46 ShowImage s=new ShowImage ( image ) ;47 s . show ( ) ;48 }49 i f ( type . equa l s ( ” audio /x−wav” ) ){50 System . out . p r i n t l n ( ”Play MP3” ) ;51 MP3Player mp3Player=new MP3Player ( attached . getRawContent ( ) ) ;52 mp3Player . s t a r t ( ) ;53 }54 i f ( id . s tartsWith ( ” at tached v ideo ” ) ){55 St r ing videoFileName = ” v i d e o F i l e . ”+id . su b s t r i n g ( 1 4 ) ;56 InputStream inputStream = attached . getRawContent ( ) ;57 F i l e f=new F i l e ( videoFileName ) ;58 OutputStream out=new FileOutputStream ( f ) ;59 byte buf [ ]=new byte [ 1 0 2 4 ] ;60 int l en ;61 while ( ( l en=inputStream . read ( buf ))>0) out . wr i t e ( buf , 0 , l en ) ;62 out . c l o s e ( ) ;63 St r ing [ ] arguments = new St r ing [ 1 ] ;64 arguments [0 ]= URLUtils . c r e a t e U r l S t r ( f ) ;65 System . out . p r i n t l n ( ” Press Enter to cont inue ! ” ) ;66 System . in . read ( ) ;67 System . out . p r i n t l n ( ”Video show” ) ;68 FmjStudio . main ( arguments ) ;
5.5. MESAJE SOAP PRIN JAVA MESSAGE SERVICE 117
69 }70 }71 }72 conn . c l o s e ( ) ;73 }74 catch ( Exception e ){75 System . out . p r i n t l n ( ” Exception : ”+e . getMessage ( ) ) ;76 }77 System . out . p r i n t l n ( ” Subsc r ibe r f i n i s h e d ” ) ;78 }79 }
Apelarea celor doua fire de executie se face prin
1 class MsgAttach{2 public stat ic void main ( St r ing [ ] a rgs ){3 St r ing f i l e l o c a t i o n=System . getProperty ( ” f i l e l o c a t i o n ” ) ;4 St r ing image l o ca t i on=System . getProperty ( ” image l o ca t i on ” ) ;5 St r ing mp3 locat ion=System . getProperty ( ” mp3 locat ion ” ) ;6 MsgSOAPPublisher p u b l i s h e r=7 new MsgSOAPPublisher ( f i l e l o c a t i o n , image locat ion , mp3 locat ion ) ;8 MsgSOAPSubscriber s u b s c r i b e r=new MsgSOAPSubscriber ( ) ;9 p u b l i s h e r . s t a r t ( ) ;
10 s u b s c r i b e r . s t a r t ( ) ;11 }12 }
Utilizarea aplicatiei se face prin ant pe structura initiala de cataloage si fisiere
app
|--> resources
| | resursele text, imagine, mp3, video
|--> src
| | MsgAttach.java
| | MsgSOAPPublisher.java
| | MsgSOAPSubscriber.java
| | MP3Player.java
| | ShowImage.java
| logging.properties (din FMJ)
| build.xml
si cu fisierul build.xml
1 <?xml version=” 1 .0 ” encoding=”UTF−8”?>2 <p r o j e c t default=”run” based i r=” . ”>3 <property name=”mq. home” value=” d: /mq”/>4 <property name=” r e s o u r c e s . home” l o c a t i o n=”${ based i r }/ r e s o u r c e s ”/>5 <property name=” fmj . home” l o c a t i o n=” d: /JavaApp/ fmj”/>
7 <path id=” c l a s s p a t h ” >8 <pathelement path=” bu i ld / c l a s s e s ” />9 <pathelement path=”${ fmj . home}/ fmj . j a r ” />
10 < f i l e s e t d i r=”${mq. home}/ l i b ”>11 <i n c l ude name=” ∗ . j a r ”/>12 </ f< i l e s e t>13 < f i l e s e t d i r=”${ fmj . home}/ l i b ”>14 <i n c l ude name=” ∗ . j a r ”/>15 </ f i l e s e t>16 </path>
118 CAPITOLUL 5. MESAJE IN JAVA
18 <t a r g e t name=” i n i t ”>19 <mkdir d i r=” bu i ld ”/>20 <mkdir d i r=” bu i ld / c l a s s e s ”/>21 </ t a r g e t>
23 <t a r g e t name=” compile ” depends=” i n i t ”>24 <javac 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 sp a t h ”25 d e s t d i r=” bu i ld / c l a s s e s ” debug=” yes ” />26 </ t a r g e t>
28 <t a r g e t name=” s e r v e r ”>29 <exec executab l e=”${mq. home}/ bin / imqbrokerd . exe ” d i r=”${mq. home}/ bin ”/>30 </ t a r g e t>
32 <t a r g e t name=”run” depends=” compile ”>33 <java classname=”MsgAttach” c l a s s p a t h r e f=” c l a s s p a t h ”34 f o rk=” yes ” f a i l o n e r r o r=” yes ”>35 <sysproper ty key=” f i l e l o c a t i o n ”36 value=”${ r e s o u r c e s . home}/ c a p i t o l . txt ”/>37 <sysproper ty key=” image l o ca t i on ”38 value=” l o c a l h o s t /${ r e s o u r c e s . home}/xml−p i c . jpg ”/>39 <sysproper ty key=” mp3 locat ion ”40 value=” l o c a l h o s t /${ r e s o u r c e s . home}/Tomjones . mp3”/>41 <sysproper ty key=” v i d e o l o c a t i o n ”42 value=” l o c a l h o s t /${ r e s o u r c e s . home}/ c l o ck . av i ”/>43 <sysproper ty key=” java . l i b r a r y . path”44 value=”${ fmj . home}/ nat ive /win32−x86”/>45 </ java>46 </ t a r g e t>
48 </ p r o j e c t>
Programul de afisare a imaginii
1 import java . awt . ∗ ;2 import java . awt . image . ∗ ;3 import javax . swing . ∗ ;4 import java . i o . ∗ ;5 import javax . imageio . ImageIO ;6 import java . net . ∗ ;
8 c l a s s MyCanvas extends Canvas{9 Image image=n u l l ;
11 MyCanvas( Image image ){12 t h i s . image=image ;13 }
15 pub l i c void pa int ( Graphics g ){16 g . drawImage ( image , 0 , 0 , t h i s ) ;17 }18 }
20 pub l i c c l a s s ShowImage{21 MyCanvas mc=n u l l ;
23 ShowImage ( Image image ){24 mc=new MyCanvas( image ) ;25 }
5.6. PROGRAME JMS PRIN APACHE-QPID 119
27 pub l i c void show (){28 // I n t e r f a t a swing29 JFrame j f rame = new JFrame ( ”The r e c e i v e d image” ) ;30 j f rame . addNoti fy ( ) ;31 j f rame . getContentPane ( ) . setLayout (new BorderLayout ( ) ) ;32 j f rame . getContentPane ( ) . add (mc, BorderLayout .CENTER) ;33 j f rame . s e tDe fau l tC lo seOperat ion ( JFrame .EXIT ON CLOSE ) ;34 j f rame . s e t S i z e ( 20 0 , 20 0 ) ;35 j f rame . s e t V i s i b l e ( t rue ) ;36 }37 }
Programul pentru redarea continutului unui fisier mp3 necesita prezenta resurseijl1.0.jar din pachetul JLayer1.0, descarcabil din internet. Un program de redare este
1 import java . i o . ∗ ;2 import javazoom . j l . p l aye r . Player ;
4 pub l i c c l a s s MP3Player extends Thread{5 p r i v a t e Player p laye r ;
7 pub l i c MP3Player ( InputStream i s ) {8 t ry {9 BufferedInputStream b i s=new BufferedInputStream ( i s ) ;
10 p laye r=new Player ( b i s ) ;11 }12 catch ( Exception e ){13 System . out . p r i n t l n ( e . getMessage ( ) ) ;14 System . e x i t ( 1 ) ;15 }16 }
18 pub l i c void run ( ){19 t ry {20 p laye r . play ( ) ;21 }22 catch ( Exception e ){23 System . out . p r i n t l n ( e . getMessage ( ) ) ;24 }25 i f ( p l aye r != n u l l ) p laye r . c l o s e ( ) ;26 }27 }
5.6 Programe JMS prin apache-qpid
apache-qpid reprezinta o implementare a protocolului AMQP care poate fi folositde clienti Java, C++, C#, Pyton, Ruby. Programele dezvoltate utilizand Oracle-Sun Java System Message Queue sau apache-ActiveMQ se ruleaza (aproape) faramodificari. Acest fapt dorim sa-l prezentam ın continuare.
Instalarea serviciului de mesagerie revine la
1. Dezarhivarea fisierului descarcat;
120 CAPITOLUL 5. MESAJE IN JAVA
2. Generarea unei semnaturi.
Catalogul QPID HOME\bin contine fisierul create-example-ssl-stores.bat, carese adapteaza corespunzator iar semnatura generata se depune ın catalogulQPID HOME\etc.
Urmatorul exemplu creaza semnatura data de fisierul qpid.keystore.
1 @REM Create example keys to r e f o r broker and2 @REM t r u s t s t o r e f o r c l i e n t /management conso l e .3 @REM4 @REM Use generated qpid . keys to r e as the broker s keys to r e5 @REM Use generated qpid . t r u s t s t o r e as c l i e n t / c o n s o l e s t r u s t s t o r e6 @REM Al l passwords have v a l u e : password
8 @REM Create Broker Keystore :9 keytoo l −genkey −a l i a s qpidBroker −keya lg RSA −v a l i d i t y 365
10 −keys to r e qpid . keys to r e −s t o r e p a s s password −keypass password11 −dname ”CN=unitbv , OU=cs , O=Org , L=Bv , C=R”
13 @REM Export S e l f Signed Cer t :14 keytoo l −export −a l i a s qpidBroker −keys to r e qpid . keys to r e15 − f i l e qpidBroker . c e r −s t o r e p a s s password
17 @REM Import Broker Cert Into MC Trus tS to r e :18 keytoo l −import −a l i a s qpidBrokerCert − f i l e qpidBroker . c e r19 −keys to r e qpid . t r u s t s t o r e −s t o r e p a s s password −noprompt
21 @REM Delete the c e r t22 de l qpidBroker . c e r
Eventual trebuie fixata locatia fisierului qpid.keystore ın elementul keyStorePathdin fisierul QPID HOME\etc\config.xml.
Serviciul de mesagerie se lanseaza prin
1 s e t JAVA HOME=. . .2 s e t QPID HOME=. . .3 s e t QPID WORK=. . .4 %QPID HOME%\bin \qpid−s e r v e r . bat
Catalogul QPID WORK este utilizat de serviciul de mesagerie pentru consemnarea(logging) evenimentelor, ın catalog fiind prezent un fisier de configurare log4j.xml.
Reluam aplicatiile anterioare privind transmiterea / receptia unui mesaj princomunicatie punctuala utilizand o coada si publicarea si receptionarea unui mesajprin comunicatie bazata pe subiect ıntr-o varianta independententa de suportul mid-dleware de serviciu de mesagerie folosit. Regasirea resurselor gestionate de serviciulde mesagerie sa va face utilizand JNDI. De data asta informatiile necesare regasiriiresurselor sunt dependente de serviciul de mesagerie. Datele de regasire sunt fixateıntr-un fisier jndi.properties1.
1Aplicatiile pot fi executate utilizand oricare din implementarile JMS, schimband doar fisieruljndi.properties.
5.6. PROGRAME JMS PRIN APACHE-QPID 121
Comunicatia prin coada - queue
Aplicatia este alcatuita din clasele MsgHelloT, MsgSenderT, SyncMsgReceiverT,AsyncMsgReceiverT, TextListener. Fata de versiunea prezentata se modifica doarclasele MsgSenderT, SyncMsgReceiverT, AsyncMsgReceiverT.
In clasa MsgHelloT campul queueName reprezinta numele JNDI al cozii.Clasa MsgSenderT
1 import javax . jms . ∗ ;2 import javax . naming . ∗ ;3 import java . u t i l . P r o p e r t i e s ;4 import java . i o . ∗ ;
6 public class MsgSenderT extends Thread{7 f ina l St r ing CONNECTION JNDI NAME = ” ConnectionFactory ” ;8 St r ing QUEUE JNDI NAME = ”queue” ;9 private I n i t i a l C o n t e x t ctx ;
10 private int n ;
12 MsgSenderT ( St r ing queueName , int n){13 QUEUE JNDI NAME=queueName ;14 this . n=n ;15 }
17 public void run ( ){18 try{19 setupJNDI ( ) ;20 // lookup the connect ion f a c t o r y21 QueueConnectionFactory c f=22 ( QueueConnectionFactory ) ctx . lookup (CONNECTION JNDI NAME) ;23 Connection conn=c f . c reateConnect ion ( ) ;24 Se s s i on s e s s i o n=conn . c r e a t e S e s s i o n ( false , S e s s i on .AUTOACKNOWLEDGE) ;25 Dest inat i on q=( Des t inat i on ) ctx . lookup (QUEUE JNDI NAME) ;26 closeJNDI ( ) ;27 MessageProducer producer=s e s s i o n . c reateProducer ( q ) ;
29 TextMessage m=s e s s i o n . createTextMessage ( ) ;30 for ( int i =0; i<n ; i ++){31 m. setText ( ” He l lo ”+i ) ;32 producer . send (m) ;33 }34 producer . send ( s e s s i o n . createMessage ( ) ) ;35 s e s s i o n . c l o s e ( ) ;36 conn . c l o s e ( ) ;37 }38 catch ( Exception e ){39 System . out . p r i n t l n ( ”JMSException : ”+e . getMessage ( ) ) ;40 }41 System . out . p r i n t l n ( ” Sender f i n i s h e d ” ) ;42 }
44 private void setupJNDI ( ){45 // Set the p r op e r t i e s . . .46 P r o p e r t i e s p r o p e r t i e s = new P r o p e r t i e s ( ) ;47 try{48 p r o p e r t i e s . load ( this . g e tC la s s ( ) . getResourceAsStream ( ” j n d i . p r o p e r t i e s ” ) ) ;49 }50 catch ( IOException e ){
122 CAPITOLUL 5. MESAJE IN JAVA
51 System . out . p r i n t l n ( ”JNDI−Prope r t i e sEr ro r : ”+e . getMessage ( ) ) ;52 }53 // Create the i n i t i a l con tex t54 try{55 ctx = new I n i t i a l C o n t e x t ( p r o p e r t i e s ) ;56 }57 catch ( NamingException e ){58 System . e r r . p r i n t l n ( ” Error Se t t i ng up JNDI Context : ” + e ) ;59 }60 }
62 private void closeJNDI ( ){63 try{64 ctx . c l o s e ( ) ;65 }66 catch ( NamingException e ){67 System . e r r . p r i n t l n ( ”Unable to c l o s e JNDI Context : ” + e ) ;68 }69 }70 }
Clasa SyncMsgReceiverT
1 import javax . jms . ∗ ;2 import javax . naming . ∗ ;3 import java . u t i l . P r o p e r t i e s ;4 import java . i o . ∗ ;
6 public class SyncMsgReceiverT extends Thread{7 f ina l St r ing CONNECTION JNDI NAME = ” ConnectionFactory ” ;8 St r ing QUEUE JNDI NAME = ”queue” ;9 private I n i t i a l C o n t e x t ctx ;
11 SyncMsgReceiverT ( St r ing queueName){12 QUEUE JNDI NAME=queueName ;13 }
15 public void run ( ){16 try{17 setupJNDI ( ) ;18 // lookup the connect ion f a c t o r y19 QueueConnectionFactory c f=20 ( QueueConnectionFactory ) ctx . lookup (CONNECTION JNDI NAME) ;21 Connection conn=c f . c reateConnect ion ( ) ;22 Se s s i on s e s s i o n=conn . c r e a t e S e s s i o n ( false , S e s s i on .AUTOACKNOWLEDGE) ;23 Dest inat i on q=( Des t inat i on ) ctx . lookup (QUEUE JNDI NAME) ;24 closeJNDI ( ) ;
26 MessageConsumer consumer=s e s s i o n . createConsumer ( q ) ;
28 conn . s t a r t ( ) ;29 Message msg=null ;30 while ( ( msg=consumer . r e c e i v e ( ) ) != null ){31 i f (msg instanceof TextMessage ){32 TextMessage m=(TextMessage )msg ;33 System . out . p r i n t l n (m. getText ( ) ) ;34 }35 else {36 break ;37 }
5.6. PROGRAME JMS PRIN APACHE-QPID 123
38 }39 s e s s i o n . c l o s e ( ) ;40 conn . c l o s e ( ) ;41 }42 catch ( Exception e ){43 System . out . p r i n t l n ( ”JMSException : ”+e . getMessage ( ) ) ;44 }45 System . out . p r i n t l n ( ”Consumer f i n i s h e d ” ) ;46 }
48 private void setupJNDI ( ) { . . .}
50 private void closeJNDI ( ) { . . .}
52 }
Comunicatia pe baza de subiect - topic
Aplicatia este alcatuita din clasele MsgPS, MsgPublisherT, MsgSubscriberT.Fata de versiunea prezentata se modifica doar clasele MsgPublisherT, MsgSubscrib-erT.
In clasa MsgPS campul subiect reprezinta numele JNDI atasat topic-ului.Clasa MsgPublisherT
1 import javax . jms . ∗ ;2 import javax . naming . ∗ ;3 import java . u t i l . P r o p e r t i e s ;4 import java . i o . ∗ ;
6 public class MsgPublisherT extends Thread{7 f ina l St r ing CONNECTION JNDI NAME = ” ConnectionFactory ” ;8 St r ing TOPIC JNDI NAME = ” t op i c ” ;9 private I n i t i a l C o n t e x t ctx ;
10 private int n ;
12 MsgPublisherT ( St r ing sub iec t , int n){13 this . n=n ;14 TOPIC JNDI NAME=s u b i e c t ;15 }
17 public void run ( ){18 try{19 setupJNDI ( ) ;20 // lookup the connect ion f a c t o r y21 TopicConnectionFactory c f=22 ( TopicConnectionFactory ) ctx . lookup (CONNECTION JNDI NAME) ;23 TopicConnection conn=c f . createTopicConnect ion ( ) ;24 TopicSess ion s e s s i o n=conn . c r ea t eTop i cSe s s i on ( false ,25 Se s s i on .AUTOACKNOWLEDGE) ;26 Dest inat i on t=( Des t inat i on ) ctx . lookup (TOPIC JNDI NAME ) ;27 closeJNDI ( ) ;
29 MessageProducer producer = s e s s i o n . c reateProducer ( t ) ;30 TextMessage m=s e s s i o n . createTextMessage ( ) ;31 for ( int i =0; i<n ; i ++){32 m. setText ( ”Despre JMS”+” ”+i ) ;
124 CAPITOLUL 5. MESAJE IN JAVA
33 producer . send (m) ;34 }35 producer . send ( s e s s i o n . createMessage ( ) ) ;36 s e s s i o n . c l o s e ( ) ;37 conn . c l o s e ( ) ;38 }39 catch ( Exception e ){40 System . out . p r i n t l n ( ”JMSException : ”+e . getMessage ( ) ) ;41 }42 System . out . p r i n t l n ( ” Pub l i she r f i n i s h e d ” ) ;43 }
45 private void setupJNDI ( ) { . . .}
47 private void closeJNDI ( ) { . . .}
49 }
Clasa MsgSubscriberT
1 javax . jms . ∗ ;2 import javax . naming . ∗ ;3 import java . u t i l . P r o p e r t i e s ;4 import java . i o . ∗ ;
6 public class MsgSubscriberT extends Thread{7 f ina l St r ing CONNECTION JNDI NAME = ” ConnectionFactory ” ;8 St r ing TOPIC JNDI NAME = ” t op i c ” ;9 private I n i t i a l C o n t e x t ctx ;
10 private St r ing c l i e n t I D ;11 private St r ing cl ientName ;
13 MsgSubscriberT ( St r ing sub iec t , S t r ing c l i en t ID , S t r ing cl ientName ){14 TOPIC JNDI NAME=s u b i e c t ;15 this . c l i e n t I D=c l i e n t I D ;16 this . c l ientName=clientName ;17 }
19 public void run ( ){20 try{21 setupJNDI ( ) ;22 // lookup the connect ion f a c t o r y23 TopicConnectionFactory c f =(24 TopicConnectionFactory ) ctx . lookup (CONNECTION JNDI NAME) ;25 TopicConnection conn=c f . createTopicConnect ion ( ) ;26 //conn . se tC l i en t ID ( c l i en t ID ) ;27 TopicSess ion s e s s i o n=conn . c r ea t eTop i cSe s s i on ( false ,28 Se s s i on .AUTOACKNOWLEDGE) ;29 Dest inat i on t=( Des t inat i on ) ctx . lookup (TOPIC JNDI NAME ) ;30 closeJNDI ( ) ;31 //TopicSubscr iber consumer =32 s e s s i o n . c r ea t eDurab l eSubsc r ibe r ( ( Topic ) t , cl ientName ) ;33 TopicSubscr iber consumer=s e s s i o n . c r e a t e S u b s c r i b e r ( ( Topic ) t ) ;
35 conn . s t a r t ( ) ;36 Message msg=null ;37 while ( ( msg=consumer . r e c e i v e ( ) ) != null ){38 i f (msg instanceof TextMessage ){39 TextMessage m=(TextMessage )msg ;40 System . out . p r i n t l n ( cl ientName+” r e c e i v e d : ”+m. getText ( ) ) ;
5.6. PROGRAME JMS PRIN APACHE-QPID 125
41 }42 else43 break ;44 }45 s e s s i o n . c l o s e ( ) ;46 conn . c l o s e ( ) ;47 }48 catch ( Exception e ){49 System . out . p r i n t l n ( ”JMSException : ”+e . getMessage ( ) ) ;50 }51 System . out . p r i n t l n ( ” Subsc r ibe r f i n i s h e d ” ) ;52 }
54 private void setupJNDI ( ) { . . .}
56 private void closeJNDI ( ) { . . .}
58 }
Fisiere JNDI cu datele de regasire
Programele sectiunii anterioare se pot utiliza cu oricare de distributiile JMSOracle-Sun Message Queue, apache-actimemq, qpid.
Fisierele jndi.properties specifice fiecarei distributii suntVarianta qpid :
1 java . naming . f a c t o r y . i n i t i a l =2 org . apache . qpid . j n d i . P r o p e r t i e s F i l e I n i t i a l C o n t e x t F a c t o r y
4 # r e g i s t e r some connect ion f a c t o r i e s5 # connec t i on f a c to ry . [ jndiname ] = [ ConnectionURL ]6 connec t i on f a c to ry . ConnectionFactory =7 amqp:// g u e s t : g u e s t @ c l i e n t i d / t e s t ? b r o k e r l i s t=’ t c p : // l o c a l h o s t : 5 6 7 2 ’
9 # r e g i s t e r some queues in JNDI us ing the form10 # queue . [ jndiName ] = [ physicalName ]11 queue . queue = myqueue
13 # t op i c . [ jndiName ] = [ physicalName ]14 t op i c . t o p i c = mytopic
Varianta ActiveMQ
1 java . naming . f a c t o r y . i n i t i a l =2 org . apache . activemq . j n d i . Act iveMQInit ia lContextFactory
4 # use the f o l l o w i n g property to c o n f i g u r e the d e f a u l t connector5 java . naming . prov ide r . u r l = t c p : // l o c a l h o s t : 6 1 6 1 6
7 # r e g i s t e r some queues in JNDI us ing the form8 # queue . [ jndiName ] = [ physicalName ]9 queue . queue = myqueue
11 # r e g i s t e r some t o p i c s in JNDI us ing the form12 # t op i c . [ jndiName ] = [ physicalName ]13 t op i c . t o p i c = mytopic
126 CAPITOLUL 5. MESAJE IN JAVA
Varianta Oracle-Sun Java System Message Queue
1 java . naming . f a c t o r y . i n i t i a l =2 com . sun . j n d i . f s c o n t e x t . RefFSContextFactory3 java . naming . prov ide r . u r l= f i l e : /// c : /Temp
5 # use the f o l l o w i n g property to c o n f i g u r e the d e f a u l t connector
7 # r e g i s t e r some queues in JNDI us ing the form8 # queue . [ jndiName ] = [ physicalName ]9 queue . queue = myqueue
11 # r e g i s t e r some t o p i c s in JNDI us ing the form12 # t op i c . [ jndiName ] = [ physicalName ]13 t op i c . t o p i c = mytopic
In acest caz este nevoie de crearea ın prealabil a obiectelor corespunzatoare conexi-unii, a cozii (queue) si a subiectului (topic). Aceaste obiecte se creaza cu utilitarulimqobjmgr din distributia Oracle-Sun Java System Message Queue.
Obiectele se pot crea cu fisierul de comenzi:
1 s e t PATH=d: \mq\bin ;%PATH%2 imqobjmgr add −t q f − l ” ConnectionFactory ”3 −j java . naming . prov ide r . u r l= f i l e : /// c : /Temp4 −j java . naming . f a c t o r y . i n i t i a l=com . sun . j n d i . f s c o n t e x t . RefFSContextFactory5 rem imqobjmgr add −t t f − l ” ConnectionFactory ”6 −j java . naming . prov ide r . u r l= f i l e : /// c : /Temp7 −j java . naming . f a c t o r y . i n i t i a l=com . sun . j n d i . f s c o n t e x t . RefFSContextFactory8 imqobjmgr add −t q − l ”queue”9 −j java . naming . prov ide r . u r l= f i l e : /// c : /Temp
10 −j java . naming . f a c t o r y . i n i t i a l=com . sun . j n d i . f s c o n t e x t . RefFSContextFactory11 rem imqobjmgr add −t t − l ” t o p i c ”12 −j java . naming . prov ide r . u r l= f i l e : /// c : /Temp13 −j java . naming . f a c t o r y . i n i t i a l=com . sun . j n d i . f s c o n t e x t . RefFSContextFactory
Obiectele se pot sterge cu fisierul de comenzi:
1 s e t PATH=d: \mq\bin ;%PATH%2 imqobjmgr d e l e t e −t q f − l ” ConnectionFactory ”3 −j java . naming . prov ide r . u r l= f i l e : /// c : /Temp4 −j java . naming . f a c t o r y . i n i t i a l=com . sun . j n d i . f s c o n t e x t . RefFSContextFactory5 imqobjmgr d e l e t e −t t f − l ” ConnectionFactory ”6 −j java . naming . prov ide r . u r l= f i l e : /// c : /Temp7 −j java . naming . f a c t o r y . i n i t i a l=com . sun . j n d i . f s c o n t e x t . RefFSContextFactory8 imqobjmgr d e l e t e −t q − l ”queue”9 −j java . naming . prov ide r . u r l= f i l e : /// c : /Temp
10 −j java . naming . f a c t o r y . i n i t i a l=com . sun . j n d i . f s c o n t e x t . RefFSContextFactory11 imqobjmgr d e l e t e −t t − l ” t o p i c ”12 −j java . naming . prov ide r . u r l= f i l e : /// c : /Temp13 −j java . naming . f a c t o r y . i n i t i a l=com . sun . j n d i . f s c o n t e x t . RefFSContextFactory
5.7 Protocolul AMQP
Punem ın evidenta un alt model de aplicatie, specific protocolului AMQP.Modelul prevede existenta a trei entitati:
5.7. PROTOCOLUL AMQP 127
• exchange – Dispecer de directionare ce primeste mesaje de la un producatorde mesaje si le distribuie unor cozi pe baza unui criteriu;
• message queue – coada ın care se pastreaza mesaje pana ce acestea sunt con-sumate de o aplicatie client.
Proprietatile unei cozi sunt:
– numele, alcatuit din litere, cifre, caracterul de subliniere, cel mult 255 decaracter.
– persistenta mesajului ın cazul ıncetarii functionarii serverului (durablemessage queue, temporary message queue).
– modul de stergere a mesajelor dupa consumarea acestora (auto-delete).
• binding – criteriul dupa care un mesaj este distribuit de dispecerul de mesajeunei cozi.
O coada comunica dispecerului de directionare o cheie denumita cheie de legare(binding key) K, ın timp ce orice mesaj va contine o cheie de rutare (routing key)R.
AMPQ defineste trei criterii de distribuire a mesajelor de catre dispecerul dedirectionare:
• distribuirea directa realizeaza o distribuire 1:1 a mesajelor:
1. o coada se leaga de dispecerul de directionare cu cheia de legare K;
2. un mesaj contine cheia de rutare R;
3. dispecerul de directionare trimite mesajul catre toate cozile care satisfacconditia R = K.
• distribuirea fanout realizeaza o distribuire 1:N a mesajelor:
1. o coada se leaga de dispecerul de directionare fara cheie de legare;
2. un mesaj nu contine cheie de rutare (eventual cheia de rutare este negli-jata);
3. dispecerul de directionare trimite neconditional mesajul catre toate cozileınregistrate.
• distribuirea publicare-abonare
1. o coada se leaga de dispecerul de directionare cu cheia de legare K;
2. un mesaj contine cheia de rutare R;
128 CAPITOLUL 5. MESAJE IN JAVA
3. dispecerul de directionare trimite mesajul catre toate cozile a caror cheiede legare se potriveste cu cheia de rutare.
Cheia de legare este alcatuita din mai multe cuvinte (token) separate decaracterul ’.’ (punct). Cheia de rutare poate contine caracterele
– # - va presupune potrivirea cu un cuvant sau nu.
– * - va presupune potrivirea cu cel putin un cuvant.
Astfel *.abc se potriveste cu x.abc dar nu se potriveste cu abc, ın timpce #.abc se potriveste cu x.abc si abc.
Corespunzator celor trei criterii de distribuire a mesajelor, serverul AMQP continedispecerii de directionare
• amq.direct
• amq.fanout
• amq.topic
Un mesaj este expediat de client catre un dispecer de directionare aflat pe unserver AMQP. Preluarea unui mesaj dintr-o coada de catre un client are ca urmarestergerea mesajului ın coada.
Resursele necesare apartin pachetului org.apache.qpid.transport.
5.7.1 Crearea unei cozi
Crearea unei cozi consta din
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. Declararea cozii
session.queueDeclare(numeCoada, null, null);
session.exchangeBind(numeCoada, dispecerulDeDirectionare,
binding_key, null);
4. Asteptarea confirmarii actiunii de realizare a cozii
5.7. PROTOCOLUL AMQP 129
session.sync();
5. Inchiderea sesiunii si a conexiunii
session.close();
con.close();
Exemplul 5.7.1 Crearea unei cozi care sa primeasca mesaje prin distribuire directasi fanout.
1 import org . apache . qpid . t r anspo r t . ∗ ;
3 public class DeclareQueue{4 public stat ic void main ( St r ing [ ] a rgs ){5 i f ( args . length <5){6 System . out . p r i n t l n ( ”Usage java DeclareQueue broker ” +7 ” port queueName exchange bindingKey ” ) ;8 System . e x i t ( 1 ) ;9 }
10 St r ing broker=args [ 0 ] ;11 int port=I n t e g e r . pa r s e In t ( args [ 1 ] ) ;12 St r ing queueName=args [ 2 ] ;13 St r ing exchange=args [ 3 ] ;14 St r ing bindingKey=args [ 4 ] ;
16 // Crearea conex iun i i17 Connection con = new Connection ( ) ;18 con . connect ( broker , port , ” t e s t ” , ” guest ” , ” guest ” , fa l se ) ;
20 // Crearea s e s i u n i i21 Se s s i on s e s s i o n = con . c r e a t e S e s s i o n ( 0 ) ;
23 // Declararea c o z i i24 s e s s i o n . queueDeclare (queueName , null , null ) ;25 s e s s i o n . exchangeBind (queueName , exchange , bindingKey , null ) ;
27 // Confirmarea c r e e r i i c o z i i28 s e s s i o n . sync ( ) ;
30 // Inch iderea s e s i u n i i s i a conex iun i i31 s e s s i o n . c l o s e ( ) ;32 con . c l o s e ( ) ;33 }34 }
5.7.2 Expedierea / publicarea unui mesaj
Expedierea / publicarea unui mesaj consta din
1. Realizarea conexiunii cu serverul AMQP
Connection con = new Connection();
con.connect(broker,port,login,passworg,clientId,false);
130 CAPITOLUL 5. MESAJE IN JAVA
2. Instantierea sesiunii
Session session = con.createSession(0);
3. Precizarea (daca este nevoie) a cheii de rutare
DeliveryProperties deliveryProps = new DeliveryProperties();
deliveryProps.setRoutingKey(routing_key);
4. Crearea si expedierea mesajului
session.messageTransfer(dispecerulDeDirectionare,
MessageAcceptMode.EXPLICIT,
MessageAcquireMode.PRE_ACQUIRED,
new Header(deliveryProps),
mesaj_text);
5. Asteptarea confirmarii receptiei mesajului decatre serverul AMQP
session.sync();
6. Inchiderea sesiunii si a conexiunii
session.close();
con.close();
Exemplul 5.7.2 Expedierea unui numar de mesaje cu continut text, urmat de unmesaj fara continut, fapt care marcheaza sfarsitul trimiterii de date.
1 import org . apache . qpid . t r anspo r t . ∗ ;
3 public class Sender{4 public stat ic void main ( St r ing [ ] a rgs ){5 i f ( args . length <5){6 System . out . p r i n t l n ( ”Usage java Sender broker port ” +7 ” exchange routingKey messagesNumber” ) ;8 System . e x i t ( 1 ) ;9 }
10 St r ing broker=args [ 0 ] ;11 int port=I n t e g e r . pa r s e In t ( args [ 1 ] ) ;12 St r ing exchange=args [ 2 ] ;13 St r ing routingKey=args [ 3 ] ;14 int n=I n t e g e r . pa r s e In t ( args [ 4 ] ) ;
16 // Crearea conex iun i i17 Connection con = new Connection ( ) ;18 con . connect ( broker , port , ” t e s t ” , ” guest ” , ” guest ” , fa l se ) ;
5.7. PROTOCOLUL AMQP 131
20 // Crearea s e s i u n i i21 Se s s i on s e s s i o n = con . c r e a t e S e s s i o n ( 0 ) ;
23 // Prec izarea ( daca e s t e nevoie ) a c h e i i de ru tare24 D e l i v e r y P r o p e r t i e s de l i v e ryProps = new D e l i v e r y P r o p e r t i e s ( ) ;25 de l i ve ryProps . setRoutingKey ( routingKey ) ;
27 // Formarea s i exped ierea mesaje lor28 for ( int i =0; i<n ; i ++){29 s e s s i o n . messageTransfer ( exchange ,30 MessageAcceptMode . EXPLICIT ,31 MessageAcquireMode .PRE ACQUIRED,32 new Header ( de l i v e ryProps ) ,33 ”Message ” + i ) ;34 }35 s e s s i o n . messageTransfer ( exchange ,36 MessageAcceptMode . EXPLICIT ,37 MessageAcquireMode .PRE ACQUIRED,38 new Header ( de l i v e ryProps ) ,39 ”” ) ;
41 // Confirmarea r e c e p t i e i mesaje lor42 s e s s i o n . sync ( ) ;
44 // Inch iderea s e s i u n i i s i a conex iun i i45 s e s s i o n . c l o s e ( ) ;46 con . c l o s e ( ) ;47 }48 }
5.7.3 Receptionarea mesajelor
Mesaje se receptioneaza asincron, adica de o clasa ascultatoare care implementeazainterfata SessionListener.
Interfata SessionListener declara metodele:
public void opened(Session session)
public void resumed(Session session)
public void message(Session session, MessageTransfer xfr)
public void exception(Session session, SessionException e)
public void closed(Session session)
Receptionarea de mesaje consta din
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);
132 CAPITOLUL 5. MESAJE IN JAVA
3. Precizarea ascultatorului de mesaje (Fie Listener o clasa care implementeazainterfata SessionListener)
Listener listener = new Listener();
session.setSessionListener(listener);
4. Crearea abonatului care urmeaza sa receptioneaze mesaje. Ascultatorul va ficaracterizat de un nume - listener destination.
session.messageSubscribe(numeCoada,
"listener_destination",
MessageAcceptMode.NONE,
MessageAcquireMode.PRE_ACQUIRED,
null, 0, null);
session.messageFlow("listener_destination",
MessageCreditUnit.BYTE, Session.UNLIMITED_CREDIT);
session.messageFlow("listener_destination",
MessageCreditUnit.MESSAGE, 11);
5. Asteptarea confirmarii trimiterii tuturor mesajelor disponibile de catre serverulAMQP
session.sync();
6. Oprirea ascultatorului
session.messageCancel("listener_destination");
7. Inchiderea sesiunii si a conexiunii
session.close();
con.close();
Exemplul 5.7.3 Receptia mesajelor expediate ın clasa Sender, creata anterior. Pro-gramul se va termina ın momentul ın care ascultatorul primeste un mesaj faracontinut.
1 import org . apache . qpid . t r anspo r t . ∗ ;
3 class L i s t e n e r implements S e s s i o n L i s t e n e r {4 boolean s f a r s i t=fa l se ;
6 public void opened ( Se s s i on s e s s i o n ){}7 public void resumed ( Se s s i on s e s s i o n ){}
5.7. PROTOCOLUL AMQP 133
8 public void message ( Se s s i on s e s s i on , MessageTransfer x f r ){9 System . out . p r i n t l n ( ”Message : ” + x f r ) ;
10 St r ing sMsg=x f r . t oS t r i ng ( ) ;11 i f ( sMsg . endsWith ( ”body=\”\”” ) ) s f a r s i t=true ;12 }13 public void except ion ( Se s s i on ssn , Ses s ionExcept ion e ){14 System . out . p r i n t l n ( ” Se s s i onL i s t ene rExcep t i on : ”+e . getMessage ( ) ) ;15 }16 public void c l o s e d ( Se s s i on s e s s i o n ) {}
18 public void run ( ){19 while ( ! s f a r s i t ) ;20 }21 }
23 public class Rece iver {24 public stat ic void main ( St r ing [ ] a rgs ) throws Inte r ruptedExcept ion {25 i f ( args . length <3){26 System . out . p r i n t l n ( ”Usage java Sender broker port queueName” ) ;27 System . e x i t ( 1 ) ;28 }29 St r ing broker=args [ 0 ] ;30 int port=I n t e g e r . pa r s e In t ( args [ 1 ] ) ;31 St r ing queueName=args [ 2 ] ;
33 // Crearea conex iun i i34 Connection con = new Connection ( ) ;35 con . connect ( broker , port , ” t e s t ” , ” guest ” , ” guest ” , fa l se ) ;
37 // Crearea s e s i u n i i38 Se s s i on s e s s i o n = con . c r e a t e S e s s i o n ( 0 ) ;
40 // Generarea unei i n s t an t e a a s c u l t a t o r u l u i41 L i s t e n e r l i s t e n e r = new L i s t e n e r ( ) ;42 s e s s i o n . s e t S e s s i o n L i s t e n e r ( l i s t e n e r ) ;
44 // Crearea abona tu lu i care recep t i oneaze mesaje le45 s e s s i o n . messageSubscr ibe (queueName ,46 ” l i s t e n e r d e s t i n a t i o n ” ,47 MessageAcceptMode .NONE,48 MessageAcquireMode .PRE ACQUIRED,49 null , 0 , null ) ;50 s e s s i o n . messageFlow ( ” l i s t e n e r d e s t i n a t i o n ” ,51 MessageCreditUnit .BYTE, Se s s i on .UNLIMITED CREDIT) ;52 s e s s i o n . messageFlow ( ” l i s t e n e r d e s t i n a t i o n ” ,53 MessageCreditUnit .MESSAGE, 1 1 ) ;
55 // Confirmarea t e rminar i i t r an sm i t e r i i mesa je lor56 s e s s i o n . sync ( ) ;
58 // Abonatul a s t eap ta recep t ionarea tu turor mesaje lo59 l i s t e n e r . run ( ) ;
61 // Oprirea a s c u l t a t o r u l u i62 System . out . p r i n t l n ( ” Shutt ing down l i s t e n e r f o r l i s t e n e r d e s t i n a t i o n ” ) ;63 s e s s i o n . messageCancel ( ” l i s t e n e r d e s t i n a t i o n ” ) ;
65 // Inch iderea s e s i u n i i s i a conex iun i i66 s e s s i o n . c l o s e ( ) ;
134 CAPITOLUL 5. MESAJE IN JAVA
67 con . c l o s e ( ) ;68 }69 }
Utilizand clasele prezentate mai sus, prin fixarea convenabila a parametrilor sia ordinii de lansare a programelor se poate exemplifica specificul celor trei dispeceride directionare:
Codurile pentru executie prin ant sunt
• Distribuirea directa:
<target name="run" depends="compile">
<java classname="DeclareQueue" fork="yes" maxmemory="100M">
<classpath refid="qpid.classpath" />
<arg line="localhost 5672 message_queue amq.direct routing_key"/>
</java>
<sleep seconds="15" />
<java classname="Sender" fork="yes" maxmemory="100M">
<classpath refid="qpid.classpath" />
<arg line="localhost 5672 amq.direct routing_key 5"/>
</java>
<sleep seconds="5" />
<java classname="Receiver" fork="yes" maxmemory="100M">
<classpath refid="qpid.classpath" />
<arg line="localhost 5672 message_queue"/>
</java>
</target>
• Distribuirea fanout:
<target name="queue">
<java classname="DeclareQueue" fork="yes" maxmemory="100M">
<classpath refid="qpid.classpath" />
<arg line="localhost 5672 q1 amq.fanout xxx"/>
</java>
<java classname="DeclareQueue" fork="yes" maxmemory="100M">
<classpath refid="qpid.classpath" />
<arg line="localhost 5672 q2 amq.fanout yyy"/>
</java>
</target>
<target name="sender">
<java classname="Sender" fork="yes" maxmemory="100M">
<classpath refid="qpid.classpath" />
<arg line="localhost 5672 amq.fanout zzz 2"/>
</java>
</target>
<target name="receiver">
<sleep seconds="5" />
<parallel>
<java classname="Receiver" fork="yes" maxmemory="100M">
<classpath refid="qpid.classpath" />
<arg line="localhost 5672 q1"/>
</java>
<java classname="Receiver" fork="yes" maxmemory="100M">
5.7. PROTOCOLUL AMQP 135
<classpath refid="qpid.classpath" />
<arg line="localhost 5672 q2"/>
</java>
</parallel>
</target>
• Distribuirea bazata pe publicare-abonare:
<target name="queue">
<java classname="DeclareQueue" fork="yes" maxmemory="100M">
<classpath refid="qpid.classpath" />
<arg line="localhost 5672 q1 amq.topic unitbv.#.topic"/>
</java>
<java classname="DeclareQueue" fork="yes" maxmemory="100M">
<classpath refid="qpid.classpath" />
<arg line="localhost 5672 q2 amq.topic unitbv.cs.*"/>
</java>
</target>
<target name="receiver">
<parallel>
<java classname="Receiver" fork="yes" maxmemory="100M">
<classpath refid="qpid.classpath" />
<arg line="localhost 5672 q1"/>
</java>
<java classname="Receiver" fork="yes" maxmemory="100M">
<classpath refid="qpid.classpath" />
<arg line="localhost 5672 q2"/>
</java>
</parallel>
</target>
<target name="sender">
<java classname="Sender" fork="yes" maxmemory="100M">
<classpath refid="qpid.classpath" />
<arg line="localhost 5672 amq.topic unitbv.cs.topic 5"/>
</java>
</target>
In cazul distribuirii fanout si a celei bazate pe publicare-abonare sunt lansate ınordine doua cozi cu cate un receptor de mesaje (Receiver) urmat de producatorulde mesaje (Sender).
136 CAPITOLUL 5. MESAJE IN JAVA
Capitolul 6
Servlet
Printre aplicatiile distribuite de tip client-server, ın care comunicatiile se bazeazape protocolul http, se disting
• Aplicatii Web (site): Cererea adresata serverului este lansata de o persoanaprin intermediul unui site, utilizand un program navigator: Google Chrome,Mozilla Firefox, Opera, Microsoft InternetExplorer, Apple Safari, etc.
• Servicii Web: Cererea catre server se face de un program.
Un servlet este un program Java care se excuta pe un server Web, compatibil, sieste capabil sa rapunda cererilor formulate de clienti.
Programarea si utilizarea unui servlet necesita:
• Cunoasterea marcajului html <form> pentru realizarea formularelor de in-troducere a datelor;
• Utilizarea unui server Web, container de servleti.
6.1 Marcajul <form>
Intr-un document html introducerea datelor se poate obtine utilizand marcajul<form> ...</form> .
Atribute ale marcajului <form> . Reamintim ca atributele se prezinta caperechi (nume, valoare) si se scriu ın antetul marcajului sub forma nume = valoare.
137
138 CAPITOLUL 6. SERVLET
Nume Valoare Semnificatia valorii
action adresa tip URL Resursa care prelucreaza formularul.
method GET Mesajul trimis serverului Web contine dupaadresa URL numele si valorile parametrilor
introdusi. Adaugarea se face potrivit sintaxei?numeParam1=valoare&numeParam2=valoare. . .
Lungimea mesajului nu poate depasi 255 caractere.POST Transmisia datelor se face ın fluxuri de date.
Permite transferul unor fisiere de pe masinaclientului pe masina serverului.
id Parametru de identificare a formularului (optional).
name Nume atribuit formularului (optional).
onSubmit Metoda JavaScript executata ınaintea apelariiserverului Web (optional).
In continutul marcajului <form> putem include elemente de control prinmarcajele
• <input>
• <option>
• <select>
• <textarea>
Atributele marcajului < input> sunt:
Nume Valoare Semnificatie
type text Se asteapta introducerea unui textpassword Se asteapta introducerea unei parolesubmit Se marcheaza sfarsitul completarii formularuluireset Se reinitializeaza formularulfile Permite selectarea unui fisierhidden Transmite mai departe un atribut fara vizualizarea lui
name numele controlului
value valoarea (initiala) a controlului
size numarul caracterelor atasat controlului
In cazul marcajului < select> utilizarea este
<select name="nume">
<option value="valoare"> Valoare
. . . . . . . . . . . . . . . .
</select>
6.2. SERVER WEB - CONTAINER DE SERVLET 139
Valoarea atributului nume este data de valoarea selectata.
6.2 Server Web - container de servlet
In prezent sunt disponibile mai multe servere Web ın care poate fi instalat unservlet si un fisier JSP Java Server Pages. Se spune ca serverul Web este containerde servlet si JSP. Dintre produsele gratuite amintim
• apache-tomcat
• jetty
• Oracle-Sun Java System Application Server
Acest server Web este utilizat ın Glassfish - o implementare JEE (Java Enter-prise Edition).
• JBoss
Geronimo, o alta implementare JEE dezvoltata de apache, poate utiliza con-tainerul apache-tomcat sau jetty.
Serverul Web apache-tomcat
In continuare se va folosi serverul Web apache-tomcat, pe scurt tomcat.Serverul Web tomcat este distribuit gratuit, putand fi descarcat de la adresa
www.apache.org.
Instalarea serverului ın mediul Windows revine la dezarhivarea fisieruluidescarcat apache-tomcat-***, ıntr-un catalog TOMCAT HOME. Utilizarea serveruluinecesita fixarea a doi parametri sistem:
• CATALINA HOME= calea la catalogul ın care s-a instalat produsul - TOMCAT HOME;
• JAVA HOME=calea la distributia Java utilizata.
Pachetul contine cataloagele1: bin, common, conf, logs, server, shared, temp,
webapps, work.
Serverul se lanseaza prin comanda
TOMCAT HOME\bin\startup
si se opreste cu comanda
TOMCAT HOME\bin\shutdown1Numele si numarul cataloagelor este dependent de distributia apache-tomcat.
140 CAPITOLUL 6. SERVLET
Din catalogul TOMCAT HOME, lansarea se poate obtine cu ajutorul fisierului decomenzi (*.bat)
set CATALINA_HOME=. . .
set JAVA_HOME=. . .
bin\startup
Optional se poate instala / activa managerul / administatorul serverului Web tom-cat.
Verificarea functionarii serverului Web tomcat se face apeland dintr-un navigatorpagina http://host:port unde
• host este numele calculatorului pe care ruleaza tomcat;
• Portul implicit este 8080.
Reusita este ilustrata de imaginea motanului
6.3 Realizarea unui servlet
6.3.1 Instalarea unui servlet
Pentru un servlet, ın catalogul webapps, se creaza un subcatalog, de exempluapphello continand
apphello
| |---> WEB-INF
| | |---> classes
| | | web.xml
Catalogul classes contine fisierele .class ale servletului iar fisierul web.xmlfurnizeaza serverului web informatii de acces la servlet. Astfel
1. In elementul <servlet> se leaga numele servlet-ului definit ın elementul<servlet-name> de clasa servlet-ului dat ın elementul<servlet-class> .
2. In elementul <servlet-mapping> se defineste numele sub care servlet-ul iden-tificat prin <servlet-name> nume servlet< /servlet> se invoca din pro-gramul navigator. Acest identificator - numeApel - se fixeaza ın elementul<url-pattern> . Identificatorul are ca prefix caracterul / (slash).
6.3. REALIZAREA UNUI SERVLET 141
Structura unui fisier web.xml este
1 <web−app>2 <s e r v l e t>3 <s e r v l e t−name>nume se rv l e t 1</ s e r v l e t−name>4 <s e r v l e t−c l a s s>Nume clasa</ s e r v l e t−c l a s s>5 </ s e r v l e t>6 <s e r v l e t>7 <s e r v l e t−name>nume se rv l e t 2</ s e r v l e t−name>8 <s e r v l e t−c l a s s>Nume clasa</ s e r v l e t−c l a s s>9 </ s e r v l e t>
10 . . .11 <s e r v l e t−mapping>12 <s e r v l e t−name>nume se rv l e t 1</ s e r v l e t−name>13 <ur l−pattern>/numeApel 1</ ur l−pattern>14 </ s e r v l e t−mapping>15 <s e r v l e t−mapping>16 <s e r v l e t−name>nume se rv l e t 2</ s e r v l e t−name>17 <ur l−pattern>/numeApel 2</ ur l−pattern>18 </ s e r v l e t−mapping>19 . . .20 </web−app>
Optional web.xml poate contine elementul
<welcome-file-list>
<welcome-file>
fisier.html sau jsp
</welcome-file>
</welcome-file-list>
cu precizarea fisierelor html sau jsp care lanseaza servletul. Declaratia fisieruluiindex.html este implicita.
Daca servlet-ul necesa alte resurse - fisiere jar, atunci acestea se depun ıntr-unsubcatalog lib ın WEB-INF.
O alta varianta de instalare a unui servlet, de exemplu reprezentat prin clasaHelloServlet.class, ın serverul Web tomcat consta din:
1. Se creaza oriunde structura de cataloage si fisiere
apphello
| |---> WEB-INF
| | |---> classes
| | | | HelloServlet.class
| | | web.xml
2. Din catalogul apphello se realizeaza arhiva apphello.war
jar cfv apphello.war WEB-INF\∗care se copiaza ın catalogul TOMCAT HOME\webapps.
142 CAPITOLUL 6. SERVLET
3. Se porneste serverul tomcat, operatie ın urma careie arhiva este dezarhivata.Astfel servlet-ul este instalat.
Daca serverul tomcat este pornit atunci arhiva se dezarhiveaza automat siservlet-ul este gata de utilizare. Aceasta instalare se numeste instalare di-namica - hot deployment.
Daca fisierul war este creat, atunci ın locul copierii, instalarea se poate face princomponenta manager a lui tomcat.
O alta posibilitate de instalare a unui servlet ın serverul web tomcat este prinintermediul produsului apache-tomcat-deployer. apache-tomcat-deployer permite in-stalarea unui servlet de la distanta cat si instalarea comandata dintr-un program.
apache-tomcat-*.*.*-deployer se instaleaza prin dezarhivarea fisierului apache-tomcat-*.*.*-deployer.Posibilitatile oferite de apache-tomcat-*.*.*-deployer se obtin ruland ant cu un fisierul build.xml din
distributia produsului. Obiectivele care pot fi atinse sunt
• compilarea unui servlet - compile
• instalarea unui servlet - deploy
• dezinstalarea unui servlet - undeploy
In prealabil trebuie completat fisierul de proprietati deployer.properties cu
• build=catalogul care va contine rezultatul compilarii si al arhivarii.
• 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 ın manager-ul din Tomcat.
• password=parola pentru manager-ul din Tomcat.
Sursa servlet-ului are structura obisnuita, precizata anterior.
6.3.2 Compilarea si apelarea unui servlet
Compilarea unui program necesita completarea variabilei de mediu classpath
cu fisierul TOMCAT HOME\. . .\servlet-api.jar din distributia tomcat. Pozitiafisierului depinde de versiunea apache-tomcat utilizata.
Un servlet se lanseaza ın executie (se apeleaza) din
• meniul File/Open a unui program navigator prin
http://host:port/context/numeApel
6.3. REALIZAREA UNUI SERVLET 143
unde
– context este dat de numele catalogului ce contine servlet-ul - ın exemplulanterior acesta este apphello.
– portul implicit este 8080.
– numeApel este identificatorul fixat ın marcajul url-pattern din fisierulweb.xml.
• ca o referinta dintr-un document html
<a href="http://host:port/context/numeApel "> ...</a>
• ca valoare a atributului action ıntr-un marcaj form
<form action="http://host:port/context/numeApel” ... >
Contextul este legat de fisierul web.xml si poate contine o multime de servleti, fiecareidentificandu-se prin numeApel.
Daca context-ul servletului contine fisierul index.html atunci aplicatia se poateapela prin http:// host:port/context.
Daca este prezent elementul <welcome-file-list> ın fisierul web.xml atunciapelarea aplicatiei poate fi http:// host:port/context/fisier.html—jsp, unde fisier.htmlsau jsp este unul din fisierele declarate ıntr-un element <welcome-file> .
6.3.3 Codul unui servlet
Clasele care asigura functionalitatea servlet-ului nu fac parte din distributia JDK,ele sunt cuprinse ın distributia serverului Web.
Un servlet implementeaza interfata Servlet sau extinde una din clasele GenericServletsau HttpServlet. GenericServlet implementeaza interfata Servlet, iar HttpServletextinde clasa GenericServlet. Extinzand clasa GenericServlet nu este nevoie derescrierea tuturor metodelor abstracte ale intrefetei Servlet.
Metodele interfetei Servlet sunt
• abstract public void init(ServletConfig config)
Se apeleaza o singura data la lansarea servlet-ului.
• abstract public void service(ServletRequest req, ServletResponse res)throwsServletException,IOException
Metoda este apelata de serverul Web pentru rezolvarea cererii unui client.
144 CAPITOLUL 6. SERVLET
• abstract public void destroy()
Se apeleaza o singura data la distrugerea servlet-ului.
• public String getServletInfo()
• public ServletConfig getServletConfig()
In cele ce urmeaza un servlet va fi o clasa care extinde clasa HttpServlet. Inlocul metodei service(...), programatorul suprascrie metodele doGet(...) saudoPost(...), ın functie de metoda utilizata de client la lansarea cererii.
Practic, un servlet consta din scrierea metodelor
• void init(ServletConfig config)
Aceasta metoda este optionala.
public void init(ServletConfig config) throws ServletException{
super.init(config);
// cod de initializare
}
Obiectul config are o metoda String getInitParameter(String numeParam)
cu ajutorul careia se pot recupera parametri de initializare asociati servletuluisi care se dau ın fisierul web.xml prin marcajele
<init-param>
<param-name> NumeleParametrului </param-name>
<param-value> Valoare </param-value>
</init-param>
cuprinse ın marcajul <servlet>.
• protected void doGet(HttpServletRequest req, HttpServletResponse res)throws IOException, ServletException
Trateaza o cerere trimisa cu metoda GET (vezi marcajul <form>).
• protected void doPost(HttpServletRequest req, HttpServletResponse res)throws IOException, ServletException
Trateaza o cerere trimisa cu metoda POST (vezi marcajul <form>).
Activitatile de ıntreprins ıntr-o metoda doGet() sau doPost() sunt
1. Stabilirea naturii raspunsului:res.setContentType(String tip)
unde tip specifica tipul MIME - Multipurpose Internet Mail Extensions alraspunsului:
6.3. REALIZAREA UNUI SERVLET 145
• "text/html" - pagina html;
• "text/xml" - document xml;
• "text/plain" - text;
• "image/jpg" - imagine gif;
• "image/gif" - imagine jpg.
2. Se obtine o referinta catre un obiect care realizeaza transmisia datelor catrenavigatorul clientului:ServletOutputStream out = res.getOutputStream();
sauPrintWriter out=res.getWriter();
3. Se preiau datele cererii cu una din metodele:String getParameter(String numeParapetru)java.util.Enumeration getParameterNames()
4. Rezolva cererea clientului;
5. Formeaza si scrie raspunsul;
6. Inchide conexiunea obiectului prin care s-a realizat transmisia datelor catrenavigatorul clientului prin out.close().
Un utilizator lanseaza o cerere catre servlet. De obicei acest lucru se realizeazaprin completarea unui formular al unui document html. Programul navigator trimitecererea serverului Web prin intermediul caruia este lansat servlet-ul ın actiune.
Ciclul de viata al unui servlet. Cand un servlet este apelat prima data decatre serverul Web se executa metoda init. Dupa aceasta, fiecarei cereri lansate deun utilizator i se asociaza un fir de executie ın care se apeleaza metoda service.Metoda service apeleaza apoi metodele doGet(), doPost().
Exemplul 6.3.1 Servletul Hello: Clientul transmite numele servet-ului care ıi raspundecu mesajul de salut ”Hi” + nume!.
Formularul html prin care clientul introduce numele este (index.html)
1 <html>2 <head>3 <t i t l e> Serv l e t−ul He l lo </ t i t l e>4 </head>5 <body>6 <center>7 <h1> Pagina de ape l a r e a s e r v l e t u l u i H e l l o S e r v l e t </h1>8 <form method=” post ”9 action=” http :// l o c a l h o s t :8080/ apphe l l o / h e l l o ”>
10 <p>I n t r o d u c e t i numele :11 <input type=” text ” name=”name” s ize=20>
146 CAPITOLUL 6. SERVLET
12 <p>13 <input type=”submit”>14 </form>15 </center>16 </body>17 </html>
Servlet-ului are codul
1 import java . i o . ∗ ;2 import javax . s e r v l e t . ∗ ;3 import javax . s e r v l e t . http . ∗ ;
5 public class H e l l o S e r v l e t extends HttpServ l e t {6 public void doGet ( HttpServ letRequest req , HttpServletResponse r e s )7 throws Serv le tExcept ion , IOException{8 r e s . setContentType ( ” text /html” ) ;9 ServletOutputStream out=r e s . getOutputStream ( ) ;
10 St r ing nume=req . getParameter ( ”name” ) ;11 out . p r i n t l n ( ”<html>” ) ;12 out . p r i n t l n ( ”<head><t i t l e >He l l oSe rv l e t </ t i t l e ></head>” ) ;13 out . p r i n t l n ( ”<body>” ) ;14 out . p r i n t l n ( ”<h1>He l l oSe rv l e t </h1>” ) ;15 out . p r i n t l n ( ”<p>” ) ;16 out . p r i n t l n ( ”Hi ”+ nume+” ! ” ) ;17 out . p r i n t l n ( ”</p>” ) ;18 out . p r i n t l n ( ”</body>” ) ;19 out . p r i n t l n ( ”</html>” ) ;20 out . c l o s e ( ) ;21 }
23 public void doPost ( HttpServ letRequest req , HttpServletResponse r e s )24 throws Serv le tExcept ion , IOException{25 doGet ( req , r e s ) ;26 }27 }
Fisierul web.xml pentru acest exemplu este
1 <?xml version=” 1 .0 ” encoding=”ISO−8859−1”?>
3 < !DOCTYPE web−app4 PUBLIC ”−//Sun Microsystems , Inc . //DTD Web Appl i ca t ion 2 .3//EN”5 ” h t tp : // java . sun . com/dtd/web−app 2 3 . dtd”>
7 <web−app>8 <s e r v l e t>9 <s e r v l e t−name>h e l l o</ s e r v l e t−name>
10 <s e r v l e t−c l a s s>H e l l o S e r v l e t</ s e r v l e t−c l a s s>11 </ s e r v l e t>12 <s e r v l e t−mapping>13 <s e r v l e t−name>h e l l o</ s e r v l e t−name>14 <ur l−pattern>/ h e l l o</ ur l−pattern>15 </ s e r v l e t−mapping>16 <welcome− f i l e − l i s t>17 <welcome− f i l e>index . html</welcome− f i l e>18 </welcome− f i l e − l i s t>19 </web−app>
6.3. REALIZAREA UNUI SERVLET 147
Compilarea si arhivarea servlet-ului o vom realiza prin intermediul lui apache-ant. In acest scop se creaza structura:
hello
| |---> src
| | | HelloServlet.java
| |---> lib
| |---> web
| | | web.xml
| |---> web-files
| | | index.html
| build.xml
si se utilizeaza fisierul build.xml
1 <p r o j e c t ba s ed i r=” . ” default=” generate . war”>
3 <property name=”TOMCATHOME” value=” . . . / apache−tomcat −∗ .∗ .∗ ”/>4 <property name=” d i s t . name” value=” apphe l l o ” />5 <property name=” d i s t . d i r ” va lue=” d i s t ” />6 <property name=” bu i ld . d i r ” va lue=” bu i ld ”/>
8 <path id=” myclasspath ”>9 < f i l e s e t d i r=” l i b ”>
10 <i n c l ude name=” ∗ . j a r ”/>11 </ f i l e s e t>12 <pathelement path=”${TOMCATHOME}/ l i b / s e r v l e t−api . j a r ” />13 </path>
15 <t a r g e t name=” i n i t ”>16 <d e l e t e d i r=”${ d i s t . d i r }”/>17 <mkdir d i r=”${ bu i ld . d i r }”/>18 <mkdir d i r=”${ d i s t . d i r }” />19 <mkdir d i r=”${ bu i ld . d i r }/WEB−INF” />20 <mkdir d i r=”${ bu i ld . d i r }/WEB−INF/ c l a s s e s ” />21 <mkdir d i r=”${ bu i ld . d i r }/WEB−INF/ l i b ” />22 </ t a r g e t>
24 <t a r g e t name=” compile ” depends=” i n i t ”>25 <javac c l a s s p a t h r e f=” myclasspath ”26 s r c d i r=”${ based i r }/ s r c ”27 d e s t d i r=”${ bu i ld . d i r }/WEB−INF/ c l a s s e s ” />28 </ t a r g e t>
30 <t a r g e t name=” generate . war” depends=” compile ”>31 <copy t o d i r=”${ bu i ld . d i r }” >32 < f i l e s e t d i r=”${ based i r }/web− f i l e s ” >33 <i n c l ude name=” ∗ . html” />34 </ f i l e s e t>35 </copy>36 <copy t o d i r=”${ bu i ld . d i r }/WEB−INF” f i l e=”${ based i r }/web/web . xml”/>37 <copy t o d i r=”${ bu i ld . d i r }/WEB−INF/ l i b ” >38 < f i l e s e t d i r=”${ based i r }/ l i b ” >39 <i n c l ude name=” ∗ . j a r ” />40 </ f i l e s e t>41 </copy>42 < j a r d e s t f i l e=”${ d i s t . d i r }/${ d i s t . name } . war” bas ed i r=”${ bu i ld . d i r }” />43 </ t a r g e t>44 </ p r o j e c t>
148 CAPITOLUL 6. SERVLET
Observatie. Valoarea parametrului dist.name trebuie sa coincida cu numele cata-logului ın atributul action a elementului form, din documentul index.html.
In cazul exemplului de fata, catalogul lib este gol. Daca aplicatia solicita resurseexterne, continute ın fisierele jar, atunci aceste fisiere se depun ın catalogul lib.
Se lanseaza ın executie serverul Web tomcat, se ıncarca servlet-ul ın serverul Websi dintr-un navigator se deschide pagina http://localhost:8080/apphello
Exemplul 6.3.2 Servlet pentru calculul celui mai mare divizor comun a doua nu-mere.
1 import java . i o . ∗ ;2 import javax . s e r v l e t . ∗ ;3 import javax . s e r v l e t . http . ∗ ;
5 public class CmmdcServlet extends HttpServ l e t {
7 public long cmmdc( long m, long n ) { . . .}
9 public void doGet ( HttpServ letRequest req , HttpServletResponse r e s )10 throws Serv le tExcept ion , IOException{11 St r ing sm=req . getParameter ( ”m” ) , sn=req . getParameter ( ”n” ) ;12 St r ing t i p=req . getParameter ( ” t i p ” ) ;13 long m=Long . parseLong (sm) , n=Long . parseLong ( sn ) ;14 long x=cmmdc(m, n ) ;15 PrintWriter out=r e s . getWriter ( ) ;16 i f ( t i p . equa l s ( ” t ext /html” ) ){17 St r ing t i t l e=”CmmdcServlet” ;18 r e s . setContentType ( ” text /html” ) ;19 out . p r i n t l n ( ”<HTML><HEAD><TITLE>” ) ;20 out . p r i n t l n ( t i t l e ) ;21 out . p r i n t l n ( ”</TITLE></HEAD><BODY>” ) ;22 out . p r i n t l n ( ”<H1>”+t i t l e+”</H1>” ) ;23 out . p r i n t l n ( ”<P>Cmmdc i s ”+x ) ;24 out . p r i n t l n ( ”</BODY></HTML>” ) ;25 }26 else {27 r e s . setContentType ( ” text / p l a i n ” ) ;28 out . p r i n t l n ( x ) ;29 }30 out . c l o s e ( ) ;31 }
33 public void doPost ( HttpServ letRequest req , HttpServletResponse r e s )34 throws Serv le tExcept ion , IOException{35 doGet ( req , r e s ) ;36 }37 }
apelabil prin documentul html (index.html)
1 <html>2 <body>3 <form method=” get ”4 action=” http :// l o c a l h o s t :8080/ myserv let /cmmdc”>5 <p>Primul numar e s t e <input type=” text ” name=”m” s ize=5>
6.4. FACILITATI DE PROGRAMARE CU SERVLET 149
6 <p>Al d o i l e a numar e s t e <input type=” text ” name=”n” s ize=5>7 <p><input type=”submit” value=” Calcu leaza ”>8 <input type=” hidden ” name=” t i p ” value=” text /html” >9 </form>
10 </body>11 </html>
Pentru fixarea naturii raspunsului text/html sau text/plain s-a introdus variabilatip, care ın fisierul de invocare index.html primeste pe ascuns valoarea text/html.
In cazul ın care vom apela servlet-ul dintr-un program, va fi avantajos sa primimraspunsul ca text/plain.
6.4 Facilitati de programare cu servlet
6.4.1 Program client al unui servlet
Apelarea unui servlet dintr-un program Java – adica lansarea unei cereri sireceptionarea raspunsului furnizat de servlet – se poate obtine cu produsul httpcomponents-client dezvoltat de apache.
Intr-un asemenea caz, din punctul de vedere al clientului este mai avantajos caraspunsul servlet-ului fie text/plain, ın loc de text/html.
Catalogul lib din httpcomponents-client contine, printre altele, fisierele httpcore-*.jar, httpclient-*.jar, commons-logging-*.jar.
Pentru compilare trebuie declarata ın variabila de sistem classpath referintacatre httpclient-*.jar si httpcore-*.jar dar pentru executie este nevoie si de referintacatre commons-logging-*.jar.
Dezvoltarea unui client presupune:
1. Crearea unui obiect de tip org.apache.http.client.HttpClient:
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 elegenta este
150 CAPITOLUL 6. SERVLET
List<NameValuePair> qparams = new ArrayList<NameValuePair>();
qparams.add(new BasicNameValuePair("param_1", value_1));
qparams.add(new BasicNameValuePair("param_2", value_2));
. . .
try{
URI uri = URIUtils.createURI("http", "localhost", 8080,
"/catalog/numeApel",URLEncodedUtils.format(qparams,"UTF-8"),
null);
HttpGet httpget = new HttpGet(uri);
. . .
}
catch(. . .){. . .}
• POST
List<NameValuePair> qparams = new ArrayList<NameValuePair>();
qparams.add(new BasicNameValuePair("param_1", value_1));
qparams.add(new BasicNameValuePair("param_2", value_2));
. . .
try{
UrlEncodedFormEntity params=new UrlEncodedFormEntity(qparams,
"UTF-8");
HttpPost httppost=new HttpPost(uri);
httppost.setEntity(params);
. . .
}
catch(. . .){. . .}
cu uri=”http://host:port/catalog/numeApel”.
Clasele HttpGet, HttpPost apartin pachetuluiimport org.apache.http.client.methods.
3. Lansarea cererii.
HttpResponse response=httpclient.execute(httpget);
respectiv
HttpResponse response=httpclient.execute(httppost);
4. Preluarea raspunsului.
6.4. FACILITATI DE PROGRAMARE CU SERVLET 151
HttpEntity entity=response.getEntity();
if(entity!=null){
InputStream is=entity.getContent();
int l;
byte[] tmp=new byte[2048];
while((l=is.read(tmp))!=-1){}
. . .
}
Exemplul 6.4.1 Dezvoltam un program client pentru servlet-ul CmmdcServlet (post).
1 import java . u t i l . Scanner ;2 import java . u t i l . L i s t ;3 import java . u t i l . ArrayList ;
5 import org . apache . http . HttpEntity ;6 import org . apache . http . HttpResponse ;7 import org . apache . http . c l i e n t . HttpCl ient ;8 import org . apache . http . c l i e n t . methods . HttpPost ;9 import org . apache . http . impl . c l i e n t . De fau l tHttpCl i ent ;
10 import org . apache . http . NameValuePair ;11 import org . apache . http . message . BasicNameValuePair ;12 import org . apache . http . c l i e n t . e n t i t y . UrlEncodedFormEntity ;
14 import java . i o . ∗ ;
16 public class ClientCmmdcServlet2{17 stat ic St r ing u r i=” http :// l o c a l h o s t :8080/ myserv let /cmmdc” ;
19 public stat ic void main ( St r ing [ ] a rgs ) {20 Scanner scanner=new Scanner ( System . in ) ;21 System . out . p r i n t l n ( ”m=” ) ;22 St r ing m=scanner . nextLine ( ) . tr im ( ) ;23 System . out . p r i n t l n ( ”n=” ) ;24 St r ing n=scanner . nextLine ( ) . tr im ( ) ;
26 // Create an ins tance o f Ht tpC l i en t .27 HttpCl ient h t t p c l i e n t = new Defau l tHttpCl i ent ( ) ;
29 // Create a method ins tance .30 List<NameValuePair> qparams = new ArrayList<NameValuePair >() ;31 qparams . add (new BasicNameValuePair ( ”m” , m) ) ;32 qparams . add (new BasicNameValuePair ( ”n” , n ) ) ;33 qparams . add (new BasicNameValuePair ( ” t i p ” , ” t ext / p l a i n ” ) ) ;34 try{35 UrlEncodedFormEntity params=new UrlEncodedFormEntity ( qparams , ”UTF−8” ) ;36 HttpPost httppost=new HttpPost ( u r i ) ;37 httppost . s e tEnt i ty ( params ) ;38 HttpResponse re sponse=h t t p c l i e n t . execute ( httppost ) ;39 HttpEntity e n t i t y=response . ge tEnt i ty ( ) ;40 i f ( e n t i t y !=null ){41 InputStream i s=e n t i t y . getContent ( ) ;42 int l ;43 byte [ ] tmp=new byte [ 2 0 4 8 ] ;44 while ( ( l=i s . read (tmp))!=−1){}
152 CAPITOLUL 6. SERVLET
45 System . out . p r i n t l n ( ”Cmmdc = ”+(new St r ing (tmp ) . tr im ( ) ) ) ;46 }47 }48 catch ( Exception e ){49 System . out . p r i n t l n ( ” Exception : ”+e . getMessage ( ) ) ;50 }51 }52 }
6.4.2 Servlete ınlantuite
Un servlet apeleaza la un moment dat alt servlet. Sablonul de lucru este
RequestDispatcher dispatcher=
getServletContext().getRequestDispatcher("/url_pattern_servlet_apelat");
if(dispatcher!=null)
dispatcher.include(request,response);
Exemplul 6.4.2 Un servlet VerifServlet verifica parametri cererii. Pentru prob-lema calculului celui mai mare divizor comun a doua numere, daca cei doi parametrisunt numere ıntregi, atunci se apeleaza servletul ComputeServlet, altfel se formeazaun mesaj de eroare.
Codurile celor doua servlete sunt:VerifServlet.java
1 package cmmdc ;2 import java . i o . ∗ ;3 import javax . s e r v l e t . ∗ ;4 import javax . s e r v l e t . http . ∗ ;
6 public class V e r i f S e r v l e t extends HttpServ l e t {
8 public void doGet ( HttpServ letRequest req , HttpServletResponse r e s )9 throws Serv le tExcept ion , IOException{
10 PrintWriter out=r e s . getWriter ( ) ;11 r e s . setContentType ( ” text /html” ) ;12 St r ing sm=req . getParameter ( ”m” ) , sn=req . getParameter ( ”n” ) ;13 St r ing message=”” ;14 long m, n ;15 i f ( ( sm==null ) | | ( sm . equa l s ( ”” ) ) ){16 message=”Numar absent ” ;17 }18 else {19 try{20 m=Long . parseLong (sm ) ;21 }22 catch ( NumberFormatException e ){23 message=”Nu e s t e numar” ;24 }25 }26 i f ( ( sn==null ) | | ( sn . equa l s ( ”” ) ) ){27 message=”Numar absent ” ;
6.4. FACILITATI DE PROGRAMARE CU SERVLET 153
28 }29 else {30 try{31 n=Long . parseLong ( sn ) ;32 }33 catch ( NumberFormatException e ){34 message=”Nu e s t e numar” ;35 }36 }37 out . p r i n t l n ( ”<html><body>” ) ;38 i f ( message . equa l s ( ”” ) ){39 out . p r i n t l n ( ”<h3> Rezu l ta tu l obţ inut </h3>” ) ;40 RequestDispatcher d i spa t che r=41 getServ l e tContext ( ) . getRequestDispatcher ( ”/ c a l c u l ” ) ;42 i f ( d i spa t che r !=null )43 d i spa t che r . i n c lude ( req , r e s ) ;44 }45 else {46 out . p r i n t l n ( ”<h3> Date eronate </h3>” ) ;47 out . p r i n t l n ( message ) ;48 }49 out . p r i n t l n ( ”</body></html>” ) ;50 out . c l o s e ( ) ;51 }
53 public void doPost ( HttpServ letRequest req , HttpServletResponse r e s )54 throws Serv le tExcept ion , IOException{55 doGet ( req , r e s ) ;56 }57 }
ComputeServlet.java
1 package cmmdc ;2 import java . i o . ∗ ;3 import javax . s e r v l e t . ∗ ;4 import javax . s e r v l e t . http . ∗ ;
6 public class ComputeServlet extends HttpServ l e t {
8 public long cmmdc( long m, long n ) { . . .}
10 public void doGet ( HttpServ letRequest req , HttpServletResponse r e s )11 throws Serv le tExcept ion , IOException{12 long m=Long . parseLong ( req . getParameter ( ”m” ) ) ;13 long n=Long . parseLong ( req . getParameter ( ”n” ) ) ;14 PrintWriter out=r e s . getWriter ( ) ;15 out . p r i n t l n ( ”<H1> Cmmdc = ”+cmmdc(m, n)+”</H1>” ) ;16 }
18 public void doPost ( HttpServ letRequest req , HttpServletResponse r e s )19 throws Serv le tExcept ion , IOException{20 doGet ( req , r e s ) ;21 }22 }
154 CAPITOLUL 6. SERVLET
6.4.3 Sesiune de lucru
In cazul protocolului HTTP, de fiecare data cand un client deschide sau revinela o pagina Web se deschide o noua conexiune cu serverul Web iar acesta nu retineinformatiile referitoare la client pe perioada conexiunii respective. Perioada de timpcat un client este ın conexiune cu o pagina Web se numeste sesiune.
Exista posibilitatea pastrarii unor informatii pe durata unei sesiuni (prin mecan-ismul denumit Session Tracking).
Inaintea satisfacerii unei cereri, servletul verifica existenta unui obiect HttpSession.Acest obiect se creaza la prima apelare de catre un client a servletului prin
HttpSession sesiune=request.getSession(true);
Un obiect HttpSession poate retine atribute, adica perechi de forma (nume, val-oare). Introducerea unui atribut se realizeaza prin
void setAttribute(String nume, Object valoare)
iar extragerea valorii unui atribut se obtine prin
Object getAttribute(String nume)
Metoda String nume[ ] getValueNames() returneaza numele tuturoratributelor definite.
Un atribut se elimina cu metoda void removeAttribute(String nume).
Exemplul 6.4.3 Exemplul urmator numara de cate ori se apeleaza servlet-ul ıntr-osesiune. Se defineste un atribut noAcces, care la prima apelare este initializat iarapoi este marit cu cate o unitate la fiecare noua apelare a servlet-ului.
1 import java . i o . ∗ ;2 import javax . s e r v l e t . ∗ ;3 import javax . s e r v l e t . http . ∗ ;
5 public class Ses iune extends HttpServ l e t {
7 public void doGet ( HttpServ letRequest req , HttpServletResponse r e s )8 throws Serv le tExcept ion , IOException{9 r e s . setContentType ( ” text /html” ) ;
10 St r ing mesaj ;11 PrintWriter out=r e s . getWriter ( ) ;12 HttpSess ion s e s s i o n=req . g e t S e s s i o n ( true ) ;13 I n t e g e r contor=( I n t e g e r ) s e s s i o n . ge tAt t r ibut e ( ”noAcces” ) ;14 i f ( contor==null ){15 contor=new I n t e g e r ( 1 ) ;16 mesaj=” Salut ! ” ;17 }18 else {19 contor=new I n t e g e r ( contor . intValue ( )+1) ;20 mesaj=”Bine a t i r e v e n i t ! ” ;21 }
6.4. FACILITATI DE PROGRAMARE CU SERVLET 155
22 s e s s i o n . s e t A t t r i b u t e ( ”noAcces” , contor ) ;23 out . p r i n t l n ( ”<html><body>” ) ;24 out . p r i n t l n ( ”<h1>”+mesaj+”</h1>” ) ;25 out . p r i n t l n ( ”Numarul de a c c e s a r i a l a c e a s t e i pag in i e s t e ” +26 contor . intValue ( ) ) ;27 out . p r i n t l n ( ”</body></html>” ) ;28 out . c l o s e ( ) ;29 }
31 public void doPost ( HttpServ letRequest req , HttpServletResponse r e s )32 throws Serv le tExcept ion , IOException{33 doGet ( req , r e s ) ;34 }35 }
Apelarea servletului se face din
1 <html>2 <head>3 <t i t l e> Ses iune </ t i t l e>4 </head>5 <body>6 <h1> Formular de acce s </h1>7 <form method=” get ”8 action=” http :// l o c a l h o s t :8080/ myserv let / s e s i u n e ”>9 <p>
10 <input type=”submit” value=” Acceseaza ”>11 </form>12 </body>13 </html>
6.4.4 Cookie
Un Cookie este un fisier de mica dimensiune trimis de catre programul serverclientului ca parte a header-ului Http.
Acesta contine informatii despre sesiunea curenta care salvate pe disc vor puteafi accesate ın sesiuni ulterioare. Cand un navigator emite o cerere catre un server,cookie-urile anterioare primite de catre client de la serverul respectiv sunt trimisedin nou serverului ca parte a cererii formulata de client.
Cookie-urile sunt sterse automat ın momentul expirarii.
Unii clienti nu permit memorarea cookie-urilor. In acest caz, clientul este infor-mat ca acest fapt ar putea duce la imposibilitatea satisfacerii cereri sale / accesariipaginii Web. Implicit, durata de viata a unui cookie este sesiunea curenta a naviga-torului (pana se ınchide navigatorul).
Clasa Cookie
Contructor
Cookie(String nume, String valoare)
Metode
156 CAPITOLUL 6. SERVLET
• void setDomain(String model)
Domeniul este o adresa URL ce restrictioneaza accesul cookie-urilor la aceldomeniu. model trebuie sa contina cel putin doua caractere ”.”.
• void setMaxAge(int durata) Fixeaza durata de existenta a cookie-ului - ınsecunde. Valoarea implicita este -1, adica cookie-ul exista pana la ınchidereaprogramului navigator.
• void setComment(String comentariu)
• void setSecure(boolean flag)
Valoarea implicita este false.
Trimiterea unui cookie clientului:public void HttpServletResponse.addCookie(Cookie cookie)
Recunoasterea cookie-urilor de catre servlet:
Cookie [ ] cookies=request.getCookies();
if(cookies!=null){
for(int i=0;i<cookies.length;i++){
String name=cookies[i].getName();
String valoare=cookies[i].getValue();
. . .
}
Exemplul 6.4.4 In exemplul urmator se numara de cate ori se apeleaza servlet-ulpe durata de viata a cookie-ului.
1 import java . i o . ∗ ;2 import javax . s e r v l e t . ∗ ;3 import javax . s e r v l e t . http . ∗ ;
5 public class Ape lar i extends HttpServ l e t {
7 public void doGet ( HttpServ letRequest req , HttpServletResponse r e s )8 throws Serv le tExcept ion , IOException{9 r e s . setContentType ( ” text /html” ) ;
10 St r ing mesaj=”” ;11 PrintWriter out=r e s . getWriter ( ) ;12 Cookie myCookie=null ;13 int contor =1;14 Cookie [ ] c oo k i e s=req . getCookies ( ) ;15 i f ( c o ok i e s !=null ){16 for ( int i =0; i<c oo k i e s . l ength ; i ++){17 St r ing name=c oo k i e s [ i ] . getName ( ) ;18 i f (name . equa l s ( ” urmar ire ” ) ){19 contor=I n t e g e r . pa r s e In t ( c oo k i e s [ i ] . getValue ( ) ) ;
6.4. FACILITATI DE PROGRAMARE CU SERVLET 157
20 contor++;21 mesaj=”Bine a t i r e v e n i t ! ” ;22 }23 }24 }25 else {26 mesaj=” Salut ! ” ;27 }28 myCookie=new Cookie ( ” urmar ire ” , (new I n t e g e r ( contor ) ) . t oS t r i ng ( ) ) ;29 myCookie . setMaxAge (1000000) ;30 r e s . addCookie ( myCookie ) ;31 out . p r i n t l n ( ”<html><body>” ) ;32 out . p r i n t l n ( ”<h1>”+mesaj+”</h1>” ) ;33 out . p r i n t l n ( ”Numarul de a c c e s a r i a l a c e a s t e i pag in i e s t e ”+contor ) ;34 out . p r i n t l n ( ”</body></html>” ) ;35 out . c l o s e ( ) ;36 }
38 public void doPost ( HttpServ letRequest req , HttpServletResponse r e s )39 throws Serv le tExcept ion , IOException{40 doGet ( req , r e s ) ;41 }42 }
6.4.5 Autorizarea accesului prin parola
Parolele celor ındreptatiti sa acceseze servletul sunt cuprinse ıntr-un fisier. Inservlet accesul la fisier se realizeaza prin preluarea unui parametru a carei valoareeste numele fisierului.
Servlet-ul solicita afisarea pe masina clientului a unei casute de dialog prin careclientul introduce numele si parola. Daca datele coincid cu cele ınregistrate ın fisieratunci se autorizeaza accesul la servlet.
Date transmise de client sunt codificate. Decodificarea se poate realiza cu clasaBase64Coder : www.source-code.biz, Christian d’Heureuse, Inventec Informatik AG,Switzerland.
Exemplul 6.4.5
1 import java . i o . ∗ ;2 import javax . s e r v l e t . ∗ ;3 import javax . s e r v l e t . http . ∗ ;4 import java . u t i l . P r o p e r t i e s ;
6 public class ProtectedPage extends HttpServ l e t {7 private P r o p e r t i e s passwords ;8 private St r ing passwordFi le ;
10 // Paro l e l e sunt in t r−un f i s i e r ” paro l e ”11 // sub forma nume=paro la .12 public void i n i t ( Se rv l e tCon f i g c o n f i g )throws Serv l e tExcept ion {13 super . i n i t ( c o n f i g ) ;14 try {
158 CAPITOLUL 6. SERVLET
15 passwordFi le = c o n f i g . ge t In i tParameter ( ” passwordFi le ” ) ;16 passwords = new P r o p e r t i e s ( ) ;17 passwords . load (new Fi leInputStream ( passwordFi le ) ) ;18 }19 catch ( IOException i o e ) {}20 }
22 public void doGet ( HttpServ letRequest request , HttpServletResponse re sponse )23 throws Serv le tExcept ion , IOException {24 re sponse . setContentType ( ” text /html” ) ;25 PrintWriter out = response . getWriter ( ) ;26 St r ing a u t h o r i z a t i o n = reques t . getHeader ( ” Author i zat ion ” ) ;27 i f ( a u t h o r i z a t i o n == null ) {28 ce rParo la ( re sponse ) ;29 }30 else {31 St r ing u s e r I n f o = a u t h o r i z a t i o n . su b s t r i n g ( 6 ) . tr im ( ) ;32 St r ing nameAndPassword = Base64Coder . decodeStr ing ( u s e r I n f o ) ;33 System . out . p r i n t l n ( nameAndPassword ) ;34 int index = nameAndPassword . indexOf ( ” : ” ) ;35 St r ing user = nameAndPassword . s ub s t r i n g (0 , index ) ;36 St r ing password = nameAndPassword . su b s t r i n g ( index +1). tr im ( ) ;37 passwords . l i s t ( System . out ) ;38 St r ing realPassword = passwords . getProperty ( user ) ;39 System . out . p r i n t l n ( user+” ”+password+” ”+realPassword ) ;40 i f ( ( rea lPassword != null)&&(realPassword . equa l s ( password ) ) ){41 St r ing t i t l e = ”Welcome to the Protected Page” ;42 out . p r i n t l n ( ”<HTML><HEAD><TITLE>”+t i t l e+”</TITLE></HEAD>” +43 ”<BODY BGCOLOR=\”#AABBAA\”>\n”+”<H1 ALIGN=CENTER>” + t i t l e +44 ”</H1>\n” + ” Aveti acce s l a pagina ”+”</BODY></HTML>” ) ;45 }46 else {47 ce rParo la ( re sponse ) ;48 }49 }50 }
52 // Cererea a f o s t fara au to r i z a r e53 private void ce rParo la ( HttpServletResponse re sponse ) {54 re sponse . s e t S t a tu s ( re sponse .SC UNAUTHORIZED) ; // Ie 40155 re sponse . setHeader ( ”WWW−Authent icate ” ,56 ”BASIC realm=\” p r i v i l e g e d−few\”” ) ;57 }
59 public void doPost ( HttpServ letRequest request , HttpServletResponse re sponse )60 throws Serv le tExcept ion , IOException {61 doGet ( request , r e sponse ) ;62 }63 }
Parolele se retin ıntr-un fisier denumit parole.properties alcatuit din ınregistraride forma nume=parola, cate o ınregistrare pe linie. Localizarea fisierului se obtineprin intermediul datelor din elementul
<init-param>
<param-name>passwordFile</param-name>
<param-value>d:\\apache-tomcat-*.*.*\\. . .\\parole.properties</param-value>
</init-param>
6.4. FACILITATI DE PROGRAMARE CU SERVLET 159
Acest element apare ın corpul elementului <servlet> atasat servlet-ului. Servletulse apeleaza prin http://host:port/context/numeApel.
6.4.6 Servlet cu conexiune la o baza de date
Folosind Anexa C consideram
Exemplul 6.4.6 Consultarea unei agende de adrese e-mail. Se utilizeaza o baza dedate AgendaEMail alcatuita dintr-un singur tabel adrese (id int, nume varchar(20),numar varchar(30)).
Utilizand SGBD derby servletul este
1 import java . i o . ∗ ;2 import javax . s e r v l e t . ∗ ;3 import javax . s e r v l e t . http . ∗ ;4 import java . s q l . ∗ ;5 import java . net . ∗ ;
7 public class AgendaEMailServlet extends HttpServ l e t {8 Statement i n s t r u c t i u n e=null ;
10 public void i n i t ( Se rv l e tCon f i g c o n f i g ) throws Serv l e tExcept ion {11 super . i n i t ( c o n f i g ) ;12 // SGBD Derby13 St r ing jdbcDr iver=” org . apache . derby . jdbc . C l i en tDr ive r ” ;14 St r ing URLBazaDate=” jdbc : derby :// l o c a l h o s t :1527/ AgendaEMail” ;15 Connection con=null ;16 try{17 Class . forName ( jdbcDr iver ) . newInstance ( ) ;18 con=DriverManager . getConnect ion (URLBazaDate ) ;19 i n s t r u c t i u n e=con . createStatement ( ) ;20 }21 catch ( ClassNotFoundException e ){22 System . out . p r i n t l n ( ” Driver i n e x i s t e n t JDBC: ”+jdbcDr iver ) ;23 }24 catch ( SQLException e ){25 System . out . p r i n t l n ( ”Baza de date i n e x i s t e n t a ”+URLBazaDate ) ;26 }27 catch ( Exception e ){28 System . out . p r i n t l n ( ” Eroare : ”+e . getMessage ( ) ) ;29 }30 }
32 public void doGet ( HttpServ letRequest req , HttpServletResponse r e s )33 throws Serv le tExcept ion , IOException{34 St r ing myAtribut , myVal ;35 r e s . setContentType ( ” text /html” ) ;36 ServletOutputStream out = r e s . getOutputStream ( ) ;
38 myAtribut=req . getParameter ( ” c r i t e r i u ” ) ;39 myVal=req . getParameter ( ” termen” ) ;40 myVal=’ \ ’ ’+myVal+’ \ ’ ’ ;41 try{42 St r ing s q l=” s e l e c t ∗ from adrese where ”+ myAtribut+” = ”+myVal ;43 Resu l tSet r s=i n s t r u c t i u n e . executeQuery ( s q l ) ;
160 CAPITOLUL 6. SERVLET
44 out . p r i n t l n ( ”<html>” ) ;45 out . p r i n t l n ( ”<head><t i t l e >AgendaEMail</ t i t l e ></head>” ) ;46 out . p r i n t l n ( ”<body>” ) ;47 out . p r i n t l n ( ”<h1>Agenda de Adrese e−mail </h1>” ) ;48 out . p r i n t l n ( ”<p/>” ) ;49 out . p r i n t l n ( ”<b> Nume <−−> Adresa e−mail </b>” ) ;50 out . p r i n t l n ( ”<br/>” ) ;51 while ( r s . next ( ) ){52 out . p r i n t ( r s . g e t S t r i n g ( ”nume”)+” <−−> ”+r s . g e t S t r i n g ( ” emai l ” ) ) ;53 out . p r i n t l n ( ”<br/>” ) ;54 }55 out . p r i n t l n ( ”</body>” ) ;56 out . p r i n t l n ( ”</html>” ) ;57 out . c l o s e ( ) ;58 }59 catch ( SQLException e ){60 System . out . p r i n t l n ( ”SQLException : ”+e . getMessage ( ) ) ;61 }62 catch ( Exception e ){63 System . out . p r i n t l n ( ” Eroare : ”+e . getMessage ( ) ) ;64 }65 }
67 public void doPost ( HttpServ letRequest req , HttpServletResponse r e s )68 throws Serv le tExcept ion , IOException{69 doGet ( req , r e s ) ;70 }71 }
Apelarea servlet-ului se face din
1 <html>2 <body>3 <h1> Cautare in baza de date AgendaEMail</h1>4 <form method=” get ”5 action=” http :// l o c a l h o s t :8080/ agendae/ adrese ”>6 <p>C r i t e r i u de cautare :7 <select name=” c r i t e r i u ” >8 <option value=”nume”>dupa Nume9 <option value=” emai l ”>dupa Email
10 </ select>11 <br>12 <p>Ent i ta tea cautata13 <input type=” text ” name=”termen” s ize=30>14 <p><input type=”submit” value=”Cauta”>15 </form>16 </body>17 </html>
Testarea aplicatiei presupune:
1. Realizarea bazei de date:
2. Testarea servlet-ului:
(a) Pornirea serverului bazei de date.
(b) Se verifica prezenta ın catalogul servlet-ului ...\WEB-INF\lib a fisieruluiderbyclient.jar sau mysql-connector-java-*.*.*-bin.jar.
6.4. FACILITATI DE PROGRAMARE CU SERVLET 161
(c) Pornirea serverului tomcat sau reıncarcarea servlet-ului.
(d) Apelarea servlet-ului din pagina Web.
6.4.7 Imagini furnizate de servlet
Indicam doua modalitati prin care un client obtine o imagine furnizata de unservlet. Imaginea poate proveni dintr-un fisier extern sau poate fi creata de servlet.
• Imaginea este transmisa direct clientului ın fluxul de iesire de tipServletOutputStream, tipul MIME al raspunsului fiind
response.setContentType("image/ext");
ext∈ {gif, jpg, png, . . .}.Textul sursa al servlet-ului este:
1 import java . i o . ∗ ;2 import javax . s e r v l e t . ∗ ;3 import javax . s e r v l e t . http . ∗ ;
5 public class MyGraphG extends HttpServ l e t {6 public void doGet ( HttpServ letRequest req , HttpServletResponse r e s )7 throws Serv le tExcept ion , IOException {8 r e s . setContentType ( ” image/ g i f ” ) ;9 ServletOutputStream out = r e s . getOutputStream ( ) ;
11 // Refer in ta l a f i s i e r u l g r a f i c12 St r ing f =13 ”d :\\ apache−tomcat −6.0.20\\webapps\\myserv let \\WEB−INF\\”+14 ” c l a s s e s \\walk ing santa . g i f ” ;15 // Tranferarea f i s i e r u l u i g r a f i c16 Fi leInputStream f i s = new Fi leInputStream ( f ) ;17 BufferedInputStream b i s = new BufferedInputStream ( f i s ) ;18 byte [ ] bytes = new byte [ b i s . a v a i l a b l e ( ) ] ;19 int nread = 0 ;20 while (−1 != ( nread = b i s . read ( bytes ) ) ) {21 out . wr i t e ( bytes , 0 , nread ) ;22 }23 }24 }
• Pe calculatorul serverului Web, imaginea se salveaza ıntr-un fisier grafic, dupacare servlet-ul scrie ın fluxul de iesire un document html cu o legatura (link)catre fisierul cu imaginea creata anterior. Navigatorul clientului va descarcasi vizualiza imaginea.
Daca tipul fisierului grafic este jpg sau png atunci textul sursa al servlet-uluieste:
162 CAPITOLUL 6. SERVLET
1 mport java . i o . ∗ ;2 import java . awt . ∗ ;3 import javax . s e r v l e t . ∗ ;4 import javax . s e r v l e t . http . ∗ ;5 import javax . imageio . ∗ ;6 import java . awt . image . ∗ ;7 import javax . imageio . stream . ∗ ;8 import java . u t i l . ∗ ;
10 public class MyGraphP extends HttpServ l e t {11 public void doGet ( HttpServ letRequest req , HttpServletResponse r e s )12 throws Serv le tExcept ion , IOException {13 r e s . setContentType ( ” text /html” ) ;14 PrintWriter out=r e s . getWriter ( ) ;15 St r ing f i l e R e f=”d :\\ apache−tomcat −6.0.20\\webapps\\myserv let \\” ;16 St r ing numeFis=” desen ” ;17 St r ing ext=” jpg ” ; // sau ”png”18 // Formarea imag in i i19 Frame frame = null ;20 Graphics g = null ;21 BufferedImage image=null ;22 try{23 frame = new Frame ( ) ;24 frame . addNoti fy ( ) ;25 image = ( BufferedImage ) frame . createImage (800 , 6 0 ) ;26 g = image . getGraphics ( ) ;27 // Fixarea f o n t u l u i28 g . setFont (new Font ( ” S e r i f ” , Font . ITALIC , 4 8 ) ) ;29 // Editarea unui t e x t30 g . drawString ( ” Tehno log i i d i s t r i b u i t e in Java” , 10 , 5 0 ) ;
32 // Sa lvarea imag in i i in t r−un f i s i e r jpg sau png33 F i l e f=new F i l e ( f i l e R e f+numeFis+” . ”+ext ) ;34 ImageIO . wr i t e ( image , ” jpg ” , f ) ;
36 // Raspunsul ca t re c l i e n t37 out . p r i n t l n ( ”<HTML><BODY>” ) ;38 out . p r i n t l n ( ”<h2>Imagine pre lua ta de pe s e r v e r </h2>” ) ;39 out . p r i n t l n ( ”<p><a h r e f =\”http :// l o c a l h o s t :8080/ myserv let /”+40 numeFis+” . ”+ext+”\”>” ) ;41 out . p r i n t l n ( ” V i z u a l i z a r e a i m a g i n i i </a>” ) ;42 out . p r i n t l n ( ”</BODY></HTML>” ) ;43 out . c l o s e ( ) ;44 }45 f ina l ly {46 // E l i b e rarea r e s u r s e l o r47 i f ( g != null ) g . d i spo s e ( ) ;48 i f ( frame != null ) frame . removeNotify ( ) ;49 }50 }51 }
Daca tipul fisierului grafic va fi gif atunci linia 34 se ınlocuieste cu
FileOutputStream fos=new FileOutputStream(f);
GifEncoder encoder = new GifEncoder(image,fos);
encoder.encode();
6.4. FACILITATI DE PROGRAMARE CU SERVLET 163
Clasa GifEncoder care realizeaza codarea, face parte din pachetul Acme.JPM.Encoders,disponibil gratuit la adresa web http://www.acme.com.
6.4.8 Servlet cu RMI
Un servlet poate fi client al unei aplicatii RMI. Interfata la diatanta se depuneın catalogul WEB-INF\lib al servletului. Apelarea programului server RMI se faceprin
InterfataDistanta obj=(InterfataDistanta)
Naming.lookup("//"+host+":"+port+"/NumeServiciuRMI");
Exemplul 6.4.7 Client servlet pentru aplicatia RMI de calcul al celui mai maredivizor comun a doua numere naturale.
1 import java . i o . ∗ ;2 import java . rmi . ∗ ;3 import java . rmi . r e g i s t r y . ∗ ;4 import javax . s e r v l e t . ∗ ;5 import javax . s e r v l e t . http . ∗ ;6 import cmmdc . ∗ ;
8 public class ServletRMI extends HttpServ l e t {
10 public void doGet ( HttpServ letRequest req , HttpServletResponse r e s )11 throws Serv le tExcept ion , IOException {12 r e s . setContentType ( ” text /html” ) ;13 PrintWriter out = r e s . getWriter ( ) ;
15 St r ing sm=req . getParameter ( ”m” ) , sn=req . getParameter ( ”n” ) ;16 long m=(new Long (sm ) ) . longValue ( ) , n=(new Long ( sn ) ) . longValue ( ) ;17 long x=0;
19 St r ing host=req . getParameter ( ” host ” ) . tr im ( ) ;20 St r ing sPort=req . getParameter ( ” port ” ) ;21 int port=I n t e g e r . pa r s e In t ( sPort ) ;
23 try{24 ICmmdc obj=(ICmmdc)Naming . lookup ( ”//”+host+” : ”+port+”/CmmdcServer” ) ;25 x=obj . cmmdc(m, n ) ;26 }27 catch ( Exception e ) {28 System . out . p r i n t l n ( ”CmmdcClient except ion : ”+e . getMessage ( ) ) ;29 }30 St r ing t i t l e=”CmmdcServlet” ;31 r e s . setContentType ( ” text /html” ) ;32 out . p r i n t l n ( ”<HTML><HEAD><TITLE>” ) ;33 out . p r i n t l n ( t i t l e ) ;34 out . p r i n t l n ( ”</TITLE></HEAD><BODY>” ) ;35 out . p r i n t l n ( ”<H1>”+t i t l e+”</H1>” ) ;36 out . p r i n t l n ( ”<P>Cmmdc : ”+x ) ;37 out . p r i n t l n ( ”</BODY></HTML>” ) ;38 out . c l o s e ( ) ;39 }
164 CAPITOLUL 6. SERVLET
41 public void doPost ( HttpServ letRequest req , HttpServletResponse r e s )42 throws Serv le tExcept ion , IOException{43 doGet ( req , r e s ) ;44 }45 }
6.4.9 Servlet cu JMS
De data aceasta cererea clientului se rezolva asincron:
• In prima faza se apeleaza un servlet care apeleaza un server JMS. Solutia esteretinuta de furnizorul serviciului de mesagerie pe o destinatie cu un subiectfurnizat de client. Pentru regasirea rezultatului, servlet-ul creaza clientului unabonament durabil, functie de numele subiectului.
• In faza a doua, clientul apeleaza un alt servlet, a carei functie este preluarearezultatului. Clientul trebuie sa furnizeze subiectul destinatiei rezultatului.
Exemplul 6.4.8
Codul serverului JMS
1 import javax . jms . ∗ ;2 import java . i o . ∗ ;3 import java . u t i l . S t r ingToken i ze r ;
5 public class MsgCmmdcServer{
7 long cmmdc( long m, long n ) { . . .}
9 public void s e r v i c e ( ){10 try{11 // Varianta Apache−MessageQueue12 //org . apache . act ivemq . ActiveMQConnectionFactory c f=13 // new org . apache . activemq . ActiveMQConnectionFactory (14 // ” tcp :// l o c a l h o s t :61616”) ;
16 // Varianta Oracle−Sun MessageQueue17 com . sun . messaging . TopicConnectionFactory c f=18 new com . sun . messaging . TopicConnectionFactory ( ) ;19 // c f . se tProper ty (” imqBrokerHostName” ,” hos t ” ) ;20 // c f . se tProper ty (” imqBrokerHostPort ” ,”7676”);21 TopicConnection conn=c f . createTopicConnect ion ( ) ;22 TopicSess ion s e s s i o n=23 conn . c r ea t eTop i cSe s s i on ( false , S e s s i on .AUTOACKNOWLEDGE) ;24 Dest inat i on tDate=s e s s i o n . c reateTopic ( ”Cmmdc” ) ;25 TopicSubscr iber consumer=s e s s i o n . c r e a t e S u b s c r i b e r ( ( Topic ) tDate ) ;26 conn . s t a r t ( ) ;27 TextMessage txtMsg=null ;28 St r ing sm=”” , sn=”” , t op i c=”” ;29 while ( true ){30 txtMsg=(TextMessage ) consumer . r e c e i v e ( ) ;31 St r ing msg=txtMsg . getText ( ) ;
6.4. FACILITATI DE PROGRAMARE CU SERVLET 165
32 Str ingToken i ze r s t=new Str ingToken i ze r (msg , ” ” ) ;33 int i =0;34 while ( s t . hasMoreElements ( ) ){35 i ++;36 i f ( i ==1) sm=s t . nextToken ( ) ;37 i f ( i ==2) sn=s t . nextToken ( ) ;38 i f ( i ==3) t o p i c=s t . nextToken ( ) ;39 }40 System . out . p r i n t l n (sm+” : ”+sn+” : ”+to p i c ) ;41 long a=Long . parseLong (sm ) ;42 long b=Long . parseLong ( sn ) ;43 long c=cmmdc( a , b ) ;44 Dest inat i on tResu l t=s e s s i o n . c reateTop ic ( t op i c ) ;45 MessageProducer producer=s e s s i o n . c reateProducer ( tResu l t ) ;46 txtMsg=s e s s i o n . createTextMessage ( (new Long ( c ) ) . t oS t r i ng ( ) ) ;47 producer . send ( txtMsg ) ;48 System . out . p r i n t l n ( ” Expediat raspuns ” ) ;49 }50 }51 catch ( Exception e ){52 System . out . p r i n t l n ( ” Exception : ”+e . getMessage ( ) ) ;53 }54 System . out . p r i n t l n ( ” Server f i n i s h e d ” ) ;55 }
57 public stat ic void main ( St r ing [ ] a rgs ){58 MsgCmmdcServer s e r v e r=new MsgCmmdcServer ( ) ;59 s e r v e r . s e r v i c e ( ) ;60 }61 }
Codul servlet-ului care transmite datele problemei serverului JMS
1 package jms ;2 import javax . jms . ∗ ;3 import java . i o . ∗ ;4 import javax . s e r v l e t . ∗ ;5 import javax . s e r v l e t . http . ∗ ;
7 public class JMSSenderServlet extends HttpServ l e t {
9 public void doGet ( HttpServ letRequest req , HttpServletResponse r e s )10 throws Serv le tExcept ion , IOException {11 r e s . setContentType ( ” text /html” ) ;12 ServletOutputStream out = r e s . getOutputStream ( ) ;13 St r ing m=req . getParameter ( ”m” ) ;14 St r ing n=req . getParameter ( ”n” ) ;15 St r ing t op i c=req . getParameter ( ” t o p i c ” ) ;16 St r ing c l i e n t I D=”JMSCmmdc” ;17 St r ing cl ientName=”JMSCmmdc” ;18 try{19 // Varianta Apache−MessageQueue20 //org . apache . act ivemq . ActiveMQConnectionFactory c f=21 // new org . apache . act ivemq . ActiveMQConnectionFactory (22 // ” tcp :// l o c a l h o s t :61616”) ;
24 // Varianta Oracle−Sun MessageQueue25 com . sun . messaging . TopicConnectionFactory c f=26 new com . sun . messaging . TopicConnectionFactory ( ) ;27 // c f . se tProper ty (” imqBrokerHostName” ,” hos t ” ) ;
166 CAPITOLUL 6. SERVLET
28 // c f . se tProper ty (” imqBrokerHostPort ” ,”7676”);29 TopicConnection conn=c f . createTopicConnect ion ( ) ;30 conn . s e tC l i en t ID ( c l i e n t I D ) ;31 TopicSess ion s e s s i o n=32 conn . c r ea t eTop i cSe s s i on ( false , S e s s i on .AUTOACKNOWLEDGE) ;33 Dest inat i on tResu l t=s e s s i o n . c reateTop ic ( t op i c ) ;34 TopicSubscr iber consumer=35 s e s s i o n . c r ea t eDurab l eSubsc r ibe r ( ( Topic ) tResult , cl ientName ) ;36 Dest inat i on t = s e s s i o n . c reateTop ic ( ”Cmmdc” ) ;37 MessageProducer producer = s e s s i o n . c reateProducer ( t ) ;38 TextMessage txtMsg=s e s s i o n . createTextMessage ( ) ;39 St r ing mesaj=m+” ”+n+” ”+t op i c ;40 txtMsg . setText ( mesaj ) ;41 producer . send ( txtMsg ) ;42 s e s s i o n . c l o s e ( ) ;43 conn . c l o s e ( ) ;44 out . p r i n t l n ( ”<html><body bgco lo r=\”#ccbbcc\”><center>” ) ;45 out . p r i n t l n ( ”<h1> JSP Cmmdc </h1>” ) ;46 out . p r i n t l n ( ”<p>” ) ;47 out . p r i n t l n ( ” Date le au f o s t exped ia te s e r v e r u l u i ” ) ;48 out . p r i n t l n ( ”</center></body></html>” ) ;49 }50 catch ( Exception e ){51 out . p r i n t l n ( e . getMessage ( ) ) ;52 }53 out . c l o s e ( ) ;54 System . out . p r i n t l n ( ” Pub l i she r f i n i s h e d ” ) ;55 }
57 public void doPost ( HttpServ letRequest req , HttpServletResponse r e s )58 throws Serv le tExcept ion , IOException {59 doGet ( req , r e s ) ;60 }61 }
Codul servlet-ului care preia rezultatul
1 package jms ;2 import javax . jms . ∗ ;3 import java . i o . ∗ ;4 import javax . s e r v l e t . ∗ ;5 import javax . s e r v l e t . http . ∗ ;
7 public class JMSReceiverServlet extends HttpServ l e t {
9 public void doGet ( HttpServ letRequest req , HttpServletResponse r e s )10 throws Serv le tExcept ion , IOException {11 r e s . setContentType ( ” text /html” ) ;12 ServletOutputStream out = r e s . getOutputStream ( ) ;13 St r ing t op i c=req . getParameter ( ” t op i c ” ) ;14 St r ing c l i e n t I D=”JMSCmmdc” ;15 St r ing cl ientName=”JMSCmmdc” ;16 try{17 // Varianta Apache−MessageQueue18 //org . apache . act ivemq . ActiveMQConnectionFactory c f=19 // new org . apache . act ivemq . ActiveMQConnectionFactory (20 // ” tcp :// l o c a l h o s t :61616”) ;
22 // Varianta Oracle−Sun MessageQueue23 com . sun . messaging . TopicConnectionFactory c f=
6.5. FILEUPLOAD 167
24 new com . sun . messaging . TopicConnectionFactory ( ) ;25 // c f . se tProper ty (” imqBrokerHostName” ,” hos t ” ) ;26 // c f . se tProper ty (” imqBrokerHostPort ” ,”7676”);27 TopicConnection conn=c f . createTopicConnect ion ( ) ;28 conn . s e tC l i en t ID ( c l i e n t I D ) ;29 TopicSess ion s e s s i o n=30 conn . c r ea t eTop i cSe s s i on ( false , S e s s i on .AUTOACKNOWLEDGE) ;31 Dest inat i on tResu l t = s e s s i o n . c reateTop ic ( t op i c ) ;32 TopicSubscr iber consumer=33 s e s s i o n . c r ea t eDurab l eSubsc r ibe r ( ( Topic ) tResult , cl ientName ) ;34 conn . s t a r t ( ) ;35 TextMessage txtMsg=(TextMessage ) consumer . r e c e i v e ( ) ;36 St r ing cmmdc=txtMsg . getText ( ) ;37 s e s s i o n . c l o s e ( ) ;38 conn . c l o s e ( ) ;39 out . p r i n t l n ( ”<html><body bgco lo r=\”#ccbbcc\”><center>” ) ;40 out . p r i n t l n ( ”<h1> JSP Cmmdc </h1>” ) ;41 out . p r i n t l n ( ”<p>” ) ;42 out . p r i n t l n ( ” Rezu l ta tu l obt inut : ”+cmmdc ) ;43 out . p r i n t l n ( ”</center></body></html>” ) ;44 }45 catch ( Exception e ){46 out . p r i n t l n ( e . getMessage ( ) ) ;47 }48 out . c l o s e ( ) ;49 System . out . p r i n t l n ( ” Subsc r ibe r f i n i s h e d ” ) ;50 }
52 public void doPost ( HttpServ letRequest req , HttpServletResponse r e s )53 throws Serv le tExcept ion , IOException {54 doGet ( req , r e s ) ;55 }56 }
In catalogul lib al servlet-ului trebuie incluse fisierele jar ale serviciului JMS folosit.
6.5 FileUpload
Deseori clientul trebuie sa furnizeze unui servlet un volum mare de date, de-pozitate ıntr-un fisier. Un produs care ne ajuta sa ındeplinim acest obiectiv estecommons-fileupload - dezvoltat de apache.
Commons-FileUpload - dezvoltat ın cadrul apache - este un produs care simplificatransferul unui fisier de la un client la programul server (file upload). Interfata deprogramare a produsului se refera la partea de server - ın cazul de fata reprezentatprin servlet.
Instalarea produsului consta din dezarhivarea fisierului descarcat din Internet.In plus este nevoie de
• commons-io
Fisierele
• commons-fileupload-*.*.jar
168 CAPITOLUL 6. SERVLET
• commons-io-*.*.jar
se depun ın catalogul lib al servlet-ului.Transferarea unui fisier, din partea clientului nu ridica nici o problema. In fisierul
html de apelare, se defineste un formular
<form
action=. . .
enctype="multipart/form-data"
method="post">
iar un fisier de ıncarcat se fixeaza prin intermediul marcajului
<input type="file" name=. . . size=. . .>
Programul navigator afiseaza o fereastra de cautare, prin care clientul selecteazafisierul pe care doreste sa-l ıncarce.
Daca partea de client este un program, atunci se utilizeaza commons-httpclient.6.4.1
De partea serverului, programarea ıncarcarii revine la
1. Crearea unei fabrici pentru manipularea fisierelor pe disc
FileItemFactory factory = new DiskFileItemFactory();
2. Crearea unei unelte de ıncarcare
ServletFileUpload upload = new ServletFileUpload(factory);
3. Analiza (parsarea) mesajului furnizat de client
List fileItems = upload.parseRequest(req);
Fiecare element al listei implementeaza interfata FileItem.
Se pot fixa parametrii
• dimensiunea zonei de pe disc destinata datelor de ıncarcat
DiskFileItemFactory factory = new DiskFileItemFactory();
factory.setSizeThreshold(maxMemorySize);
• catalogul temporar de retinere a datelor de ıncarcat
factory.setRepositoryPath(tempDirectory);
sau direct
6.5. FILEUPLOAD 169
DiskFileItemFactory factory = new DiskFileItemFactory(
maxMemorySize, tempDirectory);
• dimensiunea maxima a unui fisier
upload.setSizeMax(maxRequestSize);
4. Prelucrarea elementelor ıncarcate
Iterator iter=fileItems.iterator();
while (iter.hasNext()) {
FileItem item = (FileItem) iter.next();
if (item.isFormField()) {
// Prelucrarea elementului item care corespunde unei
// date din formularul html care nu este de tip fisier
}
else{
// Prelucrarea elementului item de tip fisier
}
}
5. In cazul unui element care nu este de tip fisier putem obtine numele si valoareaatributului furnizat de client
String name = item.getFieldName();
String value = item.getString();
6. In cazul unui fisier putem afla numele campului input, numele fisierului, di-mensiunea fisierului
String fieldName = item.getFieldName();
String fileName = item.getName();
long sizeInBytes = item.getSize();
7. Daca dorim sa salvam fisierul pe calculatorul server atunci prelucrarea este
File uploadedFile = new File(...);
item.write(uploadedFile);
8. Daca datele fisierului se ıncarca ın memoria calculatorului atunci prelucrareaeste
InputStream in = item.getInputStream();
//preluarea datelor din fluxul in
. . .
in.close();
170 CAPITOLUL 6. SERVLET
Alternativ, datele se pot retine ca un sir de octeti prin
byte[] data = item.get();
Exemplul 6.5.1 Sa se obtina ın memoria serverului matricea continuta ıntr-unfisier text. In fisierul text, fiecare linie contine o linie a matricei, iar elementelesunt separate prin spatii.
Metoda getMatrix utilizata reface matricea din datele fisierului.
1 package upload ;2 import java . i o . ∗ ;3 import javax . s e r v l e t . ∗ ;4 import javax . s e r v l e t . http . ∗ ;5 import java . u t i l . ∗ ;6 import org . apache . commons . f i l e u p l o a d . d i sk . ∗ ;7 import org . apache . commons . f i l e u p l o a d . s e r v l e t . ∗ ;8 import org . apache . commons . f i l e u p l o a d . ∗ ;
10 public class Fi l eUp loadSe rv l e t extends HttpServ l e t {
12 public void doPost ( HttpServ letRequest req , HttpServletResponse r e s )13 throws Serv le tExcept ion , IOException {14 r e s . setContentType ( ” text / p l a i n ” ) ;15 ServletOutputStream out = r e s . getOutputStream ( ) ;16 try{17 boolean i s M u l t i p a r t = Serv l e tF i l eUp load . i sMult ipartContent ( req ) ;18 Fi le I temFactory f a c t o r y = new DiskFi le I temFactory ( ) ;19 Serv l e tF i l eUp load upload = new Serv l e tF i l eUp load ( f a c t o r y ) ;20 L i s t i tems = upload . parseRequest ( req ) ;21 upload . setSizeMax (1000000) ;22 I t e r a t o r i t e r=items . i t e r a t o r ( ) ;23 while ( i t e r . hasNext ( ) ) {24 Fi l e I tem item = ( Fi l e I tem ) i t e r . next ( ) ;25 i f ( ! item . isFormFie ld ( ) ) {26 St r ing f i leName = item . getName ( ) ;27 out . p r i n t l n ( f i leName ) ;28 long s i z e InByt e s = item . g e t S i z e ( ) ;29 out . p r i n t l n ( s i z e InByt e s ) ;30 InputStream in=item . getInputStream ( ) ;31 InputStreamReader i s r=new InputStreamReader ( in ) ;32 BufferedReader br=new BufferedReader ( i s r ) ;33 double [ ] [ ] matrix=getMatrix ( br ) ;34 int m=matrix . l ength ;35 int n=matrix [ 0 ] . l ength ;36 for ( int i =0; i<m; i ++){37 for ( int j =0; j<n ; j++)38 out . p r i n t ( matrix [ i ] [ j ]+” ” ) ;39 out . p r i n t l n ( ) ;40 }41 br . c l o s e ( ) ;42 i s r . c l o s e ( ) ;43 in . c l o s e ( ) ;44 out . c l o s e ( ) ;45 }46 }47 }
6.5. FILEUPLOAD 171
48 catch ( Exception e ){49 System . out . p r i n t l n ( ” Exception : ”+e . getMessage ( ) ) ;50 }51 }
53 private double [ ] [ ] getMatrix ( BufferedReader br ) throws Exception {54 Vector<Double> v=new Vector<Double >(10) ;55 double [ ] [ ] matrix=null ;56 try{57 St r ing l i n e , s ;58 int m=0,n ,mn;59 do{60 l i n e=br . readLine ( ) ;61 i f ( l i n e !=null ){62 m++;63 St r ing [ ] s t=l i n e . s p l i t ( ” ” ) ;64 for ( S t r ing s : s t ){65 v . addElement (new Double ( s ) ) ;66 }67 }68 }69 while ( l i n e !=null ) ;70 i f ( v . s i z e ()>0){71 mn=v . s i z e ( ) ;72 n=mn/m;73 matrix=new double [m] [ n ] ;74 for ( int i =0; i<m; i ++){75 for ( int j =0; j<n ; j++){76 matrix [ i ] [ j ]=(( Double ) v . elementAt ( i ∗n+j ) ) . doubleValue ( ) ;77 System . out . p r i n t ( matrix [ i ] [ j ]+” ” ) ;78 }79 System . out . p r i n t l n ( ) ;80 }81 }82 }83 catch ( Exception e ){84 throw new Exception ( e . getMessage ( ) ) ;85 }86 return matrix ;87 }88 }
Pentru compilare se completeaza variabila de sistem classpath cu referinta catrefisierul commons-fileupload-*.*.jar.
Formularul clientului este
1 <html>2 <head>3 <script language=” j a v a s c r i p t ” >4 < !−−5 f unc t i on check I t (){6 var f i s=document . l i n e a r . my f i l e . value ;7 i f ( f i s==”” ){8 a l e r t (” S e l e c t a t i f i s i e r u l core spunzator mat r i c e i ” ) ;9 re turn f a l s e ;
10 }11 re turn true ;12 }13 //−−>
172 CAPITOLUL 6. SERVLET
14 </ script>15 </head>16 <body>17 <h1> Inc ă r ca r ea unui f i ş i e r </h1>18 <form19 action=” http :// l o c a l h o s t :8080/ upload / upload ”20 enctype=” mult ipar t /form−data ” method=” post ”21 name=” l i n e a r ” onSubmit=” return check I t ( ) ”>22 <p>23 S e l e c t a ţ i f i ş i e r u l24 <p>25 <input type=” f i l e ” name=” myf i l e ” s ize=30>26 <p>27 <input type=”submit” value=” Expediaza f i s i e r u l ”>28 </form>29 </body>30 </html>
6.6 Descarcarea unui fisier
Consideram cazul:
Exemplul 6.6.1 Fisierul ales de client dintr-o lista disponibila este descarcat fiindtransmis navigatorului.
1 import java . i o . ∗ ;2 import javax . s e r v l e t . ∗ ;3 import javax . s e r v l e t . http . ∗ ;
5 public class DownloadServlet extends HttpServ l e t {6 public void doGet ( HttpServ letRequest req , HttpServletResponse r e s )7 throws Serv le tExcept ion , IOException{8 ServletOutputStream out=r e s . getOutputStream ( ) ;9 St r ing f i l e=req . getParameter ( ” f i l e ” ) ;
10 St r ing c a l e=”webapps/download/ r e s o u r c e s /” ;11 try{12 Fi leInputStream f i s = new Fi leInputStream ( c a l e+f i l e ) ;13 BufferedInputStream b i s = new BufferedInputStream ( f i s ) ;14 byte [ ] bytes = new byte [ b i s . a v a i l a b l e ( ) ] ;15 r e s . setContentType ( ” Appl i ca t ion /Octet−stream ” ) ;16 b i s . read ( bytes ) ;17 out . wr i t e ( bytes ) ;18 b i s . c l o s e ( ) ;19 f i s . c l o s e ( ) ;20 out . c l o s e ( ) ;21 }22 catch ( Exception e ){23 r e s . setContentType ( ” text / p l a i n ” ) ;24 out . p r i n t l n ( ” Cererea d−voast ra nu poate f i s a t i s f a c u t a ” ) ;25 }26 out . c l o s e ( ) ;27 }
29 public void doPost ( HttpServ letRequest req , HttpServletResponse r e s )30 throws Serv le tExcept ion , IOException{
6.7. FILTRU 173
31 doGet ( req , r e s ) ;32 }33 }
6.7 Filtru
Un filtru se asemeana unui servlet, dar activitatea ıntreprinsa vizeaza uzualcontextul, adica ansamblul servletilor care fac parte din aplicatia Web.
Un filtru se declara ın fisierul web.xml prin
<web-app>
. . .
<filter>
<filter-name>nume_filtru</filter-name>
<filter-class>clasa_filtrului</filter-class>
</filter>
<filter-mapping>
<filter-name>nume_filtru</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
. . .
</web-app>
Clasa filtrului implementeaza interfata Filter, adica metodele
• public void init(FilterConfig filterConfig) throws ServletException
• public void destroy()
• public void doFilter(ServletRequest request,ServletResponse response, FilterChain filterChain)throws IOException, ServletException
Exemplul 6.7.1 Contextul myservlet contine doi servleti HelloServlet si Cmmdc-Servlet, apelabili respectiv din hello.html, cmmdc.html. Sa se programeze un filtrucare
• Redirecteaza solicitarea “/myservlet/hello” catre “/cmmdc.html”.
• Daca se cere ca natura raspunsului sa fie “text/xml” atunci invalideaza cererea.
Servletii HelloServlet si CmmdcServlet sunt cei dezvoltati la ınceputul acestuicapitol. Filtrul are codul
174 CAPITOLUL 6. SERVLET
1 import java . i o . IOException ;2 import javax . s e r v l e t . ∗ ;3 import javax . s e r v l e t . http . ∗ ;
5 public class MyFi l terDispatcher implements F i l t e r {6 private F i l t e r C o n f i g f i l t e r C o n f i g ;
8 public void i n i t ( F i l t e r C o n f i g f i l t e r C o n f i g ) throws Serv l e tExcept ion {9 this . f i l t e r C o n f i g = f i l t e r C o n f i g ;
10 }
12 public void dest roy ( ) {13 this . f i l t e r C o n f i g = null ;14 }
16 public void d o F i l t e r ( Serv l e tReques t request , Serv le tResponse response ,17 Fi l t e rCha in f i l t e r C h a i n ) throws IOException , Se rv l e tExcept ion {18 HttpServ letRequest req = ( HttpServ letRequest ) r eque s t ;19 HttpServletResponse r e s = ( HttpServletResponse ) re sponse ;20 St r ing u r i = req . getRequestURI ( ) ;21 i f ( u r i . equa l s ( ”/ myserv let ” ) | | u r i . equa l s ( ”/ myserv let /” ) )22 f i l t e r C h a i n . d o F i l t e r ( request , r e sponse ) ;23 else {24 i f ( u r i . equa l s ( ”/ myserv let / h e l l o ” ) ){25 St r ing d i spa t che rUr i=”/cmmdc . html” ;26 RequestDispatcher rd=reque s t . getRequestDispatcher ( d i spa t che rUr i ) ;27 rd . forward ( request , r e sponse ) ;28 }29 else {30 int index=u r i . l a s t IndexOf ( ” . ” ) ;31 i f ( index==−1){32 St r ing t i p=req . getParameter ( ” t i p ” ) ;33 i f ( t i p . equa l s ( ” t ext /xml” ) ){34 r e s . sendError ( HttpServletResponse .SC FORBIDDEN) ;35 }36 }37 f i l t e r C h a i n . d o F i l t e r ( request , r e sponse ) ;38 }39 }40 }41 }
Fisierul web.xml este
1 <?xml version=” 1 .0 ” encoding=”ISO−8859−1”?>2 < !DOCTYPE web−app3 PUBLIC ”−//Sun Microsystems , Inc . //DTD Web Appl i ca t ion 2 .3//EN”4 ” h t tp : // java . sun . com/dtd/web−app 2 3 . dtd”>
6 <web−app>7 < f i l t e r>8 < f i l t e r −name> f i l t e r D i s p a t c h e r</ f i l t e r −name>9 < f i l t e r −c l a s s>MyFi l terDispatcher</ f i l t e r −c l a s s>
10 </ f i l t e r>
12 < f i l t e r −mapping>13 < f i l t e r −name> f i l t e r D i s p a t c h e r</ f i l t e r −name>14 <ur l−pattern>/∗</ ur l−pattern>15 </ f i l t e r −mapping>
6.7. FILTRU 175
17 <s e r v l e t>18 <s e r v l e t−name>cmmdc</ s e r v l e t−name>19 <s e r v l e t−c l a s s>CmmdcServlet</ s e r v l e t−c l a s s>20 </ s e r v l e t>
22 <s e r v l e t>23 <s e r v l e t−name>h e l l o</ s e r v l e t−name>24 <s e r v l e t−c l a s s>H e l l o S e r v l e t</ s e r v l e t−c l a s s>25 </ s e r v l e t>
27 <s e r v l e t−mapping>28 <s e r v l e t−name>h e l l o</ s e r v l e t−name>29 <ur l−pattern>/ h e l l o</ ur l−pattern>30 </ s e r v l e t−mapping>
32 <s e r v l e t−mapping>33 <s e r v l e t−name>cmmdc</ s e r v l e t−name>34 <ur l−pattern>/cmmdc</ ur l−pattern>35 </ s e r v l e t−mapping>
37 </web−app>
Pentru ıntelegerea aplicatiei prezentam si codul fisierului cmmdc.html
1 <html>2 <head>3 <t i t l e>4 Cmmdc S e r v l e t5 </ t i t l e>6 </head>7 <body bgcolor=”#ccbbcc ”>8 <center>9 <h1> Cmmdc S e r v l e t </h1>
10 <form method=” get ”11 action=” http :// l o c a l h o s t :8080/ myserv let /cmmdc”>12 <table border=”1”>13 <tr>14 <td> Primul numar </td>15 <td> <input type=” text ” name=”m” s ize=10> </td>16 </ tr>17 <tr>18 <td> Al d o i l e a numar </td>19 <td> <input type=” text ” name=”n” s ize=10> </td>20 </ tr>21 <tr>22 <td> Natura ra spunsu lu i </td>23 <td> <select name=” t i p ” >24 <option value=” text /html”> t ex t /html25 <option value=” text / p l a i n ”> t ex t / p l a i n26 <option value=” text /xml”> t ex t /xml27 </ select> </td>28 </ tr>29 <tr>30 <td> <input type=”submit” value=” Calcu leaza ”> </td>31 <td></td>32 </ tr>33 </table>34 </form>35 </center>
176 CAPITOLUL 6. SERVLET
36 </body>37 </html>
Capitolul 7
Java Server Page – JSP
7.1 Tehnologia JSP
Tipul tehnologiei JSP este denumit procesare de sabloane (template engine). JSPeste o tehnologie similara cu PHP, ASP.NET, apache-velocity, etc. JSP permite in-cluderea de cod Java ıntr-un document html. Un asemenea document se depoziteazaıntr-un server Web, container de servlet, cu extensia jsp, eventual jspx.
Apelarea documentului JSP se realizeaza prin
• meniul File/Open a unui navigator, cu
http://host:port/cale/doc.jsp
• referinta html
<a href="http://host:port/cale/doc.jsp">
• valoare a atributului action ıntr-un marcaj form
<form action="http://host:port/cale/doc.jsp" ... >
Prin cale se ıntelege calea de la catalogul webapps pana la catalogul ce continefisierul jsp.
Vom depozita fisierele JSP ıntr-un catalog jsp din arborele
webapps
|--> JSPApp
| |--> WEB-INF
| | |--> classes
| | | web.xml
| |--> jsp
| | | doc.jsp
caz ın care cale=JSPApp/jsp.Astfel, schimband numele fisierului Hello.html
177
178 CAPITOLUL 7. JAVA SERVER PAGE – JSP
1 <html>2 <body>3 Hel lo4 </body>5 </html>
ın Hello.jsp si plasandu-l ın catalogul jsp se obtine acelasi efect, dar prelucrareapaginilor / documentelor este diferita. Fisierul html este prelucrat doar de progra-mul navigator si poate fi deschis ca fisier, ın timp ce fisierul JSP este prelucrat deserverul Web cu afisarea prin intermediul navigatorului. Prelucrarea efectuata deserverul Web consta din transformarea paginii / documentului JSP ıntr-un servlet,care este compilat si lansat ın executie. Din aceastra cauza prima invocare a paginii/ documentului JSP dureaza mai mult decat apelarile ulterioare.
Apelarea paginii / documentului JSP se face prinhttp://localhost:8080/JSPApp/jsp/Hello.jsp
Exista doua moduri de a include elemente JSP ıntr-un text html:
• prin elemente specifice JSP.
Fisierul are extensia jsp si se numeste pagina JSP.
• prin marcaje xml apartinand spatiului de nume
http://java.sun.com/JSP/Page
Fisierul poate avea extensia jsp sau jspx si se numeste document JSP.
Comentariile JSP se scriu de forma
<%-- Comentariu --%>
Consideram urmatorul exemplu introductiv:
Exemplul 7.1.1 Putem afisa valoarea unei variabile Java (de exemplu data calen-daristica) prin
• Varianta paginii JSP
1 <html>2 <body>3 <p>4 Data c a l e n d a r i s t i c a 1 :5 <%= new java . u t i l . Date ( ) %>
7 <p>8 <% java . u t i l . Date data1=new java . u t i l . Date ( ) ; %>9 Data c a l e n d a r i s t i c a 2 :
10 <%= data1 %>
7.1. TEHNOLOGIA JSP 179
12 <p>13 <% java . u t i l . Date data2=new java . u t i l . Date ( ) ; %>14 Data c a l e n d a r i s t i c a 3 :15 <% out . p r i n t ( data2 ) ; %>16 </body>17 </html>
Daca se utilizeaza operatorul de afisare = atunci dupa expresia de afisat nu sepune ;.
Variabila predefinita out este de tip javax.servlet.jsp.JspWriter.
• Varianta documentului JSP
1 <?xml v e r s i o n=” 1 .0 ” encoding=”UTF−8” ?>2 <html xmlns : j s p=” http :// java . sun . com/JSP/Page”>3 <body>4 <j sp : d e c l a r a t i o n>5 java . u t i l . Date d=new java . u t i l . Date ( ) ;6 </ j sp : d e c l a r a t i o n>7 <j sp : exp r e s s i on> d </ j sp : exp r e s s i on>8 </body>9 </html>
Codul Java inglobat ıntr-un text html se numeste scriptlet. Sintaxa utilizata este
• Varianta paginii JSP
<% cod Java %>
• Varianta documentului JSP
<jsp:scriptlet> codJava </jsp:scriptlet>
Domeniul de valabilitate. Domeniul de valabilitate defineste intervalul detimp, de existenta al unui obiect, fiind definit prin valorile:
Valoare Domeniu de valabilitate
page pagina curentarequest ın pagina curenta,
ın paginile incluse siın paginile catre care se face o redirectare
session ın sesiunea curentaapplication pe durata rularii aplicatiei
In orice pagina / document JSP sunt predefinite obiectele:
180 CAPITOLUL 7. JAVA SERVER PAGE – JSP
Variabila Tip/Clasa
out javax.servlet.jsp.JspWriterrequest javax.servlet.ServletRequestresponse javax.servlet.ServletResponsesession javax.servlet.http.HttpSessionpage java.lang.Object, thispageContext javax.servlet.jsp.PageContextapplication javax.servlet.ServletContext
ServletContext.getServletConfig().getContext()exception java.lang.Throwable
Astfel
String request.getParameter(String numeParametru)
furnizeaza valoarea parametrului numeParametru dintr-un formular html.
Exemplul 7.1.2 Pagina JSP Hello: Clientul transmite numele paginii care ıi raspundecu mesajul de salut ”Hi ” + nume + ” !”.
Codul paginii JPS (hello.jsp) este
1 <html>2 <head>3 <t i t l e> j s p h e l l o </ t i t l e>4 </head>5 <body>6 <center>7 <h1> Pagina de ră spuns </h1>8 <p>9 <%
10 out . p r i n t l n ( ”Hi ”+reques t . getParameter ( ”name”)+” ! ” ) ;11 %>12 </center>13 </body>14 </html>
apelat din (index.html)
1 <html>2 <head>3 <t i t l e> JSP Hel lo </ t i t l e>4 </head>5 <body bgcolor=”#bbeebb”>6 <center>7 <h1> Pagina de ape l a r e JSP </h1>8 <form method=” post ”9 action=” http :// l o c a l h o s t :8080/ j s p h e l l o / j sp / h e l l o . j sp ”>
10 <p> Numele :11 <input type=” text ” name=”name” s ize=20>12 <p>13 <input type=”submit”>
7.1. TEHNOLOGIA JSP 181
14 </form>15 </center>16 </body>17 </html>
Compilarea si arhivarea servlet-ului o vom realiza prin intermediul lui apache-ant. In acest scop se creaza structura:
jsphello
| |--> jsp
| | | hello.jsp
| |--> lib
| |--> src
| |--> web
| | | web.xml
| |--> web-files
| | | index.html
| build.xml
Fisierul web.xml este simplu
1 <?xml version=” 1 .0 ” encoding=”ISO−8859−1”?>
3 < !DOCTYPE web−app4 PUBLIC ”−//Sun Microsystems , Inc . //DTD Web Appl i ca t ion 2 .3//EN”5 ” h t tp : // java . sun . com/dtd/web−app 2 3 . dtd”>
7 <web−app>8 <welcome− f i l e − l i s t>9 <welcome− f i l e>index . html</welcome− f i l e>
10 <welcome− f i l e>index . j sp</welcome− f i l e>11 </welcome− f i l e − l i s t>12 </web−app>
Fisierul build.xml prelucrat de apache-ant este
1 <project based i r=” . ” d e f a u l t=” generate . war”>
3 <property name=”TOMCATHOME” value=” d: /apache−tomcat −5.5.26 ”/>4 <property name=” d i s t . name” value=” j s p h e l l o ” />5 <property name=” d i s t . d i r ” value=” d i s t ” />6 <property name=” bu i ld . d i r ” va lue=” bu i ld ”/>
8 <path id=” myclasspath ”>9 <f i l e s e t d i r=” l i b ”>
10 <include name=” ∗ . j a r ”/>11 </ f i l e s e t>12 <pathelement path=”${TOMCATHOME}/ l i b / s e r v l e t−api . j a r ” />13 </path>
15 <target name=” i n i t ”>16 <delete d i r=”${ d i s t . d i r }”/>17 <mkdir d i r=”${ bu i ld . d i r }”/>18 <mkdir d i r=”${ d i s t . d i r }” />19 <mkdir d i r=”${ bu i ld . d i r }/ j sp ” />20 <mkdir d i r=”${ bu i ld . d i r }/WEB−INF” />21 <mkdir d i r=”${ bu i ld . d i r }/WEB−INF/ c l a s s e s ” />22 <mkdir d i r=”${ bu i ld . d i r }/WEB−INF/ l i b ” />23 </target>
182 CAPITOLUL 7. JAVA SERVER PAGE – JSP
25 <target name=” compile ” depends=” i n i t ”>26 <javac c l a s s p a t h r e f=” myclasspath ”27 s r c d i r=”${ based i r }/ s r c ”28 d e s t d i r=”${ bu i ld . d i r }/WEB−INF/ c l a s s e s ” />29 </target>
31 <target name=” generate . war” depends=” compile ”>32 <copy t o d i r=”${ bu i ld . d i r }” >33 <f i l e s e t d i r=”${ based i r }/web− f i l e s ” >34 <include name=” ∗ . html” />35 </ f i l e s e t>36 </copy>37 <copy t o d i r=”${ bu i ld . d i r }/ j sp ” >38 <f i l e s e t d i r=”${ based i r }/ j sp ” >39 <include name=” ∗ . j s p ” />40 <include name=” ∗ . j spx ” />41 </ f i l e s e t>42 </copy>43 <copy t o d i r=”${ bu i ld . d i r }/WEB−INF” >44 <f i l e s e t d i r=”${ based i r }/web” >45 <include name=” ∗ . xml” />46 </ f i l e s e t>47 </copy>48 <copy t o d i r=”${ bu i ld . d i r }/WEB−INF/ l i b ” >49 <f i l e s e t d i r=”${ based i r }/ l i b ” >50 <include name=” ∗ . j a r ” />51 </ f i l e s e t>52 </copy>53 <copy t o d i r=”${ bu i ld . d i r }” >54 <f i l e s e t d i r=”${ based i r }” >55 <include name=” ∗ . p r o p e r t i e s ” />56 </ f i l e s e t>57 </copy>58 <jar d e s t f i l e=”${ d i s t . d i r }/${ d i s t . name } . war” bas ed i r=”${ bu i ld . d i r }” />59 </target>60 </project>
7.1.1 Declaratii JSP
Printr-o declaratie JSP, putem defini campuri(variabile) si metode Java ce potfi apoi folosite, respectiv apelate ın documentul respectiv. O declaratie JSP sedefineste printr-un marcaj
<%! . . . %>
sau, ın format XML
<jsp:declaration> . . . </jsp:declaration>
Exemplul 7.1.3 Calculul celui mai mare divizor comun a doua numere naturalecu metoda de calcul este definita ıntr-o declaratie JSP.
Pagina JSP a aplicatiei cmmdc.jsp:
7.1. TEHNOLOGIA JSP 183
1 <html>2 <body>3 <H1> CMMDC </H1>4 <%!5 long cmmdc( long m, long n){6 long c , r ;7 do{8 c=n ;9 r=m%n ;
10 m=n ;11 n=r ;12 }whi le ( r !=0) ;13 r e turn c ;14 }15 %>16 Rezu l ta tu l e s t e17 <%18 String sm=reques t . getParameter ( ”m” ) ;19 String sn=reques t . getParameter ( ”n” ) ;20 long m=Long . parseLong (sm) , n=Long . parseLong ( sn ) ;21 out . p r i n t l n (cmmdc(m, n ) ) ;22 %>23 </body>24 </html>
apelat din documentul cmmdc.html
1 <html>2 <body>3 <h1> Calcu lu l Cmmdc </h1>4 <form method=” post ”5 action=” http :// l o c a l h o s t :8080/JSPApp/ j sp /cmmdc . j sp ”>6 <p>7 Primul numar e s t e8 <input type=” text ” name=”m” value=”” s ize=5>9 <p>
10 Al d o i l e a numar e s t e11 <input type=” text ” name=”n” value=”” s ize=5>12 <p>13 <input type=”submit” value=” Calcu leaza ”>14 <input type=” r e s e t ” value=”Abandon”>15 </form>16 </body>17 </html>
Exista doua metode jspInit() - utilizata pentru initializarea datelor -, si jspDestroy()- utilizata pentru eliberarea resurselor -, care daca sunt declarate de programatoratunci sunt executate la ınceputul si la sfarsitul ciclului de executie a paginii /documentului JSP.
7.1.2 Directive JSP
Directivele JSP fixeaza informatii pentru tot documentul jsp. O directiva jsp seindica prin marcajul
<%@ directiva atribut1 atribut2 . . . %>
184 CAPITOLUL 7. JAVA SERVER PAGE – JSP
sau ın format XML
<jsp:directive.directiva atribut1 atribut2 . . . />
unde fiecare atribut are sintaxa nume=valoare.
Directivele pot fi: page, include, taglib.
• Directiva page. Mentionam atributele
import= ”lista de pachete separate prin ,”info= ”text” Informatia se poate regasi apeland metoda
getServletInfo()errorPage= ”adresa url a paginii ce trateaza exceptia”isErrorPage= "true | false"
• Directiva include permite includerea unor fisiere .html sau .jsp ın document
<%@ include file=”fisier html, jsp” %>
Includerea are loc ın locul ın care apare directiva.
Referinta la fisierul html sau jsp se face relativ la catalogul paginii JSP initiale(adica cea ın care apare directiva).
• Directiva taglib indica bibliotecile de marcaje utilizate ın documentul jsp,avand atributele
uri= ”uri - Universal Resource Identifier - a bibliotecii de marcaje”prefix= ”prefixul marcajului”
7.1.3 Marcaje JSP predefinite
Un marcaj JSP defineste o actiune care se executa ın timpul procesarii paginiijsp. Sintaxa marcajelor JSP seamana cu cea a marcajelor html sau xml
<prefix : marcaj atribute />
Dintre marcajele JSP predefinite – adica cu prefixul JSP – amintim:
• <jsp : include page=”numeFisier jsp sau html” />
• <jsp : forward page=”numeFisier jsp sau html” />
Prelucrarea care urmeaza va fi cea din fisierul mentional. Diferenta dintre celedoua elemente consta ın faptul ca include prevede revenirea ın pagina JSPinitiala iar forward nu.
Referinta la fisierul html sau jsp se face relativ la catalogul paginii JSP initiale.
7.1. TEHNOLOGIA JSP 185
In cazul marcajelor <jsp: include>, <jsp: forward> se pot transmiteparametri prin marcajele incluse<jsp:param name="nume" value=valoare "/>
sau<jsp:params>
<jsp:param name="nume" value=valoare "/>. . . . . .
</jsp:params>
• <jsp : useBean id=”numeComponentaJava”class=”numeClasa”scope=”domeniu” />
unde domeniu precizeaza domeniul de valabilitate al componentei Java, adicapage, request, session, application.
Creaza un obiect ”numeComponentaJava” de tip ”numeClasa” avand dome-niul de valabilitate data de ”domeniu”.
• <jsp : setProperty name=”numeComponentaJava”property=”numeProp”value=”valoare”/>
Acest marcaj este echivalent cu codul JavanumeComponentaJava.setNumeProp(valoare).
<jsp : setProperty name=”numeComponentaJava” property="*" />vizeaza toate proprietatile componentei Java, fixarea valorilor facandu-se cudatele unui formular. Numele parametrilor din formularele de introducere adatelor trebuie sa coincida cu identificatorii campurilor din componenta Javacorespunzatoare.
• <jsp : getProperty name=”numeComponentaJava”property=”numeProp”/>
Preia si afiseaza valoarea campului numeComponentaJava.numeProp.
7.1.4 Componenta Java (Java Bean)
O componenta Java este o clasa care poate interactiona cu alte componente Java,cu un document jsp, etc.
O componenta Java contine cel putin
• Un constructor fara nici un argument;
• O multime de campuri declarate private;
186 CAPITOLUL 7. JAVA SERVER PAGE – JSP
• Pentru fiecare asemenea camp
private Tip xyz;
trebuie definite metodele
public void setXyz(Tip xyz){
this.xyz=xyz;
}
public Tip getXyz(){
return xyz;
}
7.1.5 Pagini JSP cu componente Java
Clasa componentei Java care se va utiliza ıntr-o pagina JSP trebuie inclusa ıntr-un pachet.
Reluam exemplul 7.1.2 cu o componenta Java corespunzatoare numelui din for-mularul index.html.
Exemplul 7.1.4
1 package j sp ;2 public class HelloBean {3 private St r ing name=”” ;4 public St r ing getName ( ) {5 return name ;6 }7 public void setName ( St r ing name) {8 this . name=name ;9 }
10 }
In acest caz, pagina JSP este (hello.jsp)
1 <j sp : useBean id=” obj ” class=” j sp . HelloBean ” scope=” reques t ”/>2 <j sp : s e tProper ty name=” obj ” property=”∗”/>3 <html>4 <head>5 <t i t l e> j s p h e l l o </ t i t l e>6 </head>7 <body>8 <h1> Pagina de ră spuns </h1>9 <center>
10 <%11 out . p r i n t l n ( ”Hi ”+obj . getName()+” ! ” ) ;12 %>13 </center>14 </body>15 </html>
7.1. TEHNOLOGIA JSP 187
Mai mult, se poate include formularul ın pagina JSP, bineınteles stergandu-l dinfisierul html:
1 <j sp : useBean id=” obj ” class=” j sp . HelloBean ” scope=” reques t ”/>2 <j sp : s e tProper ty name=” obj ” property=”∗”/>3 <html>4 <head>5 <t i t l e> j s p h e l l o </ t i t l e>6 </head>7 <body>8 <center>9 <h1> Pagina JSP − a p l i c a ţ i a He l lo </h1>
10 <form method=” post ”>11 <p> <h3> I n t r o d u c e t i numele : </h3>12 <input type=” text ” name=”name” s ize=20>13 <p>14 <input type=”submit”>15 </form>16 <p>17 <%18 out . p r i n t l n ( ”Hi ”+obj . getName()+” ! ” ) ;19 %>20 </center>21 </body>22 </html>
In vederea generarii arhivei war, desfasurarea aplicatiei va fi
jsphello
| |---> jsp
| | | hello.jsp
| |---> lib
| |---> src
| | |---> jsp
| | | | HelloBean.java
| |---> web
| | | web.xml
| |---> web-files
| | | index.html
| build.xml
Exemplul 7.1.5 Pagina JSP pentru calculul celui mai mare divizor comun cu metodade calcul definita ıntr-o componenta Java.
Utilizand documentului html din Exemplul 7.1.3 se defineste componenta Java
1 package cmmdc ;2 public class CmmdcBean{3 private St r ing m=”” ;4 private St r ing n=”” ;5 private St r ing cmmdc ;
7 public void setM ( St r ing m){8 this .m=m;9 }
10 public void setN ( St r ing n){11 this . n=n ;12 }
188 CAPITOLUL 7. JAVA SERVER PAGE – JSP
13 public St r ing getM (){14 return m;15 }16 public St r ing getN (){17 return n ;18 }
20 public St r ing getCmmdc ( ){21 long m=Long . parseLong (getM ( ) ) ;22 long n=Long . parseLong ( getN ( ) ) ;23 return (new Long (cmmdc(m, n ) ) ) . t oS t r i ng ( ) ;24 }
26 long cmmdc( long m, long n ) { . . .}
28 }
Instantiem o componenta Java si ıi fixam proprietatile (adica ıi transmitemparametri problemei) dupa care apelam metoda ce calculeaza rezultatul dorit ınpagina JSP:
1 <j sp : useBean id=” obj ” class=”cmmdc . CmmdcBean” scope=” a p p l i c a t i o n ”/>2 <j sp : s e tProper ty name=” obj ” property=”∗”/>3 <html>4 <body>5 Cel mai mare d i v i z o r comun a l numerelor6 <p>7 <%=obj . getM ( ) %> s i <%=obj . getN ( ) %>8 e s t e <%=obj . getCmmdc ( ) %>9 </body>
10 </html>
Exemplul 7.1.6 Generarea unei exceptii (errhandler.jsp):
1 <%@ page errorPage=” er ro rpage . j sp ” %>2 <html>3 <body>4 <%5 String mater ia=reque s t . getParameter ( ” mater ia ” ) . tr im ( ) ;6 i f ( mater ia . equa l s ( ”AN” ) ) {7 out . p r i n t l n ( ”<hr><f ont c o l o r=red>Alegere co r e c ta !</ font>” ) ;8 }9 e l s e {
10 throw new Exception ( ”N−a t i f a cu t a l e g e r e a co r e c ta ” ) ;11 }12 %>13 </body>14 </html>
cu pagina de tratare a exceptiei (errorpage.jsp)
7.2. JSP STANDARD TAG LIBRARY JSTL 189
1 < !−−2 Aceste comentar i i sunt f o a r t e importante in cazu l u t i l i z a r i i3 nav i g a t o ru l u i IE s i a l u i apache−tomcat −5 .∗ .∗ . / 6 .∗ .∗ . In l i p s a4 l o r nu se genereaza s a l t u l l a e x c ep t i e pr in pagina j s p .5 Rolu l comentar i i l o r e s t e marirea lung imi i f i s i e r u l u i de f a t a .
7 O a l t e r n a t i v a e s t e ca din IE6 . . . Options sa se d e z a c t i v e z e8 opt iunea ”Show f r i e n d l y HTTP e r r o r message”
10 Cu nav i ga t o ru l F i re fox nu e x i s t a aceas ta problema .11 −−>
13 <%@ page i sErrorPage=” true ” %>14 <html>15 <body>16 <div align=” cente r ”>17 <%= except ion . getMessage ( ) %>18 </div>
20 </body>21 </html>
apelate prin
1 <html>2 <body>3 <form method=post4 action=” http :// l o c a l h o s t :8080/ myserv let / j sp / e r rhand l e r . j sp ”>5 Care e s t e mater ia p r e f e r a t a din a n i i de s tud iu u n i v e r s i t a r ?6 <p>7 Algor i tmica s i programare8 <input type=” rad io ” name=” mater ia ” value=”AP” checked>9 <p>
10 Anal iza numerica11 <input type=” rad io ” name=” mater ia ” value=”AN”>12 <p>13 I n t e l i g e n t a a r t i f i c i a l a14 <input type=” rad io ” name=” mater ia ” value=”IA”>15 <p>16 <input type=submit>17 </form>18 </body>19 </html>
7.2 JSP Standard Tag Library JSTL
JSTL este o familie de biblioteci de marcaje ce ofera o serie de facilitati activitatiide realizare a paginilor Web. JSTL ajuta la separarea activitatii de programare deaceea a proiectare (design) a paginii Web.
JSTL este alcatuita din 5 biblioteci:
190 CAPITOLUL 7. JAVA SERVER PAGE – JSP
URI Descriere
http://java.sun.com/jsp/jstl/core Biblioteca de bazahttp://java.sun.com/jsp/jstl/xml Biblioteca de prelucrare
a documentelor xmlhttp://java.sun.com/jsp/jstl/fmt Biblioteca de formatare a datelorhttp://java.sun.com/jsp/jstl/sql Biblioteca de lucru cu baze de datehttp://java.sun.com/jsp/jstl/functions Biblioteca de functii ajutatoare
Instalarea bibliotecilor. Bibliotecile sunt livrate ımpreuna cu apache-tomcat-*ın catalogul apache-tomcat-*\webapps\examples\WEB-INF\lib prin fisierele jstl.jarsi standard.jar.
Utilizarea bibliotecilor. In vederea utilizarii, cele doua fisiere trebuie copiateın catalogul lib al aplicatiei care utilizeaza bibliotecile.
In pagina / documentul JSP, o biblioteca utilizata trebuie declarata printr-odirectiva taglib.
7.2.1 Biblioteca de baza
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
Marcaje din biblioteca de baza:
• c:set Fixeaza o valoare ıntr-o variabila.
Atribute ale marcajului:
Atribut Fel Descriere
var obligatoriu Numele variabilei ce va stoca valoareaexpresiei.
value optional Expresia care va fi evaluata si atribuitavariabilei
scope optional Domeniul de valabilitate al variabilei.Unul din valorile:page, request, session, application.
Referirea la o variabila se face prin sintaxa ${numeVariabila}Referirea la valoarea unui camp dintr-un formular se face prin${param.numeCamp}Alaturi de obiectul param, alte obiecte predefinite sunt cookie, header,
initParam, pageContext.
Se pot defini variabile cu acelasi nume dar avand domenii de valabilitatediferita. Referirea se face prin ${pageScope.numeVariabila},
7.2. JSP STANDARD TAG LIBRARY JSTL 191
${requestScope.numeVariabila}, ${sessionScope.numeVariabila},${applicationScope.numeVariabila}.
Plasand clauza empty ınaintea unei variabile, ${empty numeVariabila}, seobtine false sau true dupa cum variabila are sau nu atribuita o valoare.
• c:remove Sterge o variabila.
Atribute ale marcajului:
Atribut Fel Descriere
var obligatoriu Numele variabilei ce se sterge.scope optional Domeniul de valabilitate al variabilei.
Unul din valorile:page, request, session, application.
• c:out Afiseaza o valoare.
Atribute ale marcajului:
Atribut Fel Descriere
value obligatoriu Valoarea ce se evalueaza si se afiseaza.default optional Cea ce se afiseaza ın cazul ın care
expresia nu poate fi evaluata.escapeXml optional true / false. Valoarea implicita este true.
Pe false interpreteaza caracterele din value
ca si cod html.
• c:if Test, verificarea unei conditii.
Atribute ale marcajului:
Atribut Fel Descriere
test obligatoriu Conditia de test.var optional Numele variabilei ce va stoca valoarea
testului.scope optional Domeniul de valabilitate al variabilei
definita anterior.
In cazul ın care conditia are valoarea true se prelucreaza corpul marcajului,ın caz contrar, acesta este ignorat.
Exemplul 7.2.1 Preluarea datelor unui formular cu campurile de intrare nume,prenume si email se face prin pagina JSP
192 CAPITOLUL 7. JAVA SERVER PAGE – JSP
1 <HTML>2 <%@ t a g l i b u r i=” http :// java . sun . com/ j sp / j s t l / core ” p r e f i x=”c” %>3 <BODY>4 <p>5 <c : i f t e s t=”${empty param . nume}” var=”testNume” >6 <c : out value=”Numele l i p s e s t e ! ” />7 </c : i f>8 <c : i f t e s t=”${not testNume}” >9 Nume:<c : out value=”${param . nume}” />
10 </c : i f>11 <p>12 <c : i f t e s t=”${empty param . prenume}” var=” testPrenume ” >13 <c : out value=”Prenumele l i p s e s t e ! ” />14 </c : i f>15 <c : i f t e s t=”${not testPrenume}” >16 Prenume :<c : out value=”${param . prenume}” />17 </c : i f>18 <p>19 <c : i f t e s t=”${empty param . emai l }” var=” testEmai l ”>20 <c : out value=”Adresa E−Mail l i p s e s t e ! ” />21 </c : i f>22 <c : i f t e s t=”${not tes tEmai l }” >23 E−mail :<c : out value=”${param . emai l }” />24 </c : i f>25 </BODY>26 </HTML>
• c:choose Marcajul de selectie poate contine oricate marcaje c:when si cel multun marcaj c:otherwise. Fiecare marcaj c:when contine obligatoriu atributultest. Daca ıntr-un marcaj c:when conditia are valoarea true, atunci seprelucreaza corpul acelui marcaj. In cazul ın care toate marcajele c:when aufost evaluate cu false atunci se va prelucra marcajul c:otherwise (marcajfara atribute).
• c:forEach Ciclu.
Atribute ale marcajului:
Atribut Fel Descriere
items optional Colectia care se parcurge.var optional Numele variabilei ın care se stocheaza
valoarea elementului curent.begin optional Valoarea initiala a variabilei var.end optional Valoarea finala a variabilei var.step optional Valoarea pasului de iterare. Implicit este 1.varStatus optional Informatii despre elementul curent.
Variabila varStatus are campurile:
– index valoarea curenta a elementului dupa care se realizeaza ciclarea;
– count numarul iteratiei curente;
7.2. JSP STANDARD TAG LIBRARY JSTL 193
– first are valoarea true daca este primul element al ciclului;
– last are valoarea true daca este ultimul element al ciclului;
Exemplul 7.2.2 Lista parametrilor formularului de apelare a exemplului an-terior se afiseaza prin:
<h2> Lista parametrilor din formular </h2>
<ul>
<c:forEach items="${param}" var="p">
<li>
<c:out value="${p}" />
</li>
</c:forEach>
</ul>
Exemplul 7.2.3 Lista parametrilor unui header se afiseaza prin:
<h2> Lista campurilor din antet </h2>
<ul>
<c:forEach items="${header}" var="h">
<li>
<c:out value="${h}" />
</li>
</c:forEach>
</ul>
Exemplul 7.2.4 Evidentierea fontului cu care se scriu titlurile ıntr-un docu-ment html:
<c:forEach begin="1" end="6" var="i" >
<c:out value="<h${i}> Heading ${i} </h${i}>" escapeXml="false" />
</c:forEach>
• c:forTokens Asigura aceasi functionalitate ca si clasei java.util.String
Tokenizer.
Atribute ale marcajului:
Atribut Fel Descriere
value obligatoriu Valoarea ce se evalueaza si se afiseaza.expresiei.
default optional Cea ce se afiseaza ın cazul ın careexpresia nu poate fi evaluata.
escapeXml optional true / false. Valoarea implicita este true.Pe false interpreteaza caracterele din value
ca si cod html.
194 CAPITOLUL 7. JAVA SERVER PAGE – JSP
• c:import Permite includerea altor pagini JSP ın pagina curenta.
Atribute ale marcajului:
Atribut Fel Descriere
url obligatoriu Adresa documentului importat.context optional Context-ul paginii / documentului importat.
Simbolul /, urmat de numele unei aplicatiide pe acelasi server.
var optional Numele variabilei ın care va fi stocatdocumentul importat.
scope optional Domeniul de valabilitate al variabilei var.Unul din valorile:page, request, session, application.
Cu marcajul c:param se pot fixa parametri pentru pagina importata. Acestmarcaj are doua atribute name si value. Acesti parametri se transmit cumetoda get.
• c:redirect Redirectarea activitatea catre o alta pagina.
Atribute ale marcajului:
Atribut Fel Descriere
url obligatoriu Adresa paginii catre care se face redirectarea.context optional Context-ul paginii catre care se face redirectarea.
Simbolul /, urmat de numele unei aplicatiide pe acelasi server.
Prin redirectare, parametrii nu sunt retransmisi automat mai departe.
• c:url Retine adrese URL.
Atribute ale marcajului:
Atribut Fel Descriere
value obligatoriu Adresa documentului de retinut.context optional Context-ul documentului.
Simbolul /, urmat de numele unei aplicatiide pe acelasi server.
var optional Numele variabilei ın care va fi stocataadresa documentului.
scope optional Domeniul de valabilitate al variabilei var.Unul din valorile:page, request, session, application.
7.2. JSP STANDARD TAG LIBRARY JSTL 195
7.2.2 Biblioteca de lucru cu baze de date
<%@taglib uri="http://java.sun.com/jsp/jstl/sql" prefix="sql" %>
Marcaje din biblioteca de baza:
• sql:setDataSource Fixeaza referinta la baza de date.
Atribute ale marcajului:
Atribut Fel Descriere
dataSource optional Referinta la baza de datedriver optional Driver-ul bazei de dateurl optional url-ul bazei de dateusername optional nume utilizatorului bazei de datepassword optional parola de acces la baza de datevar optional variabila cu referinta la baza de datescope optional Domeniul de valabilitate al variabilei var.
• sql:query O interogare a bazei de date.
Atribute ale marcajului:
Atribut Fel Descriere
sql obligatoriu Fraza sqldataSource optional Referinta la baza de datestartRow optional Linia de la care se ıncepe interogareamaxRows optional Numarul maxim de rezultate acceptatevar obligatoriu Variabila cu rezultatele interogarii
bazei de datescope optional Domeniul de valabilitate al variabilei var.
• sql:update Actualizarea a bazei de date.
Atribute ale marcajului:
Atribut Fel Descriere
sql obligatoriu Fraza sqldataSource optional Referinta la baza de date
Exemplul 7.2.5 Sa se afiseze lista din agenda telefonica creata ın exemplul dinCap. Servlet.
1 <HTML>2 <%@ t a g l i b u r i=” http :// java . sun . com/ j sp / j s t l / core ” p r e f i x=”c” %>3 <%@ t a g l i b u r i=” http :// java . sun . com/ j sp / j s t l / s q l ” p r e f i x=” s q l ” %>4 <BODY>
196 CAPITOLUL 7. JAVA SERVER PAGE – JSP
5 <p>6 <s q l : setDataSource7 d r i v e r=” org . apache . derby . jdbc . C l i en tDr ive r ”8 u r l=” jdbc : derby :// l o c a l h o s t :1527/ AgendaTelefonica ”9 var=”db” />
10 <s q l : query11 dataSource=”${db}”12 var=” r e z u l t ”13 s q l=” s e l e c t ∗ from t e l e f ” />14 <c : i f t e s t=”${ r e z u l t . rowCount gt 0}” >15 <table>16 <tr>17 <c : forEach items=”${ r e z u l t . columnNames}” var=” c o l ”>18 <th>19 <c : out value=”${ c o l }” />20 </th>21 </c : forEach>22 </ tr>23 <c : forEach items=”${ r e z u l t . rowsByIndex}” var=” l i n e ” >24 <tr>25 <c : forEach items=”${ l i n e }” var=”elem” >26 <td>27 <c : out value=”${elem}” />28 </td>29 </c : forEach>30 </ tr>31 </c : forEach>32 </table>33 </c : i f>34 </BODY>35 </HTML>
7.3 Marcaje JSP personale
Programatorul poate crea marcaje JSP proprii care se grupeaza ın colectii numitebiblioteci de marcaje. O biblioteca de marcaje este reprezentat de o identificatordat sub forma unui URI —textitUniversal Resource Identifier).
7.3.1 Marcaje fara atribute si fara corp.
Pentru a crea unui asemenea marcaj JSP propriu este necesara definirea a patrucomponente:
1. O clasa de definitie a comportamentului marcajului JSP (tag handler class).
2. Descriptorul de biblioteca de marcaje JSP, care leaga clasa de definitie a mar-cajului cu identificatorul bibliotecii de marcaje.
3. Marcajul taglib a fisierului web.xml, care permite serverului Web sa gaseascadescriptorul bibliotecii de marcaje.
4. Fisierul JSP ce utilizeaza marcajul JSP (clientul).
7.3. MARCAJE JSP PERSONALE 197
Exemplificam acesta tehnologie prin
Exemplul 7.3.1 Sa se realizeze un marcaj dateTag, a carui efect sa fie afisareadatei calendaristice.
1. Clasa de definitie a comportamentului marcajului. Programul consta din:
(a) Importul pachetelor
import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.*;
Aceste pachete se gasesc ın fisierul jsp-api.jar.
(b) Un marcaj fara atribute si fara corp trebuie sa extinda clasa TagSupport
si sa suprascrie metoda doStartTag, care defineste activitatea intreprinsacand este ıntalnit marcajul ıntr-un document jsp. Metoda trebuie sareturneze constanta SKIP BODY.
public class NumeClasa extends TagSupport{
public int doStartTag(){
. . .
return SKIP_BODY;
}
}
(c) Scrierea ın fluxul de iesire se face cu un obiect JspWriter, care se obtinecu pageContext.getOut(). Metoda print a clasei JspWriter poategenera o exceptie IOException.
Textul sursa al clasei de definitie a comportamentului marcajului dateTag este:
1 package j sp ;2 import javax . s e r v l e t . j sp . ∗ ;3 import javax . s e r v l e t . j sp . tagext . ∗ ;4 import java . i o . ∗ ;5 import java . u t i l . ∗ ;
7 public class DateTag extends TagSupport{8 public int doStartTag ( ){9 try{
10 JspWriter out=pageContext . getOut ( ) ;11 out . p r i n t l n (new Date ( ) ) ;12 }13 catch ( IOException e ){14 System . out . p r i n t l n ( ”DateTagException ”+e . getMessage ( ) ) ;15 }16 return SKIP BODY;17 }18 }
198 CAPITOLUL 7. JAVA SERVER PAGE – JSP
2. Descriptorul de biblioteca de marcaje JSP este dependent de versiunea tomcatfolosita. Acest fisier trebuie sa aiba extensia tld (Taglib Language Definition).Localizarea acestui fisier este definita ın elementul taglib din web.xml. Incazul unei distributii ≥ apache-tomcat-5.*, acest fisier este (mylibtag.tld):
1 <?xml version=” 1 .0 ” encoding=”ISO−8859−1” ?>2 < !DOCTYPE t a g l i b3 PUBLIC ”−//Sun Microsystems , Inc . //DTD JSP Tag Library 1 .2//EN”4 ” h t tp : // java . sun . com/ j 2 e e /dtd/web−j s p t a g l i b r a r y 1 2 . dtd”>
6 < !−− a tag l i b r a r y d e s c r i p t o r −−>7 <t a g l i b>8 <t l i b−version> 1 .0 </ t l i b−version>9 <j sp−version> 1 .2 </ jsp−version>
10 <short−name> mytags </ short−name>11 <u r i>h t t p : // cs . unitbv . ro / mytagl ib</ u r i>12 <d e s c r i p t i o n> L i b r a r i e de marcaje </ d e s c r i p t i o n>
14 <tag>15 <name> dateTag </name>16 <tag−c l a s s> j sp . DateTag </tag−c l a s s>17 <body−content> EMPTY </body−content>18 <d e s c r i p t i o n> f u r n i z e a z a data curenta </ d e s c r i p t i o n>19 </ tag>20 </ t a g l i b>
Elementul uri contine identificatorul bibliotecii de marcaje, cs.unitbv.ro/mytaglib.
Pentru fiecare marcaj propriu se completeaza un marcaj tag. Pentru un mar-caj propriu fara atribute elementele acestui marcaj sunt
(a) name Numele simbolic al marcajului.
(b) tag-class Referinta la fisierul class al clasei de definitie a comportamen-tului marcajului propriu. Referinta se face relativ la catalogul...\WEB-INF\classes
(c) description Descrierea marcajului propriu.
(d) body-content In cazul nostru are valoarea EMPTY. In cazul unui marcajcu corp se da valoarea JSP.
3. Marcajul taglib din fisierul web.xml
<taglib>
<taglib-uri>
http://cs.unitbv.ro/mytaglib
</taglib-uri>
<taglib-location>
/WEB-INF/mylibtag.tld
</taglib-location>
</taglib>
7.3. MARCAJE JSP PERSONALE 199
Elementele marcajului taglib sunt:
(a) taglib-uri Identificatorul bibliotecii de marcaje.
(b) taglib-location Locatia fisierului descriptor de biblioteca de marcaje(numele calificat al fisierului, adica alcatuit din cale plus numele fisierului).
Astfel elementele constitutive se vor gasi ın:
webapps
|--> mytag
| |--> WEB-INF
| | |--> classes
| | | |--> jsp
| | | | |--> DateTag.class
| | | web.xml
| | | mylibtag.tld
| |--> jsp
| | | dateTag.jsp
4. Marcajele proprii se utilizeaza cu sintaxa
<prefix : NumeMarcaj />
Referinta la catalogul cu toate componentele necesare marcajului si prefixulse fixeaza ın directiva taglib.
Un fisier jsp care utilizeaza marcajul realizat este (dateTag.jsp):
1 <html>2 <head>3 <t i t l e>4 Tag pentru data c a l e n d a r i s t i c a curenta5 </ t i t l e>6 </head>7 <body>8 <%@ t a g l i b u r i=” http :// cs . unitbv . ro / mytagl ib ”9 p r e f i x=”mk” %>
10 <p>11 Data curenta e s t e :12 <mk: dateTag/>13 </body>14 </html>
200 CAPITOLUL 7. JAVA SERVER PAGE – JSP
7.3.2 Marcaje cu atribute si fara corp.
Realizam un marcaj ziuaTag cu un atribut ziua care va fi afisat ın momentulprelucrarii marcajului.
1. Pentru fiecare atribut clasa ce defineste actiunea marcajului trebuie sa continao metoda
public void setNumeAtribut(String value){...}
care preia valoarea atributului data de parametrul value.
Exemplul 7.3.2
Pentru exemplul enuntat aceasta clasa este
1 package j sp ;2 import javax . s e r v l e t . j sp . ∗ ;3 import javax . s e r v l e t . j sp . tagext . ∗ ;4 import java . i o . ∗ ;
6 public class ZiuaTag extends TagSupport{7 St r ing z iua ;
9 public void s e tZ iua ( S t r ing value ){10 z iua=value ;11 }
13 public int doStartTag ( ){14 try{15 JspWriter out=pageContext . getOut ( ) ;16 out . p r i n t l n ( z iua ) ;17 }18 catch ( IOException e ){19 System . out . p r i n t l n ( ” ZiuaTagException ”+e . getMessage ( ) ) ;20 }21 return SKIP BODY;22 }23 }
2. In descriptorul bibliotecii de marcaje pentru fiecare atribut se defineste unmarcaj <attribute>...< /attribute> avand incluse marcajele
Nume marcaj Semnificatie Fel
name numele atributului obligatoriu
required true | false dupa cum atributul e obligatoriuobligatoriu sau nu
rtexprvalue true | false dupa cum atributul optionalse poate utiliza ıntr-o expresie
< %= numeAtribut % >
7.3. MARCAJE JSP PERSONALE 201
Marcajul <tag> din descriptorul bibliotecii de marcaje devine
<tag>
<name> ziuaTag </name>
<tag-class> jsp.ZiuaTag </tag-class>
<body-content> EMPTY </body-content>
<description> furnizeaza argumentul ziua curenta </description>
<attribute>
<name> ziua </name>
<required> true </required>
<rtexprvalue> true </rtexprvalue>
</attribute>
</tag>
3. Utilizarea acestui marcaj este exemplificat ın
1 <html>2 <body>3 <form method=” get ”4 action=” http :// l o c a l h o s t :8080/ mytag/ j sp /ziuaTag . j sp ”>5 <p>Astazi , e s t e6 <select name=” z iua ”>7 <option value=” l u n i ”> Luni8 <option value=” marti ”> Marti9 <option value=” mie r cur i ”> Miercur i
10 <option value=” j o i ”> Jo i11 <option value=” v i n e r i ”> Viner i12 <option value=” simbata ”> Simbata13 <option value=”duminica ”> Duminica14 </ select>15 <p><input type=”submit” value=” Af i s eaza ”>16 </form>17 </body>18 </html>
unde ziuaTag.jsp este
1 <html>2 <head>3 <t i t l e> Tag cu marcaj </ t i t l e>4 </head>5 <body>6 <%@ t a g l i b u r i=” http :// cs . unitbv . ro / mytagl ib ”7 p r e f i x=”mk” %>8 <p>9 <%
10 String z i=reques t . getParameter ( ” z iua ” ) ;11 %>12 Ziua e s t e :13 <mk: ziuaTag z iua=”<%= z i %>” />14 </body>15 </html>
202 CAPITOLUL 7. JAVA SERVER PAGE – JSP
7.3.3 Marcaje cu corp.
In metoda doStartTag valoarea returnata trebuie sa fie EVAL BODY INCLUDE, ınloc de SKIP BODY.
In descriptorul bibliotecii de marcaje apare
<body-content> JSP </body-content>
ın loc de EMPTY.
Daca se doreste ca marcajul sa execute actiuni dupa interpretarea corpului,atunci acele activitati sunt definite ın metoda doEndTag. Aceasta metoda re-turneaza valoarea EVAL PAGE sau SKIP PAGE dupa cum se doreste sau nu continuareaprocesarii paginii jsp.
Exemplul 7.3.3 Fie marcajul modTag care modifica un text ın caractere mari saumici dupa valoarea atributului trans. Acest marcaj poate include ale elemente.
Codul clasei ce prelucreaza marcajul este
1 package j sp ;2 import javax . s e r v l e t . j sp . ∗ ;3 import javax . s e r v l e t . j sp . tagext . ∗ ;4 import java . i o . ∗ ;
6 public class ModTag extends TagSupport{7 St r ing text ;8 boolean toUpperCase ;
10 public void setText ( S t r ing value ){11 t ex t=value ;12 }
14 public void setTrans ( S t r ing value ){15 toUpperCase=(new Boolean ( value ) ) . booleanValue ( ) ;16 }
18 public int doStartTag ( ){19 try{20 JspWriter out=pageContext . getOut ( ) ;21 i f ( toUpperCase )22 out . p r i n t l n ( t ex t . toUpperCase ( ) ) ;23 else24 out . p r i n t l n ( t ex t . toLowerCase ( ) ) ;25 }26 catch ( IOException e ){27 System . out . p r i n t l n ( ”ModTagException ”+e . getMessage ( ) ) ;28 }29 return EVAL BODY INCLUDE;30 }31 }
Descriptorul bibliotecii de marcaje se completeaza cu
7.3. MARCAJE JSP PERSONALE 203
<tag>
<name> modTag </name>
<tag-class> jsp.ModTag </tag-class>
<body-content> JSP </body-content>
<description> modifica caracterele </description>
<attribute>
<name> text </name>
<required> true </required>
<rtexprvalue> true </rtexprvalue>
</attribute>
<attribute>
<name> trans </name>
<required> true </required>
<rtexprvalue> true </rtexprvalue>
</attribute>
</tag>
O pagina de utilizare a marcajului modTag cu un corp nevid este
1 <html>2 <body>3 <form method=” get ”4 action=” http :// l o c a l h o s t :8080/ mytag/ j sp /modtextTag . j sp ”>5 Introduce o f r a z ă6 <input type=” text ” name=” text ” s ize=”40” >7 <p>8 Se trans form ă în l i t e r e9 <select name=” trans ”>
10 <option value=”upperCase”> mari11 <option value=” lowerCase ”> mici12 </ select>13 <p><input type=”submit” value=” Af i s eaza ”>14 </form>15 </body>16 </html>
ımpreuna cu modtextTag.jsp
1 <html>2 <body>3 <%@ t a g l i b u r i=” http :// cs . unitbv . ro / mytagl ib ” p r e f i x=”mk” %>4 <%5 String text=reques t . getParameter ( ” t ext ” ) ;6 String t rans=reques t . getParameter ( ” t rans ” ) ;7 String t ;8 i f ( t rans . equa l s ( ”upperCase” ) )9 t=” true ” ;
10 e l s e11 t=” f a l s e ” ;12 %>13 <p>14 <mk: modTag text=”<%= text %>” t rans=”<%=t%>”>15 <mk: dateTag/>16 </mk: modTag>17 </body>18 </html>
204 CAPITOLUL 7. JAVA SERVER PAGE – JSP
Capitolul 8
Portlet
Prezentarea termenului de portlet se face ımpreuna cu cea de portal. Portalulca si portletul sunt aplicatii Web. Practic, un portal accesat afiseaza portlete ınferestre distincte, portletele fiind aplicatii pe care clientul le poate folosi (Fig. 8.1,Fig. 8.2).
Figure 8.1: Portal - Portlet.
O aplicatie portlet ındeplineste standardele JSR (Java Specification Request)168 si JSR 286.
Portalul este o aplicatie Web cu functionalitatile:
• Container de portleti. Containerul este responsabil de initializarea si dis-trugerea portletilor, de transmiterea cererilor catre portleti si de colectarearaspunsurilor.
• Agregarea continuturilor (Content aggregator). Permite afisarea si gestionareamai multor portlete.
• Asigura servicii dintre care amintim:
205
206 CAPITOLUL 8. PORTLET
Figure 8.2: Aparitia portlet-etelor ıntr-o pagina a unui portal.
– acces la portal pe baza de autentificare si autorizare. Odata autorizat,un client are acces la orice portlet.
– posibilitatea personalizarii portletelor de catre clienti.
Varietatea serviciilor variaza de la un portal la altul.
Portletul este o aplicatie Web care se aseamana cu servletul prin:
• Se instaleaza ıntr-un container.
• Genereaza continut dinamic.
• Ciclul de viata este gestionat de container.
• Interactioneaza cu clientul prin modelul request/reply.
Deosebirile unui portlet fata de un servlet sunt:
• Portletul poseda mai multe variante de tratare a cererilor.
• Prin conceptul de mod (mode) se specifica variante distincte prin care portle-tul reactioneaza. Sunt definite modurile VIEW, EDIT, HELP. Actiunile core-spunzatoare sunt definite ın metodele doView, doEdit, doHelp.
8.1. APACHE-PLUTO 207
• Prin WindowState se fixeaza spatiul utilizat de portlet. Valorile variabilei Win-dowState sunt NORMAL, MAXIMIZED, MINIMIZED. In varianta MAXIMIZEDportletul ocupa ıntreaga fereastra, ın timp ce ın varianta MINIMIZED portle-tul apare ıntr-o bara de titluri.
8.1 Apache-pluto
Pentru dezvoltarea unui portlet vom folosi produsul Apache-pluto care genereazaun portal ın care se pot instala / dezinstala usor portlete.
Instalarea produsului. Daca se descarca varianta ıncorporata ın serverul Webapache-tomcat, denumita pluto-bundle, atunci instalarea la dezarhivarea fisieruluidescarcat.
Utilizarea produsului. Dintr-un navigator, portalul se apeleaza prin
http://host:8080/pluto/portal
Accesul se face cu User name = password = pluto.
Instalarea unui portlet se face ın 2 pasi:
1. Desfasurarea portlet-ului: Fisierul arhivat al portletului, avand extensia war,se depune ın catalogul PlutoDomain. Apeland managerul lui apache-tomcatdin componenta Pluto admin se obtine instalarea portletului.
Alternativ, desfasurarea portlet-lui se va obtine cu apache-ant cu utilizareaunui fisier build.xml dedicat.
2. Publicarea portlet-ului se face prin componenta Pluto admin.
8.2 Dezvoltarea unui portlet
Compilarea si arhivarea unui portlet ın vederea desfasurarii se va face ruland antcu fisierul build.xml:
1 <?xml version=” 1 .0 ” encoding=”UTF−8”?>2 <p r o j e c t name=” p o r t l e t−bu i ld ” default=” deploy ” bas ed i r=” . ”>
4 <property environment=”env”/>5 < !−−6 Set CATALINAHOME or use −Dpluto . home=/path/ to /tomcat−with−p lu t o7 on command l i n e8 −−>9 <property name=” pluto . home” value=”${ env .CATALINA HOME}”/>
10 <property f i l e=” bu i ld . p r o p e r t i e s ”/>
12 < !−−13 Al l j a r s used by your p o r t l e t need to be in l i b in add i t i on to the14 p luto−ant−t a s k s j a r15 −−>
208 CAPITOLUL 8. PORTLET
16 <path id=” p r o j e c t . c l a s s p a t h ”>17 < f i l e s e t d i r=” l i b ”>18 <i n c l ude name=” ∗ . j a r ”/>19 </ f i l e s e t>20 < f i l e s e t d i r=”${ pluto . home}/ l i b ”>21 <i n c l ude name=” ∗ . j a r ”/>22 </ f i l e s e t>23 </path>
25 <t a skde f26 name=” assemble ”27 classname=” org . apache . p luto . ant . AssembleTask”28 c l a s s p a t h r e f=” p r o j e c t . c l a s s pa th ”29 />
31 <t a r g e t name=” assemble ”>32 <assemble33 webxml=”${web−i n f . d i r }/web . xml”34 por t l e txml=”${web−i n f . d i r }/ p o r t l e t . xml”35 d e s t f i l e=”${ bu i ld . d i r }/web . xml”36 />37 </ t a r g e t>
39 <t a r g e t name=” i n i t ” d e s c r i p t i o n=” Creates bu i ld d i r s ”>40 <echo message=”Ant v e r s i on = ${ ant . v e r s i on }”/>41 <mkdir d e s c r i p t i o n=” Creates bu i ld d i r e c t o r y i f needed”42 d i r=”${ bu i ld . d i r }”/>43 <mkdir d e s c r i p t i o n=” Creates war d i r e c t o r y i f needed”44 d i r=”${webbuild . d i r }”/>45 <mkdir d e s c r i p t i o n=” Creates WEB−INF d i r e c t o r y i f needed”46 d i r=”${webbuild . d i r }/WEB−INF”/>47 <mkdir d e s c r i p t i o n=” Creates WEB−INF/ c l a s s e s d i r e c t o r y i f needed”48 d i r=”${ c l a s s b u i l d . d i r }”/>49 <mkdir d e s c r i p t i o n=” Creates WEB−INF/ l i b d i r e c t o r y i f needed”50 d i r=”${webbuild . d i r }/WEB−INF/ l i b ”/>51 </ t a r g e t>
53 <t a r g e t name=” compile ” depends=” i n i t ” d e s c r i p t i o n=”Compiles source ”>54 <javac c l a s s p a t h r e f=” p r o j e c t . c l a s s p a t h ”55 f o rk=” yes ”56 debug=” true ”57 debug l eve l=” l i n e s , vars , source ”58 d e s t d i r=”${ c l a s s b u i l d . d i r }”59 s r c d i r=”${ java . s r c . d i r }”/>60 </ t a r g e t>
62 <t a r g e t name=”war” depends=” compile ”>63 < !−− Move web f i l e s exc lud ing web .xml −−>64 <copy t o d i r=”${webbuild . d i r }/”>65 < f i l e s e t d i r=”${web . d i r }” exc ludes=”∗∗/web . xml”/>66 </copy>
68 < !−− Move other neccessary l i b r a r i e s −−>69 <copy t o d i r=”${webbuild . d i r }/WEB−INF/ l i b /”>70 < f i l e s e t d i r=”${ l i b . d i r }”>71 <i n c l ude name=” ∗∗/∗ . j a r ”/>72 <exc lude name=” c a s t o r ∗ . j a r ”/>73 <exc lude name=” pluto ∗ . j a r ”/>74 <exc lude name=” p o r t l e t ∗ . j a r ”/>
8.2. DEZVOLTAREA UNUI PORTLET 209
75 <exc lude name=” s e r v l e t ∗ . j a r ”/>76 <exc lude name=” j u n i t ∗ . j a r ”/>77 </ f i l e s e t>78 </copy>
80 <a n t c a l l t a r g e t=” assemble ”/>
82 < !−− Create war in deployment d i r e c t o r y −−>83 <war based i r=”${webbuild . d i r }” update=” f a l s e ”84 w a r f i l e=”${app . name } . war”85 webxml=”${ bu i ld . d i r }/web . xml”/>86 </ t a r g e t>
88 <t a r g e t name=” bu i ld ” depends=” clean , war”/>
90 <t a r g e t name=” deploy ” depends=” bu i ld ”>91 <echo message=” Deploying to p luto . home=${pluto . home}”/>92 < !−−93 Remove former deployment because sometimes94 tomcat does not f u l l y redep loy a war95 −−>96 <d e l e t e97 d i r=”${ pluto . home}/webapps/${app . name}”98 f a i l o n e r r o r=” true ”99 />
100 < !−− Deploy war f i l e −−>101 <copy102 f i l e=”${app . name } . war”103 t o d i r=”${ pluto . home}/PlutoDomain”104 ove rwr i t e=” true ”105 />106 < !−− Deploy con tex t deployment d e s c r i p t o r f o r Tomcat −−>107 <copy108 f i l e=”${ conf . d i r }/${app . name } . xml”109 t o d i r=”${ pluto . home}/ conf / Cata l ina / l o c a l h o s t ”110 ove rwr i t e=” f a l s e ”111 />
113 </ t a r g e t>
115 <t a r g e t name=” c l ean ” d e s c r i p t i o n=” Cleans bu i ld ”>116 <d e l e t e d i r=”${ bu i ld . d i r }” f a i l o n e r r o r=” f a l s e ”/>117 </ t a r g e t>
119 </ p r o j e c t>
Fisierul de proprietati build.properties este
1 #bui ld . p r o p e r t i e s2 #Standard p r o p e r t i e s f o r Ant bu i ld o f a Pluto 1 .1 p o r t l e t
4 #module name5 app . name=NumePortlet
7 #Direc tory that ho lds source code8 s r c . d i r = s r c /main9 java . s r c . d i r = ${ s r c . d i r }/ java
11 #Direc tory that ho lds documentation12 doc . d i r = docs
210 CAPITOLUL 8. PORTLET
14 #Direc tory that ho lds f i l e s to be b u i l t i n to a jar , war or ear15 bu i ld . d i r = bu i ld16 webbuild . d i r = ${ bu i ld . d i r }/webapp17 c l a s s b u i l d . d i r = ${webbuild . d i r }/WEB−INF/ c l a s s e s
19 #Direc tory that ho lds c o n f i g u r a t i o n f i l e s20 conf . d i r = ${ s r c . d i r }/ r e sou r c e
22 #Direc tory that ho lds l i b r a r i e s r equ i r ed to bu i ld and run the c l a s s e s23 l i b . d i r = l i b
25 #Direc tory that ho lds webapp f i l e s26 web . d i r = ${ s r c . d i r }/webapp
28 #WEB−INF d i r e c t o r y29 web−i n f . d i r = ${web . d i r }/WEB−INF
32 #Direc tory that ho lds f i l e s to bu i ld d i s t r i b u t i o n33 d i s t . d i r = ${ bu i ld . d i r }/ d i s t
Pentru utilizarea acestui build.xml este nevoie de structura urmatoare de cat-aloage
NumePortlet
|--> lib
| | castor-1.1.1.jar
| | commons-logging-1.0.4.jar
| | pluto-ant-tasks-2.0.*.jar
| | pluto-descriptor-api-1.1.6.jar
| | pluto-descriptor-impl-1.1.6.jar
| | pluto-util-2.0.*.jar
| | pluto-container-2.0.0.jar
| | jaxb-api-2.1.jar
| | jaxb-impl-2.1.9.jar
|--> src
| |--> main
| | |--> java
| | | |--> pachetul portletului
| | |--> resource
| | | | NumePortlet.xml
| | |--> webapp
| | | |--> jsp
| | | | | fisierele jsp ale portletului
| | | |--> WEB-INF
| | | | | portlet.xml
| | | | | web.xml
8.3. ELEMENTE DE PROGRAMARE 211
Fisierele castor.1.1.1.jar, pluto-descriptor-api-*.jar, pluto-descriptor-impl-*.jar, portlet-container-*.jar se copiaza din catalogul PLUTO HOME\shared\lib.
Fisierul web.xml de mai sus este
2 <?xml version=” 1 .0 ” encoding=”UTF−8”?>
4 <web−app xmlns=” ht tp : // java . sun . com/xml/ns/ j 2 e e ”5 xmlns :x s i=” h t t p : //www. w3 . org /2001/XMLSchema−i n s t ance ”6 xs i : s chemaLocat ion=” h t tp : // java . sun . com/xml/ns/ j 2 e e7 h t t p : // java . sun . com/xml/ns/ j 2 e e /web−app 2 4 . xsd”8 version=” 2 .4 ”>
10 </web−app>
Continutul final al acestui fisier rezulta ın urma obiectivului ant assemple, ıncare se preiau date din fisierul de configurare al portletului portlet.xml. Editareafisierului portlet.xml este sarcina programatorului.
Fisierul NumePortlet.xml este utilizat la desfasurarea aplicatie, fiind copiat ıncatalogul conf\Catalina\localhost al lui apache-tomcat sau Apache-pluto. Acestfisier are continutul:
1 <Context path=”NumePortlet” docBase=” . . \ PlutoDomain\NumePortlet . war”2 crossContext=” true ”/>
8.3 Elemente de programare
Orice portlet implementeaza interfata Portlet. Interfata Portlet declara 4metode
public interface Portlet{
public void init(PortletConfig config) throws PortletException;
public void processAction(ActionRequest request, ActionResponse
response) throws PortletException, java.io.IOException;
public void render(RenderRequest request, RenderResponse
response) throws PortletException, java.io.IOException;
public void destroy();
}
Metoda processAction prelucreaza cererea emisa de containerul de portlete. Lasolicitarea containerului, metoda render regenereaza continutul unui portlet.
Clasa GenericPortlet este implementarea initiala a interfetei Portlet. Ex-tinzand clasa GenericPortlet, sarcina programatorului este sa suprascrie metodele
212 CAPITOLUL 8. PORTLET
• doView pentru tratarea modului VIEW;
protected void doView(RenderRequest req,RenderResponse res)throws PortletException, IOException
• doEdit pentru tratarea modului EDIT;
protected void doEdit(RenderRequest req,RenderResponse res)throws PortletException, IOException
• doHelp pentru tratarea modului HELP;
protected void doHelp(RenderRequest req,RenderResponse res)throws PortletException, IOException
• init, destroy pentru initializarea, respectiv oprirea portletului.
void init() throws PortletException
void init(PortletConfig config) throws PortletException
void destroy()
si eventual, sa defineasca continutul metodei
public void processAction(ActionRequest request,ActionResponse response)throws PortletException, java.io.IOException;
Metoda processAction este apelata de metoda include(request, response) a claseiPortletRequestDispatcher.
Exemplul 8.3.1 Portletul HelloWorld.
1 package h e l l o ;2 import java . i o . ∗ ;3 import javax . p o r t l e t . ∗ ;
5 public class Hel loWor ldPort le t extends Gener i cPor t l e t {6 protected void doView ( RenderRequest request , RenderResponse re sponse )7 throws Port le tExcept ion , IOException{8 re sponse . setContentType ( ” text /html” ) ;9 re sponse . getWriter ( ) . p r i n t l n ( ” He l lo World ! ” ) ;
10 }
12 //Alta var ian ta de programare13 /∗14 pu b l i c vo id doView(RenderRequest req , RenderResponse res )15 throws Por t l e tExcep t ion , IOException {16 res . setContentType (” t e x t /html ” ) ;17 PrintWriter out=res . getWri ter ( ) ;18 out . p r i n t l n (”<h2>”);19 out . p r i n t l n (” He l lo World ! ” ) ;20 out . p r i n t l n (”</h2>”);21 }22 ∗/23 }
8.3. ELEMENTE DE PROGRAMARE 213
Fisierul portlet.xml este
1 <?xml version=” 1 .0 ” encoding=”UTF−8”?>2 <p o r t l e t−app xmlns=” ht tp : // java . sun . com/xml/ns/ p o r t l e t / p o r t l e t−app 2 0 . xsd”3 xmlns :x s i=” h t t p : //www. w3 . org /2001/XMLSchema−i n s t ance ”4 xs i : s chemaLocat ion=” h t tp : // java . sun . com/xml/ns/ p o r t l e t / p o r t l e t−app 2 0 . xsd5 h t t p : // java . sun . com/xml/ns/ p o r t l e t / p o r t l e t−app 2 0 . xsd”6 id=”myPortletApp” version=” 2 .0 ”>
8 <p o r t l e t>9 <d e s c r i p t i o n>Hel lo World as a p o r t l e t app</ d e s c r i p t i o n>
10 <p o r t l e t−name>Hel loWorld1Port let</ p o r t l e t−name>11 <di sp lay−name>Hel lo World P o r t l e t</ d i sp lay−name>12 <p o r t l e t−c l a s s>h e l l o . He l loWor ld1Port let</ p o r t l e t−c l a s s>13 <supports>14 <mime−type>t ex t /html</mime−type>15 <p o r t l e t−mode>VIEW</ p o r t l e t−mode>16 </ supports>17 <p o r t l e t−i n f o>18 < t i t l e>Hel lo World P o r t l e t</ t i t l e>19 </ p o r t l e t−i n f o>20 </ p o r t l e t>21 </ p o r t l e t−app>
Exemplul 8.3.2 Evidentierea modurilor VIEW, EDIT si HELP.
1 package h e l l o p l u t o ;2 import java . i o . ∗ ;3 import javax . p o r t l e t . ∗ ;
5 public class He l l oP lu toPor t l e t extends Gener i cPor t l e t {6 public void doView ( RenderRequest req , RenderResponse r e s )7 throws Port le tExcept ion , IOException {8 r e s . setContentType ( ” text /html” ) ;9 Writer out=r e s . getWriter ( ) ;
10 out . wr i t e ( ”<strong>Hel lo Pluto in view mode</strong>” ) ;11 }
13 public void doEdit ( RenderRequest req , RenderResponse r e s )14 throws Port le tExcept ion , IOException {15 r e s . setContentType ( ” text /html” ) ;16 Writer out=r e s . getWriter ( ) ;17 out . wr i t e ( ”<i>Hel lo Pluto in e d i t mode</i>” ) ;18 }
20 public void doHelp ( RenderRequest req , RenderResponse r e s )21 throws Port le tExcept ion , IOException {22 r e s . setContentType ( ” text /html” ) ;23 Writer out=r e s . getWriter ( ) ;24 out . wr i t e ( ”<u>Hel lo Pluto in he lp mode</u>” ) ;25 }26 }
Fisierul portlet.xml este
1 <?xml ve r s i o n=” 1 .0 ” encoding=”UTF−8”?>2 <p o r t l e t−app xmlns=” http :// java . sun . com/xml/ns/ p o r t l e t / p o r t l e t−app 2 0 . xsd”
214 CAPITOLUL 8. PORTLET
3 xmlns : x s i=” http ://www. w3 . org /2001/XMLSchema−i n s t ance ”4 x s i : schemaLocation=” http :// java . sun . com/xml/ns/ p o r t l e t / p o r t l e t−app 2 0 . xsd5 http :// java . sun . com/xml/ns/ p o r t l e t / p o r t l e t−app 2 0 . xsd”6 id=”myPortletApp” v e r s i o n=” 2 .0 ”>
8 <p o r t l e t >9 <d e s c r i p t i o n >Hel lo Pluto as a p o r t l e t app</d e s c r i p t i o n >
10 <p o r t l e t−name>Hel l oP lutoPor t l e t </p o r t l e t−name>11 <di sp lay−name>Hel lo Pluto</d i sp lay−name>12 <p o r t l e t−class>h e l l o p l u t o . He l l oP lutoPor t l e t </p o r t l e t−class>13 <supports>14 <mime−type>t ex t /html</mime−type>15 <p o r t l e t−mode>VIEW</p o r t l e t−mode>16 <p o r t l e t−mode>EDIT</p o r t l e t−mode>17 <p o r t l e t−mode>HELP</p o r t l e t−mode>18 </supports>19 <p o r t l e t−i n fo>20 <t i t l e >Hel lo Pluto Port l e t </ t i t l e >21 </p o r t l e t−i n fo>22 </p o r t l e t >23 </p o r t l e t−app>
Exemplul 8.3.3 Portletul Hello. Portletul afiseaza o zona text de introducere aunui nume si un buton. Odata introdus numele, la apasarea butonului se afisaezatextul Hello nume si un buton de reluare.
1 package hel loname ;
3 import java . i o . ∗ ;4 import javax . p o r t l e t . ∗ ;5 import java . u t i l . Enumeration ;
7 public class HelloNamePortlet extends Gener i cPor t l e t {
9 public void doView ( RenderRequest req , RenderResponse r e s )10 throws Port le tExcept ion , IOException {11 r e s . setContentType ( ” text /html” ) ;12 St r ing nume=( St r ing ) req . getParameter ( ”name” ) ;13 Port l e tReques tDi spatcher prd=null ;14 i f (nume==null ){15 prd=getPort l e tContext ( ) . getRequestDispatcher ( ”/ j sp / input . j sp ” ) ;16 prd . i n c lude ( req , r e s ) ;17 }18 else {19 // Varianta cu a f i s a r e pr in View20 /∗21 Writer out=res . getWri ter ( ) ;22 out . wr i t e (” He l lo ”+ nume ) ;23 PortletURL renderURL=res . createRenderURL ( ) ;24 renderURL . setPort le tMode ( PortletMode .VIEW) ;25 renderURL . setWindowState (WindowState .NORMAL) ;26 out . wr i t e (”<p><a hre f=\””+renderURL . t oS t r i n g ()+”\”> Reluare </a>”);27 ∗/28 // Varianta cu a f i s a r e pr in t r−un f i s i e r j s p29 prd=getPort l e tContext ( ) . getRequestDispatcher ( ”/ j sp / output . j sp ” ) ;30 prd . i n c lude ( req , r e s ) ;
8.3. ELEMENTE DE PROGRAMARE 215
31 }32 }
34 public void proces sAct ion ( ActionRequest req , ActionResponse r e s )35 throws IOException , Por t l e tExcept ion {36 // Preia parametr i i s i l e t r im i t e c e l u i care a emis cererea37 Enumeration params=req . getParameterNames ( ) ;38 while ( params . hasMoreElements ( ) ){39 St r ing parameterName = ( St r ing ) params . nextElement ( ) ;40 St r ing parameterValue=req . getParameter ( parameterName ) ;41 r e s . setRenderParameter ( parameterName , parameterValue ) ;42 }43 }44 }
Fisierele input.jsp si putput.jsp au codurile
1 <%@ t a g l i b u r i=” http :// java . sun . com/ p o r t l e t ” p r e f i x=” p o r t l e t ” %>2 <p o r t l e t : d e f i n eOb j e c t s />3 <div align=” cente r ”>4 Introduce ţ i numele :5 <br/>6 <form action=”<p o r t l e t : actionURL />”7 method=”POST”>8 <br>9 <input type=” text ” name=”name”/>
10 <br>11 <input type=”submit” name=”submitButton” value=”Apasa−ma” />12 </form>13 </div>
si respectiv
1 <%@ t a g l i b u r i=” ht t p : // java . sun . com/ p o r t l e t ” p r e f i x=” p o r t l e t ” %>2 <p o r t l e t : d e f i n e O b j e c t s />3 <p>4 <%5 St r ing r e s u l t=” He l lo ”+renderRequest . getParameter ( ”name”)+” ! ” ;6 out . p r i n t l n ( r e s u l t ) ;7 %>8 <p><a h r e f=”<port let : renderURL portletMode=”view” windowState=”normal” />”>9 Reluare
10 </a> .
Exemplul 8.3.4 Cel mai mare divizor comun a doua numere naturale ıntr-un port-let.
Varianta ın care calculul este programat ın portlet.
1 package cmmdc ;
3 import java . i o . ∗ ;4 import javax . p o r t l e t . ∗ ;5 import java . u t i l . Enumeration ;
7 public class CmmdcPortlet extends Gener i cPor t l e t {
9 public void doView ( RenderRequest req , RenderResponse r e s )
216 CAPITOLUL 8. PORTLET
10 throws Port le tExcept ion , IOException {11 r e s . setContentType ( ” text /html” ) ;12 Port l e tReques tDi spatcher prd=null ;13 St r ing rez=req . getParameter ( ” r ez ” ) ;14 i f ( r e z==null ){15 prd=getPort l e tContext ( ) . getRequestDispatcher ( ”/ j sp / input . j sp ” ) ;16 prd . i n c lude ( req , r e s ) ;17 }18 else {19 prd=getPort l e tContext ( ) . getRequestDispatcher ( ”/ j sp / output . j sp ” ) ;20 prd . i n c lude ( req , r e s ) ;21 }22 }
24 public void proces sAct ion ( ActionRequest req , ActionResponse r e s )25 throws IOException , Por t l e tExcept ion {26 // Preia parametr i i s i l e t r im i t e c e l u i care a emis cererea27 St r ing sm=req . getParameter ( ”m” ) ;28 St r ing sn=req . getParameter ( ”n” ) ;29 long m=Long . parseLong (sm ) ;30 long n=Long . parseLong ( sn ) ;31 long c=cmmdc(m, n ) ;32 r e s . setRenderParameter ( ” r ez ” , (new Long ( c ) ) . t oS t r i ng ( ) ) ;33 }
35 private long cmmdc( long m, long n ) { . . .}
37 }
Fisierele inputCmmdc.jsp si outputCmmdc.jsp au codurile
1 <%@ t a g l i b u r i=” http :// java . sun . com/ p o r t l e t ” p r e f i x=” p o r t l e t ” %>2 <p o r t l e t : d e f i n eOb j e c t s />3 <div align=” cente r ”>4 <form action=”<p o r t l e t : actionURL />”5 method=”POST”>6 <table border=”1” >7 <tr>8 <td> Primul numă r </td>9 <td> <input type=” text ” name=”m”/> </td>
10 </ tr>11 <tr>12 <td> Al d o i l e a numă r </td>13 <td> <input type=” text ” name=”n”/> </td>14 </ tr>15 <tr>16 <td>17 <input type=”submit” name=”submitButton” value=” Calcu leaza ” />18 </td>19 </ tr>20 </table>21 </form>
23 </div>
si respectiv
1 <%@ t a g l i b u r i=” http :// java . sun . com/ p o r t l e t ” p r e f i x=” p o r t l e t ” %>2 <p o r t l e t : d e f i n eOb j e c t s />
8.3. ELEMENTE DE PROGRAMARE 217
4 <P>5 <%6 String r e s u l t=”Cmmdc ”+renderRequest . getParameter ( ” r ez ”)+” ! ” ;7 out . p r i n t l n ( r e s u l t ) ;8 %>
10 <P>11 <a href=”<p o r t l e t : renderURL portletMode=”view” windowState=”normal” />”>12 Reluare13 </a>
Varianta ın care calculul este programat ıntr-o componenta Java (bean)si care este apelat ın pagina jsp de afisare a rezultatului.
1 package cmmdc ;
3 import java . i o . ∗ ;4 import javax . p o r t l e t . ∗ ;5 import java . u t i l . Enumeration ;
7 public class CmmdcPortlet extends Gener i cPor t l e t {
9 public void doView ( RenderRequest req , RenderResponse r e s )10 throws Port le tExcept ion , IOException {11 r e s . setContentType ( ” text /html” ) ;12 Port l e tReques tDi spatcher prd=null ;13 St r ing sb=req . getParameter ( ” submitButton” ) ;14 i f ( sb==null ){15 prd=getPort l e tContext ( ) . getRequestDispatcher ( ”/ j sp /inputCmmdc . j sp ” ) ;16 prd . i n c lude ( req , r e s ) ;17 }18 else {19 prd=getPort l e tContext ( ) . getRequestDispatcher ( ”/ j sp /outputCmmdc . j sp ” ) ;20 prd . i n c lude ( req , r e s ) ;21 }22 }
24 public void proces sAct ion ( ActionRequest req , ActionResponse r e s )25 throws IOException , Por t l e tExcept ion {26 // Preia parametr i i s i l e t r im i t e c e l u i care a emis cererea27 Enumeration params=req . getParameterNames ( ) ;28 while ( params . hasMoreElements ( ) ) {29 St r ing parameterName = ( St r ing ) params . nextElement ( ) ;30 St r ing parameterValue=req . getParameter ( parameterName ) ;31 System . out . p r i n t l n ( ” >> parameterName = ” + parameterName +32 ” <=> parameterValue = ” + parameterValue ) ;33 r e s . setRenderParameter ( parameterName , parameterValue ) ;34 }35 }36 }
Codul componentei Java
1 public class CmmdcBean{
3 private St r ing m=”” ;4 private St r ing n=”” ;
6 public void setM ( St r ing m){
218 CAPITOLUL 8. PORTLET
7 this .m=m;8 }9 public void setN ( St r ing n){
10 this . n=n ;11 }12 public St r ing getM (){13 return m;14 }15 public St r ing getN (){16 return n ;17 }18 public St r ing cmmdc( ){19 long m0=Long . parseLong (m) ;20 long n0=Long . parseLong (n ) ;21 long c , r ;22 do{23 c=n0 ;24 r=m0%n0 ;25 m0=n0 ;26 n0=r ;27 }28 while ( r !=0) ;29 return (new Long ( c ) ) . t oS t r i ng ( ) ;30 }31 }
Pagina outputCmmdc.jsp
1 <%@ t a g l i b u r i=” http :// java . sun . com/ p o r t l e t ” p r e f i x=” p o r t l e t ” %>2 <j sp : useBean id=”myCmmdcBean” class=”cmmdc . CmmdcBean” scope=” s e s s i o n ”/>3 <j sp : s e tProper ty name=”myCmmdcBean” property=”∗”/>
5 <p o r t l e t : d e f i n eOb j e c t s />
7 <P>8 <%9 String r e s u l t=”Cmmdc ”+myCmmdcBean . cmmdc ( ) ;
10 out . p r i n t l n ( r e s u l t ) ;11 %>12 <P>13 <a href=”<p o r t l e t : renderURL portletMode=”view” windowState=”normal” />”>14 Reluare15 </a>
Varianta ın care care calculul este programat ıntr-un servlet. Servletulutilizat este cel prezentat ın capitolul Servlet, (6.3.2), dar inclus ın pachetul portlet-ului. Fisierul inputCmmdc.jsp are ın plus linia
<input type="hidden" name="tip" value="text/html"/>
iar ın codul clasei CmmdcPortlet, ın locul liniei
prd=getPortletContext().getRequestDispatcher("/jsp/outputCmmdc.jsp");
apare
prd=getPortletContext().getRequestDispatcher("/cmmdc");
8.3. ELEMENTE DE PROGRAMARE 219
adica ın locul invocarii paginii JSP, dispecerul apeleaza servletul. In servlet esteesentiala furnizarea rezultatului ın format html. Pagina html generata se ıncarca ınfereastra portlet-ului.
Fisierul web.xml, ınaintea completarii prin ant, este
1 <?xml version=” 1 .0 ” encoding=”UTF−8”?>
3 <web−app xmlns=” ht tp : // java . sun . com/xml/ns/ j 2 e e ”4 xmlns :x s i=” h t t p : //www. w3 . org /2001/XMLSchema−i n s t ance ”5 xs i : s chemaLocat ion=” h t tp : // java . sun . com/xml/ns/ j 2 e e6 h t t p : // java . sun . com/xml/ns/ j 2 e e /web−app 2 4 . xsd”7 version=” 2 .4 ”>
9 <s e r v l e t>10 <s e r v l e t−name>CmmdcServlet</ s e r v l e t−name>11 <s e r v l e t−c l a s s>cmmdc . CmmdcServlet</ s e r v l e t−c l a s s>12 </ s e r v l e t>
14 <s e r v l e t−mapping>15 <s e r v l e t−name>CmmdcServlet</ s e r v l e t−name>16 <ur l−pattern>/cmmdc</ ur l−pattern>17 </ s e r v l e t−mapping>18 </web−app>
Interfata PortletPreferences
Atribute, adica perechi de tip String (nume,valoare) definite ın fisierul portlet.xmlprin
<portlet-preferences>
<preference>
<name>nume_atribut</name>
<value>valoare_atribut</value>
<read-only>true|false</read-only>
</preference>
. . .
</portlet-preferences>
Atributele se transmit metodelor doView, doEdit si doHelp. Suportul esteoferit prin interfata PortletPreferences.
Metode
• String getValue(String key, String def )
Returneaza valoarea primului atribut avand numele key. In lipsa atributuluisau a valorii returneaza valoarea def.
• String[] getValues(String key, String[] def )
Returneaza toate valorile atributului key.
220 CAPITOLUL 8. PORTLET
• Enumeration<String> getNames()
Suport pentru acces la numele atributelor care au valoare.
• Map<String,String[]> getMap()
Suport pentru acces la atribute.
Un obiect care implementeaza interfata PortletPreferences se obtine prinmetoda getPreferences() a clasei RenderRequest.
Exemplul 8.3.5 Portlet ın care se preiau si se afiseaza valori ale atributelor.
Codul portletului este
1 package p r e f ;
3 import java . i o . ∗ ;4 import javax . p o r t l e t . ∗ ;
6 public class P r e f P o r t l e t extends Gener i cPor t l e t {
8 public void doView ( RenderRequest req , RenderResponse r e s )9 throws Port le tExcept ion , IOException {
10 P o r t l e t P r e f e r e n c e s p r e f s = req . g e t P r e f e r e n c e s ( ) ;11 St r ing a t t r 1 = p r e f s . getValue ( ”ATTR1” , ” a t t r 1 ” ) ;12 St r ing a t t r 2 = p r e f s . getValue ( ”ATTR2” , ” a t t r 2 ” ) ;13 r e s . setContentType ( ” text /html” ) ;14 Writer out=r e s . getWriter ( ) ;15 out . wr i t e ( ”<strong>”+at t r 1+” <−−> ”+at t r 2+”</strong>” ) ;16 }17 }
iar atributele din fisierul portlet.xml sunt
<portlet-preferences>
<preference>
<name>ATTR1</name>
<value>Programare distribuita</value>
<read-only>true</read-only>
</preference>
<preference>
<name>ATTR2</name>
<!--
<value>Analiza numerica</value>
-->
<read-only>true</read-only>
</preference>
</portlet-preferences>
Al doilea atribut nu are valoare.Portletul afiseaza textul Programare distribuita <–>attr2.
8.4. PRODUSE PORTAL 221
8.4 Produse Portal
Termenul portal va desemna
• aplicatia informatica prin care o institutie comunica cu lumea exterioara
• produsul informatic care realizeaza aplicatia amintita la pct. anterior
In cele ce urmeaza ne vom referi doar la produse portal care sunt containere deportlete.
Dezvoltarea unui portal al unei organizatii se face pe produse specializate acestuiscop. Dintre asemenea produsele gratuite amintim:
• uPortal;
• jetspeed-2;
care vor fi prezentate ın continuare. apache-pluto este ideal pentru testarea portlet-elor.
8.4.1 uPortal
uPortal este un portal cadru, dezvoltat de JA-SIG (Java Architecture SpecialInterest Group) si a fost utilizat de mai multe universitati ca suport ın constructiaportalului specific.
Instalarea produsului. Distributia produsului se face ın doua variante
• uPortal-*.*.* - uPortal-only ;
• uPortal-*.*.*-quick-start care ınglobeaza toate resursele necesare functionarii(apache-ant, apache-tomcat, apache-maven, HypersonicSQLDB).
In cele ce urmeaza utilizam varianta uPortal-quick-start. Instalarea produsuluirevine la dezarhivarea fisierului descarcat.
Lansarea portalului. In urma dezarhivarii, ın catalogul uPortal HOME segaseste un fisier build.xml, ale carei obiective asigura lansarea portalului1.
Se completeaza fisierul ant.bat cu referinta set JAVA HOME=...
Lansarea portalului consta ın executarea comenzii
ant start
De fapt se porneste SGBD HypersonicSQLDB si serverul Web apache-tomcat.Oprirea portalului se face prin executarea comenzii
1La prima executare a unei operatii asupra portalului, calculatorul trebuie sa fie conectat lainternet, deoarece mai multe resurse sunt descarcate prin apache-maven. Aceste resurse se depunın c:\Documents and Settings\adminName\.m2\repository.
222 CAPITOLUL 8. PORTLET
ant stop
Dintr-un navigator, portalul se acceseaza prin
http://host:8080/uPortal
Accesarea portalului se poate face doar de detinatorii unui cont (UserName,Password). Administratorul (UserName=Password=admin) poate crea conturi noi.
Instalarea unui portlet consta ın desfasurarea si publicarea lui.Compilarea si arhivarea portletului se poate face cu apache-ant In acest scop se
creaza structura
|--> lib
| | portlet-api-1.0.jar
|--> pachetul portlet-ului
| |--> jsp
| | | *.jsp
| |--> WEB-INF
| | |--> classes
| | | | *.java
| | | web.xml
| | | portlet.xml
| build.xml
cu fisierele *.java, *.jsp si portlet.xml corespunzatoare portletului iar web.xml estegeneric
1 <?xml version=” 1 .0 ” encoding=”ISO−8859−1”?>2 < !DOCTYPE web−app PUBLIC3 ”−//Sun Microsystems , Inc . //DTD Web Appl i ca t ion 2 .3//EN”4 ” h t tp : // java . sun . com/dtd/web−app 2 3 . dtd”>5 <web−app>6 </web−app>
Fisierul build.xml, compilare si arhivare este
1 <p r o j e c t name=” p o r t l e t−bu i ld ” default=”war” based i r=” . ”>
3 <property name=” package ” value=” h e l l o ” />4 <property name=” p o r t l e t . name” value=” HelloNamePortlet ” />5 <property name=” bu i ld . d i r ” va lue=” bu i ld ” />
7 <path id=” p r o j e c t . c l a s s p a t h ”>8 < f i l e s e t d i r=” l i b ”>9 <i n c l ude name=” ∗ . j a r ”/>
10 </ f i l e s e t>11 </path>
13 <t a r g e t name=” i n i t ” >14 <d e l e t e d i r=”${package }/${ bu i ld . d i r }” />15 <mkdir d i r=”${package }/${ bu i ld . d i r }” />16 <mkdir d i r=”${package }/${ bu i ld . d i r }/ j sp ” />17 <mkdir d i r=”${package }/${ bu i ld . d i r }/WEB−INF” />18 <mkdir d i r=”${package }/${ bu i ld . d i r }/WEB−INF/ c l a s s e s ” />19 </ t a r g e t>
21 <t a r g e t name=” compile ” depends=” i n i t ” d e s c r i p t i o n=”Compiles source ”>
8.4. PRODUSE PORTAL 223
22 <javac c l a s s p a t h r e f=” p r o j e c t . c l a s s p a t h ”23 d e s t d i r=”${package }/${ bu i ld . d i r }/WEB−INF/ c l a s s e s ”24 s r c d i r=”${package }/WEB−INF/ c l a s s e s ”/>25 </ t a r g e t>
27 <t a r g e t name=”war” depends=” compile ”>28 <copy t o d i r=”${package }/${ bu i ld . d i r }/WEB−INF/”29 f i l e=”${package }/WEB−INF/ p o r t l e t . xml” />30 <copy t o d i r=”${package }/${ bu i ld . d i r }/ j sp ”>31 < f i l e s e t d i r=”${package }/ j sp ”>32 <i n c l ude name=” ∗ . j s p ”/>33 </ f i l e s e t>34 </copy>
36 <war based i r=”${package }/${ bu i ld . d i r }” update=” f a l s e ”37 w a r f i l e=”${ p o r t l e t . name } . war”38 webxml=”${package }/WEB−INF/web . xml”/>39 </ t a r g e t>
41 <t a r g e t name=” bu i ld ” depends=” clean , war”/>
43 <t a r g e t name=” c l ean ” d e s c r i p t i o n=” Cleans bu i ld ”>44 <d e l e t e d i r=”${ bu i ld . d i r }” f a i l o n e r r o r=” f a l s e ”/>45 </ t a r g e t>
47 </ p r o j e c t>
Desfasurarea portlet-ului se face cu apache-ant utilizand fisierul build.xml dinuPortal HOME\uPortal-*.*.* prin
ant deployPortletApp -DportletApp=arhiva portlet-ului.war
In urma acestei operatii, portlet-ul se dezarhiveaza ın uPortal HOME\apache-tomcat-*.*.*\webapps iar fisierul web.xml este actualizat.
Publicarea portlet-ului se face cu rolul de administrator. Dupa conectare lauPortal
1. AdminTools → Portlet Manager → Publish a new channel
2. Se parcurg meniurile Channel Manager
(a) Din meniul Channel Type se selecteaza optiunea Portlet. Clic Next.
(b) In meniul General Settings se fixeaza toti parametrii indicati. Clic Next.
(c) In meniul Portlet Descriptor se fixeaza
• Contextul portlet-ului, adica catalogul din webapps care contine portlet-ul. In mod obligatoriu primul caracter este / (slash) Pentru fixareaacestui parametru se va consulta fisierul web.xml.
• Numele portlet-ului asa cum este definit ın fisierul portlet.xml.
Clic Next.
(d) In meniul Portlet Preferences, clic Next.
224 CAPITOLUL 8. PORTLET
(e) In meniul Display Settings, clic Next.
(f) In meniul Channel Controls, clic Next.
(g) In meniul Categories se fixeaza categoria canalului si cel putin un mem-bru.
Select Marked → Next.
(h) In meniul Groups se fixeaza grupul si cel putin un membru.
Select Marked → Next
Grupul desemneaza clientii care pot publica portlet-ul.
(i) In meniul Review, clic Finish.
Canalul portlet-ului apare ın lista afisata.
3. Fiecare client care poate utiliza portlet-ul - adica cei din grupul selectat, ılpublica prin componenta Add Content.
Pentru administrator: AdminTools → Customize urmat de
(a) Clic pe un buton Add Channel corespunzator locului unde vrem sa fiepozitionat portlet-ul.
(b) In User Preferences,
i. se alege categoria portlet-ului, clic go;
ii. se alege numele portlet-ului, clic Add Channel.
(c) Clic pe numele canalului corespunzator portlet-ului. Canalul este afisatın meniul Welcome.
(d) Clic pe numele canalului din meniul Welcome lanseaza portlet-ul.
Un client elimina un portlet prin clic pe butonul Remove din fereastra portlet-ului.
Administratorul portalului sterge un portlet prin clic pe butonul de ınchidereın lista portlet-elor publicate din AdminTools → Portlet Manager → Modify a
currently published channel.
Asemanator, se pot publica ın uPortal aplicatii Web. Deosebirea esentiala esteca tipul canalului (Channel Type) este WebProxy sau Inline Frame.
8.4.2 Jetspeed-2
Jetspeed-2 este un portal cadru dezvoltat de apache.
Instalarea se executa ruland distributia jetspeed-2.*.*-installer.jar.
Versiunea instalata a platformei jetspeed este construita peste o distributieapache-tomcat-*. Astfel, lansarea se face apeland bin\startup.bat.
Portalul se acceseaza, dintr-un navigator, prin
8.4. PRODUSE PORTAL 225
http://localhost:8080/jetspeed
Desfasurarea unui portlet consta ın copierea arhivei war corespunzatoare, re-alizat ın 8.4.1, ın catalogul
Jetspeed HOME\webapps\jetspeed\WEB-INF\deploy
Pe rol de admin (acces cu valorile initiale username=password=admin), publi-carea portlet-ului presupune
1. Clic pe icon-ul butonului Edit - aflat sub butonul logout.
2. Clic pe butonul Add Portlet, aflat sub butonul Edit.
3. Clic pe butonul Add al portlet-ului care se doreste publicat.
4. Clic pe sageata de reıntoarcere, urmat de clic pe iconul butonului View - aflatpe pozitia butonului Edit.
Pentru a sterge un portlet, dupa primul pas anterior, se apasa butonul deınchidere din zona portlet-ului.
226 CAPITOLUL 8. PORTLET
Capitolul 9
Java Web Start
9.1 Java Web Start
O aplicatie Java destinata a fi utilizata pe un calculator poate fi valorificatasi ıntr-o retea, pe baza protocolului Java Network Launching Protocol - JNLP.Tehnologia poarta numele de Java Web Start.
Aplicatia Java trebuie sa satisfaca o serie de restrictii:
• Aplicatia trebuie arhivata cu jar;
• Eventualele date necesare aplicatiei se introduc prin intermediul unei interfetegrafice (swing, SWT, apache-pivot);
• Acces limitat la proprietatile si resursele sistemului client.
Aplicatiei i se ataseaza un fisier xml, dar cu extensia jnlp, care se va apeladintr-un navigator. Pentru acest fisier folosim terminologia de fisier jnlp.
Fisierul jnlp fixeaza:
• referinta URL a aplicatie (prin atributul codebase);
• arhivele jar utilizate (prin atributul href);
• clasa cu metoda main (prin atributul main-class).
Ansamblul de resurse formeaza o aplicatie Web care poate fi desfasurata ıntr-un server Web (Microsoft Internet Information Service (IIS), apache) sau poate fiincorporat ıntr-un servlet, caz ın care desfasurarea va fi ıntr-un server Web containerde servlet.
Aratam activitatile care trebuie ıntreprinse ın cazul unui exemplu simplu dat declasa VisualCmmdc.java.
227
228 CAPITOLUL 9. JAVA WEB START
1 public class VisualCmmdc extends javax . swing . JFrame {2 public VisualCmmdc ( ){3 initComponents ( ) ;4 }
6 private long cmmdc( long m, long n ) { . . .}
8 private void initComponents ( ) {9 // cod generat de Netbeans
10 }
12 private void cmmdcButtonMouseClicked ( java . awt . event . MouseEvent evt ){13 try{14 St r ing sm=mTextField . getText ( ) ;15 St r ing sn=nTextField . getText ( ) ;16 long m=Long . parseLong (sm ) ;17 long n=Long . parseLong ( sn ) ;18 long c=cmmdc(m, n ) ;19 St r ing s=(new Long ( c ) ) . t oS t r i ng ( ) ;20 cmmdcTextField . setText ( s ) ;21 }22 catch ( Exception e ){23 System . e r r . p r i n t l n ( ” Exception : ”+e . getMessage ( ) ) ;24 }25 }
27 private void exitForm ( java . awt . event . WindowEvent evt ){28 System . e x i t ( 0 ) ;29 }
31 public stat ic void main ( St r ing args [ ] ) {32 new VisualCmmdc ( ) . s e t V i s i b l e ( true ) ;33 }
35 private javax . swing . JButton cmmdcButton ;36 private javax . swing . JLabel mLabel ;37 private javax . swing . JLabel nLabel ;38 private javax . swing . JTextFie ld mTextField ;39 private javax . swing . JTextFie ld nTextField ;40 private javax . swing . JTextFie ld cmmdcTextField ;41 }
Interfata grafica a programului este ilustrata ın Fig. 9.1
Figure 9.1: Interfata grafica pentru rezolvarea ecuatiei algebrice.
9.1. JAVA WEB START 229
Instalare ıntr-un server Web
Pentru instalarea aplicatiei ıntr-un server Web, se parcurg pasii:
1. Se arhiveaza aplicatia
jar cfv cmmdc.jar *.class
2. Se editeaza fisierul launch.jnlp
1 <?xml version=” 1 .0 ” encoding=”UTF−8”?>2 <j n l p codebase=” h t t p : // host /cmmdc”>3 <i n fo rmat ion>4 < t i t l e> . . . </ t i t l e>5 <vendor> . . . </ vendor>6 <d e s c r i p t i o n> . . . </ d e s c r i p t i o n>7 </ in fo rmat ion>8 <r e s o u r c e s>9 < j 2 s e version=”1.2+”/>
10 < j a r h r e f=”cmmdc . j a r ”/>11 </ r e s o u r c e s>12 <app l i c a t i on−desc main−c l a s s=”VisualCmmdc”/>13 </ j n l p>
host se ınlocuieste cu numele calculatorului care gazduieste serverul Web.
3. Se creaza fisier de apelare a aplicatiei (cmmdc.html)
1 <html>2 <body bgcolor=”#AAEEAA”>3 <center>4 <h3>Visua l Cmmdc Appl i ca t ion </h3>5 <a href=” http :// host /cmmdc/ launch . j n l p ”>6 Launch the a p p l i c a t i o n </a>7 </center>8 </body>9 </html>
4. Ansamblul
cmmdc
| cmmdc.jar
| cmmdc.html
| launch.jnlp
se copiaza ın serverul Web (ın cazul IIS acest loc este catalogulInetPub\wwwroot).
Dintr-un navigator, apelarea aplicatiei este http://host/cmmdc/cmmdc.html.
230 CAPITOLUL 9. JAVA WEB START
Aplicatia Java ca servlet
Pentru includerea aplicatie Java ıntr-un servlet, primii trei pasi prezentati maisus coincid. Singura diferenta consta ın continutul referintelor, dupa host va apareportul utilizat de serverul Web container de servlet, uzual host:8080.
4. Intr-un catalog de lucru se creaza structura de cataloage si fisiere:
app
|--- cmmdc.jar
|--- launch.jnlp
WEB-INF
|--- lib
| |--- jnlp-servlet.jar
|--- web.xml
cmmdc.html
Fisierul jnlp-servlet.jar se preia din distributia JDK, din catalogul sam-ple/jnlp/servlet.
Fisierul web.xml este
1 ?xml v e r s i on=” 1 .0 ” encoding=” i so −8859−1”?>2 < !DOCTYPE web−app3 PUBLIC ”−//Sun Microsystems , Inc . //DTD Web Appl i ca t ion 2 .3//EN”4 ” h t tp : // java . sun . com/dtd/web−app 2 3 . dtd”>5 <web−app>6 < !−− Standard Action S e r v l e t Conf igurat ion ( with debugging ) −−>7 <web−app>8 <s e r v l e t>9 <s e r v l e t−name>JnlpDownloadServlet</ s e r v l e t−name>
10 <s e r v l e t−c l a s s>11 j n l p . sample . s e r v l e t . JnlpDownloadServlet12 </ s e r v l e t−c l a s s>13 </ s e r v l e t>14 <s e r v l e t−mapping>15 <s e r v l e t−name>JnlpDownloadServlet</ s e r v l e t−name>16 <ur l−pattern>∗ . j n l p</ ur l−pattern>17 </ s e r v l e t−mapping>18 </web−app>19 </web−app>
5. Continutul catalogului de lucru se arhiveaza ıntr-un fisier war.
jar cfv cmmdc.war app/* WEB-INF/* cmmdc.html
6. Utilizand apache-tomcat sau jetty, de exemplu, fisierul war se copiaza ın cat-alogul webapps al serverului web.
Dintr-un navigator, apelarea aplicatiei se obtine prinhttp://host:8080/cmmdc/cmmdc.html.
9.1. JAVA WEB START 231
Daca aplicatia Java utilizeaza imagini grafice acestea trebuie arhivate ımpreunacu aplicatia, de exemplu ıntr-un catalog images.
Incarcarea si afisarea unei imagini programandu-se prin
ClassLoader cl=this.getClass().getClassLoader();
URL file=cl.getResource("images/pic1.jpg");
Image img=Toolkit.getDefaultToolkit().getImage(file);
graphics.drawImage(img,x,y,this);
Daca aplicatia Java utilizeaza resurse externe date prin fisiere jar atunci:
1. Toate fisierele jar se certifica.
Certificarea resurselor se realizeaza ruland succesiv
(a) keytool -genkey -keystore myKeystore -alias myself
(b) keytool -selfcert -alias myself -keystore myKeystore
(c) jarsigner -keystore myKeystore resource.jar myself
keytool.exe si jarsigner.exe se gasesc ın distributia jdk.
Primele doua actiuni au ca rezultat obtinerea certificatului myKeystore iarultima actiune reprezinta ınglobarea certificarii ın arhiva resource.jar.
Toate fisierele jar trebuie sa poarte aceasi certificare.
2. Fisierele jar certificate se depun ın catalogul app\lib.
3. In fisierul jnlp, ın elementul resources, pentru fiecare fisier jar utilizat seintroduce declaratia
<jar href=”lib/resource.jar”/>
4. In plus, fisierul jnlp atasat aplicatiei contine elementele
<security>
<all-permissions />
</security>
Daca arhiva jar a aplicatiei Java este executabila atunci, ın fisierul jnlp, elemen-tul application-desc poate lipsi.
Intr-o arhiva jar executabila, fisierul MANIFEST.MF indica clasa cu metoda mainsi eventualele resurse externe utilizate (fisiere jar) prin proprietatile
Main-class: numeClasa
Class-path: lib/resursa1.jar lib/resursa2.jar . . .
Pentru a obtine fisierul MANIFEST.MF cu aceste proprietati se editeaza un fisier textcu continutul de mai sus, denumit de exemplu myManifest.mf, si se arhiveaza prin
jar cfvm numeArhiva.jar myManifest.mf *.class lib
232 CAPITOLUL 9. JAVA WEB START
Capitolul 10
Java Management Extensions
Java Management Extensions (JMX) face posibila ca un obiect Java sa permitagestionarea metodelor si a anumitor campuri de catre alte obiecte. Obiectele Javacare ısi expun astfel resursele se numesc MBean - uri si formeaza temelia cadruluide lucru JMX.
Exista mai multe tipuri de MBean-uri:
• Standard MBean;
• Dynamic MBean;
• Open MBean;
• Model MBean;
• MXBean;
Un obiect care gestioneaza resursele unui MBean se numeste agent sau server MBean.Agentul dispune de mijloace care interactioneaza cu un MBean, permitandu-i:
• accesul la valorile unui camp si la modificarea lor;
• invocarea metodelor.
In general, un agent poate fi definit ca
• autorul unei actiuni;
• factor care provoaca actiuni;
• reprezentant al unei institutii ınsarcinat cu ındeplinirea unor actiuni.
Terminologia server MBean se justifica prin faptul ca poate fi invocat de unprogram client. In aceasta ipostaza, serverul MBean are rolul unui container deMBean-uri si de gestionare si executie a apelurilor clientilor.
Structura unei aplicatii JMX contine doua nivele:
233
234 CAPITOLUL 10. JAVA MANAGEMENT EXTENSIONS
• componentele MBean;
• agentul (serverul MBean).
10.1 Standard MBean
10.1.1 Crearea unui Standard MBean
O componenta MBean este alcatuita dintr-o interfata si o clasa care imple-menteaza interfata satisfacand urmatoarele restrictii:
1. interfata are numele clasei care o implementeaza avand ın plus sufixul MBean;
2. Interfata si clasa care o implementeaza apartin aceluiasi pachet;
3. constructorii si metodele expuse trebuie sa fie publice.
In continuare campurile si metodele destinate expunerii se vor denumi atribute,respectiv operatii. Fiecarui atribut xxx i se ataseaza cel putin una din metodele
public void setXxx(tip xxx){
this.xxx=xxx;
}
si / sau
public tip getXxx(){
return xxx;
}
Un atribut se precizeaza doar prin aceste metode, fara definirea / declararea campuluicorespunzator. Campul se defineste ın clasa ce implementeaza interfata MBean-ului.
Astfel, un MBean este caracterizat de
• atribute
care pot fi consultate (citite), modificate (scrise) sau cu ambele optiuni.
• operatii
• notificari
cu evidenta modificarilor suferite de atribute.
Exemplul 10.1.1
Construim un MBean cu
10.1. STANDARD MBEAN 235
• atributele
– label
ce poate fi numai citit;
– cursEuro
care poate fi consultat si modificat;
• operatiile
– public String sayHello()
afiseaza un mesaj;
– public long cmmdc(long m, long n);
de calcul a celui mai mare divizor comun a doua numere naturale.
Interfata IntroMBean este
1 package bas i c ;
3 public interface IntroMBean {4 // Opera t i i5 public St r ing sayHe l lo ( ) ;6 public long cmmdc( long m, long n ) ;
8 // Atr i bu te9 // read−only
10 public St r ing getLabe l ( ) ;11 // read−wr i t e12 public double getCursEuro ( ) ;13 public void setCursEuro (double cursEuro ) ;14 }
fiind implementat de clasa Intro
1 package bas i c ;2 import javax . management . ∗ ;
4 public class In t ro implements IntroMBean {
6 //Atr i bu te7 private f ina l St r ing label = ”Fac . Matematica s i In fo rmat i ca ” ;8 private double cursEuro = 3 . 5 0 ;
10 public St r ing getLabe l ( ) {11 return label ;12 }
14 public double getCursEuro ( ) {15 return cursEuro ;16 }
18 public synchronized void setCursEuro (double cursEuro ) {19 this . cursEuro = cursEuro ;20 }
236 CAPITOLUL 10. JAVA MANAGEMENT EXTENSIONS
22 //Opera t i i23 public St r ing sayHe l lo ( ) {24 St r ing message=” He l lo World ! ” ;25 System . out . p r i n t l n ( message ) ;26 return message ;27 }
29 public long cmmdc( long m, long n ) { . . .}30 }
In acest caz nu s-a implementat posibilitatea notificarilor atributului cursEuro.
10.1.2 Crearea unui MBeanServer
Un agent sau MBean server implementeaza interfata MBeanServer. Un aseme-nea obiect se obtine printr-una din metodele statice
• static MBeanServer ManagementFactory.getPlatformMBeanServer()
Utilitarul jconsole permite conectarea la serverul MBean.
• static MBeanServer MBeanServerFactory.createMBeanServer()
In agent se ınregistreaza componente MBean. Un obiect MBean este caracterizatde un nume, un obiect de tip ObjectName. Inregistrarea si / sau crearea uneicomponente MBean necesita definirea ın prealabil a acestui nume. Structura uneinume este
domeniu : numeAtribut=valAtribut ,numeAtribut=valAtribut . . .
unde
• domeniu
este un nume simbolic (String). Daca domeniul este stringul vid atunci seconsidera valoarea implicita DefaultDomain.
• atribute uzuale:
– type=numele MBean-ului
– index=numar de identificare a MBean-ului
Cel putin un atribut este obligatoriu.
Clasa ObjectName
Constructori
• ObjectName(String nume)
Parametrul nume are structura descrisa mai sus.
10.1. STANDARD MBEAN 237
• ObjectName(String domeniu, Hashtable<String,String> tabel)
• ObjectName(String domeniu, String numeAtribut, String
valAtribut)
Metode
• static ObjectName getInstance(String nume)
Inregistrarea si utilizarea MBean-ului face apel la metodele interfetei MBeanServer.
ObjectInstance
Un obiect de tip ObjectInstance este folosit pentru reprezentarea ansamblu-lui alcatuit de un obiect ObjectName asociat unui MBean si numele clasei core-spunzatoare.
Interfata MBeanServer
Metode
• ObjectInstance registerMBean(Object obj, ObjectName nume)
Inregistreaza pe platforma, instanta obj a unui MBean avand numele nume.
• void unregister(ObjectName nume)
• ObjectInstance createMBean(String numeClasa, ObjectName nume)
Creaza si ınregistreaza un MBean de clasa numeClasa si de nume nume.
• ObjectInstance createMBean(String numeClasa, ObjectName nume, Object[]
param, String[] sign)
In plus, sirul param contine parametri constructorului, de tip, respectiv sign.
• String getDefaultDomain()
• Object invoke(ObjectName mbeanName, String operationName, Object[]
param, String[] paramTip)
Se invoca operatia operationName a MBean-ului mbeanName. Parametri nece-sari operatiei ımpreuna cu tipurile corespunzatoare sunt dati ın variabileleparam si respectiv paramTip.
• Object getAttribute(ObjectName mbeanName,String atribut)
Returneaza valoarea atributului atribut a mbean-ului mbeanName.
238 CAPITOLUL 10. JAVA MANAGEMENT EXTENSIONS
• void setAttribute(ObjectName mbeanName,Attribute atribut)
Fixeaza valoarea atributului atribut a MBean-ului mbeanName. Retinem doarconstructorul clasei Attribute prin
Attribute(String nume, Object valoare)
• MBeanInfo getMBeanInfo(ObjectName mbeanName)
Returneaza un obiect de tip MBeanInfo util inspectarii resurselor unui MBean.
Exista mai multe sabloane de programare a ınregistrarii unei componente MBean.
Exemplul 10.1.2 Se creaza doua componente MBean de tip Intro care vor fi in-spectate prin intermediul utilitarului jconsole1 - distributia jdk .
Utilitarul jconsole permite apelarea operatiilor, modificarea atributelor si sem-naleaza notificarile.
1 package bas i c ;2 import java . lang . management . ∗ ;3 import javax . management . ∗ ;
5 public class Main{6 public stat ic void main ( St r ing [ ] a rgs ){7 St r ing domeniu=”” ;8 i f ( args . length >0) domeniu=args [ 0 ] ;9 try{
10 // Serveru l p l a t f o rme i11 MBeanServer mbs = ManagementFactory . getPlatformMBeanServer ( ) ;
13 //Varianta 114 // Construirea ObjectName corespunzator MBean−u l u i15 ObjectName mbeanObjectName =16 new ObjectName ( domeniu+” : type=Intro , index=1” ) ;
18 // Crearea MBean−u l u i19 In t ro mbean = new In t ro ( ) ;
21 // In r e g i s t r a r e a MBean−u l u i22 mbs . registerMBean (mbean , mbeanObjectName ) ;
24 //Varianta 225 mbeanObjectName=new ObjectName ( domeniu+” : type=Intro , index=2” ) ;26 mbs . createMBean ( ” ba s i c . In t ro ” , mbeanObjectName ) ;
28 // Asteptare n ed e f i n i t a29 System . out . p r i n t l n ( ”Waiting f o r e v e r . . . ” ) ;30 while ( true ) ;31 }32 catch ( Exception e ){33 System . e r r . p r i n t l n ( ” Exception : ”+e . getMessage ( ) ) ;34 }35 }36 }
1In acest caz, este nevoie ca variabilele de tip clasa acoperitoare Double, Long sa fie ınlocuiteprin tipuri predefinite.
10.1. STANDARD MBEAN 239
Executarea aplicatiei revine la
1. Intr-o fereastra DOS se lanseaza agentul Main prinjava -Dcom.sun.manager.jmxremote basic.Main
2. Intr-o alta fereastra DOS se lanseazajconsole
pornind utilitarul jconsole.
3. In fereastra de dialog jconsole:Connect to Agent se da clic pe Connect.
4. In panoul Tree gasim domeniul dat. Prin clic pe domeniu apar MBean-urilede indice 1 si 2.
5. Prin clic pe unul din aceste MBean-uri, ın panoul central avem acces la atributelesi la operatiile lor.
Rezultatul unei operatii apare ıntr-o fereastra de informare (Fig. 10.1).
10.1.3 Notificari
Pentru implementarea retinerii de catre un agent MBean a notificarilor, clasace implementeaza interfata MBean-ului trebuie sa extinda clasa Notification-
BroadcasterSupport.
Modificarile unui atribut se retin ıntr-un obiect de tip Notification si estetransmis prin metoda
sendNotification(Notification notification)
a clasei NotificationBroadcasterSupport.
Suplimentar se defineste metoda
public MBeanNotificationInfo[] getNotificationInfo()
ın care se precizeaza
• tipul notificarii - (constanta definita de clasa AttributeChangeNotification);
• clasa ın care s-a generat notificarea
String name = AttributeChangeNotification.class.getName();
• o descriere a modificarii.
Astfel, introducerea notificarilor presupune familiarizarea cu clasele
240 CAPITOLUL 10. JAVA MANAGEMENT EXTENSIONS
Figure 10.1: Rezultatele furnizate de jcluster.
• NotificationBroadcasterSupport
Constructori
– NotificationBroadcasterSupport()
Metode
– void sendNotification(Notification notificare)
• Notification
Constructori
– Notification(String type, Object source, long sequenceNumber)
– Notification(String type, Object source, long sequenceNumber, long
timeStamp)
10.1. STANDARD MBEAN 241
– Notification(String type, Object source, long sequenceNumber, long
timeStamp, String mesaj)
– Notification(String type, Object source, long sequenceNumber, String
mesaj)
Metode
– public void setUserData(Object userData)
– public Object getUserData()
• AttributeChangeNotification extends Notification
Constructori
– AttributeChangeNotification(Object source, long sequenceNumber,long timeStamp, String msg, String attributeName, String attribute-Type, Object oldValue, Object newValuE)
Campuri
– static String ATTRIBUTE CHANGE
Semnaleaza schimbarea atributului
Exemplul 10.1.3 Extinderea MBean-ului Intro cu notificarea modificarilor atributelorın jconsole.
Implementarea notificarilor ın clasa Intro presupune modificarea metodei setCursEuro.Totodata se adauga metoda getNotificationInfo, ce furnizeaza informatii referitoarela modificarea aparuta. Codul clasei care implementeaza interfata devine
1 package agentn ;2 import javax . management . ∗ ;
4 public class IntroN extends Not i f i c a t i onBroadcas t e rSuppor t5 implements IntroNMBean{6 private long sequenceNumber=1;
8 //Atr i bu te9 private f ina l St r ing label = ”Fac . Matematica s i In fo rmat i ca ” ;
10 private double cursEuro = 3 . 5 0 ;
12 public St r ing getLabe l ( ) { . . .}
14 public double getCursEuro ( ) { . . .}
16 public synchronized void setCursEuro (double cursEuro ) {17 double oldCursEuro=this . cursEuro ;18 this . cursEuro = cursEuro ;19 //System . out . p r i n t l n (”Curs de schimb euro : ” + euro+” ron . ” ) ;20 N o t i f i c a t i o n n=new Attr ibuteChangeNot i f i ca t i on (21 this ,
242 CAPITOLUL 10. JAVA MANAGEMENT EXTENSIONS
22 sequenceNumber++,23 System . cur r entT imeMi l l i s ( ) ,24 ”Schimbarea c u r s u l u i Euro” ,25 ” cursEuro ” ,26 ” double ” ,27 oldCursEuro ,28 cursEuro ) ;29 s e n d N o t i f i c a t i o n (n ) ;30 }
32 public MBeanNot i f i cat ionInfo [ ] g e t N o t i f i c a t i o n I n f o ( ) {33 St r ing [ ] types = new St r ing [ ] {34 Attr ibuteChangeNot i f i ca t i on .ATTRIBUTE CHANGE35 } ;36 St r ing name = Att r ibuteChangeNot i f i ca t i on . class . getName ( ) ;37 St r ing d e s c r i p t i o n = ”An a t t r i b u t e o f t h i s MBean has changed” ;38 MBeanNot i f i cat ionInfo i n f o =39 new MBeanNot i f i cat ionInfo ( types , name , d e s c r i p t i o n ) ;40 return new MBeanNot i f i cat ionInfo [ ] { i n f o } ;41 }
43 // Opera t i i44 public St r ing sayHe l lo ( ) { . . .}
46 public long cmmdc( long m, long n ) { . . .}47 }
In jconsole pentru notificare, ın prealabil este nevoie de subscriere.
10.1.4 Agent MBean
In exemplelele anterioare rezursele unui MBean au fost utilizate prin jconsole.Valorificarea resurselor unui MBean Intro, dintr-un MBeanServer (agent) se pro-grameaza prin
Exemplul 10.1.4
1 package agent ;2 import java . i o . IOException ;3 import javax . management . ∗ ;4 import javax . management . remote . ∗ ;5 import java . u t i l . Scanner ;
7 public class Agent{8 public stat ic void main ( St r ing [ ] a rgs ) {9 try {
10 // Crearea Agentu lu i − MBeanServer11 MBeanServer mbs = MBeanServerFactory . createMBeanServer ( ) ;
13 // Crearea unui MBean14 St r ing domain = mbs . getDefaultDomain ( ) ;15 St r ing className=” agent . In t ro ” ;16 St r ing sObjectName=domain+” : type=”+className ;17 ObjectName mbeanObjectName = new ObjectName ( sObjectName ) ;18 mbs . createMBean ( className , mbeanObjectName ) ;
10.1. STANDARD MBEAN 243
20 // U t i l i z a r e a MBean−u l u i21 // Apelarea o p e r a t i i l o r22 St r ing ope ra t i a=” sayHe l lo ” ;23 mbs . invoke ( mbeanObjectName , operat ia , null , null ) ;
25 ope ra t i a=”cmmdc” ;26 System . out . p r i n t l n ( ”Cmmdc a l numerelor : ” ) ;27 Scanner scanner=new Scanner ( System . in ) ;28 System . out . p r i n t l n ( ”Primul numar : ” ) ;29 long m=scanner . nextLong ( ) ;30 System . out . p r i n t l n ( ”Al d o i l e a numar : ” ) ;31 long n=scanner . nextLong ( ) ;32 Object [ ] param={m, n } ;33 St r ing [ ] s i gn={” long ” , ” long ” } ;34 Long r=(Long )mbs . invoke ( mbeanObjectName , operat ia , param , s i gn ) ;35 System . out . p r i n t l n ( ”cmmdc=”+r . t oS t r i ng ( ) ) ;
37 // U t i l i z a r e a A t r i b u t e l o r38 St r ing label=( St r ing )mbs . ge tAt t r ibut e ( mbeanObjectName , ” Label ” ) ;39 System . out . p r i n t l n ( ” Valoarea a t r i b u t u l u i l a b e l : ”+label ) ;
41 System . out . p r i n t l n ( ” I n t r o d u c e t i c u r s u l euro ” ) ;42 double cursEuro=scanner . nextDouble ( ) ;43 Attr ibute curs=new Attr ibute ( ”CursEuro” , cursEuro ) ;44 mbs . s e t A t t r i b u t e ( mbeanObjectName , curs ) ;45 Double euro=(Double )mbs . ge tAt t r ibut e ( mbeanObjectName , ”CursEuro” ) ;46 System . out . p r i n t l n ( ” Valoarea a t r i b u t u l u i cursEuro : ”+euro ) ;47 }48 catch ( Exception e ){49 System . out . p r i n t l n ( e . getMessage ( ) ) ;50 }51 }52 }
10.1.5 Invocarea la distanta
Din punct de vedere al programarii distribuite, cazul interesant este cel ın careclasa ce implementeaza MBean-ul si clientul (agentul MBean) care o utilizeaza seafla pe calculatoare diferite.
In acest caz:
• Este nevoie de o clasa server (agent) al carui rol este
– Instantierea unui MBeanServer
– Instantiarea unui server de conexiune, obiect de tip MBeanServerConnection.
Bazat pe tehnologia RMI sau RMI-IIOP, acest obiect gestioneaza comunicatiadintre un client si serverul MBeanServer. Serverul de conexiune si serverulMBeanServer apartin aceleiacsi clase.
– Lansarea ın executie a serverului de conexiune.
• Clientul dispune de interfata MBeanu-ului.
244 CAPITOLUL 10. JAVA MANAGEMENT EXTENSIONS
Interfata MBeanServerConnection este implementata de clasa MBeanServer Sablonulde programare pentru instantierea obiectului de tip MBeanServerConnection silansarea sa ın executie poate fi:
String surl="service:jmx:rmi:///jndi/rmi://host:port/numeServer"
// String surl="service:jmx:iiop:///jndi/iiop://host:port/numeServer";
// Crearea unui RMI server-conector
JMXServiceURL url = new JMXServiceURL(surl);
JMXConnectorServer cs =
JMXConnectorServerFactory.newJMXConnectorServer(url,null,MBeanServer);
//
// Pornirea server-conectorului RMI
cs.start();
System.out.println("Press Enter to finish !");
System.in.read();
cs.stop();
Serverul de conexiune are un nume, numeServer care trebuie cunoscut de catreclient.
Lansarea ın executie a serverului este precedata de pornirea registrului rmireg-istry, respectiv orbd.
Exemplul 10.1.5
1 package s e r v e r ;2 import java . i o . IOException ;3 import javax . management . ∗ ;4 import javax . management . remote . ∗ ;
6 public class MBServer{7 public stat ic void main ( St r ing [ ] a rgs ) {8 St r ing host=” l o c a l h o s t ” ;9 St r ing port=”1099” ;
10 i f ( args . l ength==0){11 System . out . p r i n t l n ( ”The name o f the s e r v e r i s r equ i r ed ” ) ;12 System . e x i t ( 0 ) ;13 }14 i f ( args . length >=2)15 host=args [ 1 ] ;16 i f ( args . length >=3)17 port=args [ 2 ] ;18 try {19 // Crearea MBeanServer20 MBeanServer mbs = MBeanServerFactory . createMBeanServer ( ) ;
22 // Crearea unui RMI server−conector23 St r ing s u r l=” s e r v i c e : jmx : rmi :/// j n d i /rmi : // ”+24 host+” : ”+port+”/”+args [ 0 ] ;25 // S t r ing s u r l=”s e r v i c e : jmx : i i o p :/// jnd i / i i o p ://”+26 // hos t+”:”+port+”/”+args [ 0 ] ;27 JMXServiceURL u r l=new JMXServiceURL( s u r l ) ;28 JMXConnectorServer cs=29 JMXConnectorServerFactory . newJMXConnectorServer ( ur l , null , mbs ) ;
10.1. STANDARD MBEAN 245
31 // Pornirea server−conec to ru lu i RMI32 cs . s t a r t ( ) ;33 System . out . p r i n t l n ( ” Press Enter to f i n i s h ! ” ) ;34 System . in . read ( ) ;35 cs . stop ( ) ;36 }37 catch ( Exception e ){38 System . out . p r i n t l n ( e . getMessage ( ) ) ;39 e . pr intStackTrace ( ) ;40 }41 }42 }
Primul argument care trebuie furnizat programului anterior (args[0]) este numeleserverului.
Clientul, la randul lui, este nevoit sa creeze un conector RMI catre server (agent),prin intermediul caruia obtine un obiect ce implementeaza interfata MBeanServerConnection.Prin acest obiect, clientul va putea crea MBean-uri - ın agent - si le va putea utilizaresursele.
Sablonul de programare pentru crearea obiectului MBeanServerConnection poatefi
JMXServiceURL url =
new JMXServiceURL("service:jmx:rmi:///jndi/rmi://host:port/numeServer");
JMXConnector jmxc = JMXConnectorFactory.connect(url,null);
// Obtinerea obiectului de tip MBeanServerConnection
MBeanServerConnection cs = jmxc.getMBeanServerConnection();
Resursele unui MBean se poate invoca prin
• metoda invoke(mbeanObjectName,operationName,param,sign) a interfeteiMBeanServerConnection.
• crearea unui reprezentant local al MBean-ului prin metoda statica
mbeanClass proxy =(mbeanClass)MBeanServerInvocationHandler.newProxyInstance(mbeanServerConnection,mbeanObjectName,mbeanClass.class,true);
In final, MBean-ul se sterge din serverul de conexiune, princs.unregisterMBean(mbeanObjectName).
Exemplul 10.1.6 Client ce utilizeaza un MBean Intro, definit ın Exemplul 10.1.1
1 package c l i e n t ;2 import java . i o . IOException ;3 import java . u t i l . ∗ ;4 import javax . management . ∗ ;5 import javax . management . remote . ∗ ;
246 CAPITOLUL 10. JAVA MANAGEMENT EXTENSIONS
7 public class Cl i en t {8 public stat ic void main ( St r ing [ ] a rgs ) {9 St r ing host=” l o c a l h o s t ” ;
10 St r ing port=”1099” ;11 i f ( args . length <=1){12 System . out . p r i n t l n ( ”The s e r v e r and domain names are r equ i r ed ” ) ;13 System . e x i t ( 0 ) ;14 }15 St r ing serverName=args [ 0 ] ;16 St r ing domain=args [ 1 ] ;17 i f ( args . length >=3) host=args [ 2 ] ;18 i f ( args . length >=4) port=args [ 4 ] ;19 Scanner scanner=new Scanner ( System . in ) ;20 try {21 //Crearea unui conector RMI s i a o b i e c t u l u i de t i p MBeanServercsection22 St r ing s u r l=” s e r v i c e : jmx : rmi :/// j n d i /rmi : // ”+23 host+” : ”+port+”/”+args [ 0 ] ;24 // S t r ing s u r l=”s e r v i c e : jmx : i i o p :/// jnd i / i i o p ://”+25 // hos t+”:”+port+”/”+args [ 0 ] ;26 JMXServiceURL u r l = new JMXServiceURL( s u r l ) ;27 JMXConnector jmxc = JMXConnectorFactory . connect ( ur l , null ) ;28 MBeanServerConnection cs = jmxc . getMBeanServerConnection ( ) ;
30 // Domeniile a g en tu l u i sunt31 System . out . p r i n t l n ( ”Domains : ” ) ;32 St r ing domains [ ] = cs . getDomains ( ) ;33 for ( int i = 0 ; i < domains . l ength ; i++) {34 System . out . p r i n t l n ( ”\tDomain [ ” + i + ” ] = ” + domains [ i ] ) ;35 }
37 // ia r domeniul imp l i c i t38 System . out . p r i n t l n ( ”DefaultDomain : ” +cs . getDefaultDomain ( ) ) ;39 System . out . p r i n t l n ( ”Domain : ” +domain ) ;
41 // Crearea unui MBean Intro42 St r ing className=” bas i c . In t ro ” ;43 St r ing sObjectName=domain+” : type=”+className ;44 ObjectName mbeanObjectName = new ObjectName ( sObjectName ) ;45 cs . createMBean ( className , mbeanObjectName , null , null ) ;
47 double cursEuro ;48 long m, n ;
50 // U t i l i z a r e a MBean−u l u i51 // Varianta 1 de invocare pr in proxy52 System . out . p r i n t l n ( ” Varianta de invocare pr in prox i ” ) ;53 IntroMBean proxy=54 ( IntroMBean ) MBeanServerInvocationHandler . newProxyInstance (55 cs ,56 mbeanObjectName ,57 c l i e n t . IntroMBean . class ,58 true ) ;
60 // U t i l i z a r e a o p e r a t i i l o r61 // opera t i a ” sayHe l lo ”62 proxy . sayHe l lo ( ) ;
64 // opera t i a cmmdc65 System . out . p r i n t l n ( ”Cmmdc a l numerelor : ” ) ;
10.1. STANDARD MBEAN 247
66 System . out . p r i n t l n ( ”Primul numar : ” ) ;67 m=scanner . nextLong ( ) ;68 System . out . p r i n t l n ( ”Al d o i l e a numar : ” ) ;69 n=scanner . nextLong ( ) ;70 System . out . p r i n t l n ( ”Cmmdc=”+proxy . cmmdc(m, n ) ) ;
72 // U t i l i z a r e a a t r i b u t e l o r73 System . out . p r i n t l n ( ”Numele : ”+proxy . getLabe l ( ) ) ;74 System . out . p r i n t l n ( ” I n t r o d u c e t i c u r s u l euro ” ) ;75 cursEuro=scanner . nextDouble ( ) ;76 proxy . setCursEuro ( cursEuro ) ;77 System . out . p r i n t l n ( ”Euro : ”+proxy . getCursEuro ( ) ) ;
79 // Varianta 2 de invocare pr in conexiune80 System . out . p r i n t l n ( ” Varianta de invocare pr in conexiune ” ) ;81 // Apelarea o p e r a t i i l o r82 St r ing ope ra t i a=” sayHe l lo ” ;83 cs . invoke ( mbeanObjectName , operat ia , null , null ) ;84 ope ra t i a=”cmmdc” ;85 System . out . p r i n t l n ( ”Cmmdc a l numerelor : ” ) ;86 System . out . p r i n t l n ( ”Primul numar : ” ) ;87 m=scanner . nextLong ( ) ;88 System . out . p r i n t l n ( ”Al d o i l e a numar : ” ) ;89 n=scanner . nextLong ( ) ;90 Object [ ] param={m, n } ;91 St r ing [ ] s i gn={” long ” , ” long ” } ;92 Long r=(Long ) cs . invoke ( mbeanObjectName , operat ia , param , s i gn ) ;93 System . out . p r i n t l n ( ”Cmmdc=”+r . t oS t r i ng ( ) ) ;
95 // U t i l i z a r e a A t r i b u t e l o r96 St r ing label=( St r ing ) cs . g e tAt t r ibut e ( mbeanObjectName , ” Label ” ) ;97 System . out . p r i n t l n ( ” Valoarea a t r i b u t u l u i l a b e l : ”+label ) ;
99 System . out . p r i n t l n ( ” I n t r o d u c e t i c u r s u l euro ” ) ;100 cursEuro=scanner . nextDouble ( ) ;101 Attr ibute curs=new Attr ibute ( ”CursEuro” , cursEuro ) ;102 cs . s e t A t t r i b u t e ( mbeanObjectName , curs ) ;103 Double newEuro=(Double ) cs . g e tAt t r ibute ( mbeanObjectName , ”CursEuro” ) ;104 System . out . p r i n t l n ( ” Valoarea a t r i b u t u l u i euro : ”+newEuro ) ;105 cs . unregisterMBean ( mbeanObjectName ) ;106 }107 catch ( Exception e ) {108 System . out . p r i n t l n ( e . getMessage ( ) ) ;109 }110 }111 }
Inspectarea si valorificarea resurselor unei componente MBean se poateface si prin intermediul metodei
1 private stat ic void getMBeanResources ( MBeanInfo i n f o ){2 System . out . p r i n t l n ( ”CLASA: \ t ” + i n f o . getClassName ( ) ) ;3 System . out . p r i n t l n ( ”DESCR: \ t ” + i n f o . g e tDe s c r i p t i on ( ) ) ;4 System . out . p r i n t l n ( ”ATTRIBUTE” ) ;5 MBeanAttributeInfo [ ] a t t r I n f o = i n f o . g e tAt t r i bu t e s ( ) ;6 i f ( a t t r I n f o . l ength > 0) {7 for ( int i = 0 ; i < a t t r I n f o . l ength ; i++) {8 System . out . p r i n t l n ( ”\tNUME: \ t ” + a t t r I n f o [ i ] . getName ( ) ) ;9 System . out . p r i n t l n ( ”\tDESC : \ t ” + a t t r I n f o [ i ] . g e tDe s c r i p t i on ( ) ) ;
248 CAPITOLUL 10. JAVA MANAGEMENT EXTENSIONS
10 System . out . p r i n t l n ( ”\tTIP : \ t ” + a t t r I n f o [ i ] . getType ( ) +11 ” READ: ”+ a t t r I n f o [ i ] . i sReadable ( ) +12 ” WRITE: ”+ a t t r I n f o [ i ] . i sWr i tab l e ( ) ) ;13 }14 }15 else16 System . out . p r i n t l n ( ”\ tFara a t r i b u t e ! ” ) ;17 System . out . p r i n t l n ( ”CONSTRUCTORI” ) ;18 MBeanConstructorInfo [ ] c o n s t r I n f o = i n f o . ge tConst ruc tor s ( ) ;19 for ( int i =0; i<c o n s t r I n f o . l ength ; i++) {20 System . out . p r i n t l n ( ”\tNUME: \ t ” + c o n s t r I n f o [ i ] . getName ( ) ) ;21 System . out . p r i n t l n ( ”\tDESCR: \ t ” + c o n s t r I n f o [ i ] . g e tDe s c r i p t i on ( ) ) ;22 System . out . p r i n t l n ( ”\tPARAM: \ t ” +23 c o n s t r I n f o [ i ] . g e tS ignature ( ) . l ength +” parametr i ” ) ;24 }25 System . out . p r i n t l n ( ”OPERATII” ) ;26 MBeanOperationInfo [ ] opInfo = i n f o . getOperat ions ( ) ;27 i f ( opInfo . l ength > 0) {28 for ( int i = 0 ; i < opInfo . l ength ; i++) {29 System . out . p r i n t l n ( ”\tNUME: \ t ” + opInfo [ i ] . getName ( ) ) ;30 System . out . p r i n t l n ( ”\tDESCR: \ t ” + opInfo [ i ] . g e tDe s c r i p t i on ( ) ) ;31 System . out . p r i n t l n ( ”\tPARAM: \ t ” +32 opInfo [ i ] . g e tS ignature ( ) . l ength +” parametr i ” ) ;33 }34 }35 else36 System . out . p r i n t l n ( ”\ tFara o p e r a t i i ” ) ;37 System . out . p r i n t l n ( ”NOTIFICARI” ) ;38 MBeanNot i f i cat ionInfo [ ] n o t i f I n f o = i n f o . g e t N o t i f i c a t i o n s ( ) ;39 i f ( n o t i f I n f o . l ength > 0) {40 for ( int i = 0 ; i < n o t i f I n f o . l ength ; i++) {41 System . out . p r i n t l n ( ”\tNUME: ” + n o t i f I n f o [ i ] . getName ( ) ) ;42 System . out . p r i n t l n ( ”\tDESCR: ” + n o t i f I n f o [ i ] . g e tDe s c r i p t i on ( ) ) ;43 St r ing not i fTypes [ ] = n o t i f I n f o [ i ] . getNot i fTypes ( ) ;44 for ( int j = 0 ; j < not i fTypes . l ength ; j++) {45 System . out . p r i n t l n ( ”\tTIP : ” + not i fTypes [ j ] ) ;46 }47 }48 }49 else50 System . out . p r i n t l n ( ”\ tFara n o t i f i c a r i ” ) ;51 }
Aceasta metoda poate fi inserata ın oricare din programele agent sau client.
Notificarea la distanta
Notificarea la distanta presupune utilizarea unui MBean posedand aceasta fa-cilitate. Pe partea de client trebuie implementat interfata NotificationListener
care declara metoda
public void handleNotification(Notification notification, Object
handback)
Atasarea si disponibilizarea clasei ce implementeaza interfata Notification
Listener se obtin prin metodele interfetei MBeanServerConnection:
10.1. STANDARD MBEAN 249
• void addNotificationListener(ObjectName name, NotificationListener
listener, NotificationFilter filter, Object handback )throws Instance-
NotFoundException, IOException
• void removeNotificationListener(ObjectName name, ObjectName listener)throws InstanceNotFoundException, ListenerNotFoundException, IOException
Exemplul 10.1.7 Folosind exemplul 10.1.6 - dar cu MBean-ul creat pentru 10.1.3se creaza un client cu notificare, care sesiseaza modificarea valoarii atributului cursEuroa MBean-ului IntroN.
Implementarea interfetei NotificationListener este
1 package c l i e n t ;2 import javax . management . N o t i f i c a t i o n ;3 import javax . management . N o t i f i c a t i o n L i s t e n e r ;4 import javax . management . At t r ibuteChangeNot i f i ca t i on ;
6 public class C l i e n t L i s t e n e r implements N o t i f i c a t i o n L i s t e n e r {7 public void h a n d l e N o t i f i c a t i o n ( N o t i f i c a t i o n n o t i f i c a t i o n ,8 Object handback ) {9 System . out . p r i n t l n ( ”\nReceived n o t i f i c a t i o n : ” + n o t i f i c a t i o n ) ;
10 Attr ibuteChangeNot i f i ca t i on myNotif=11 ( Att r ibuteChangeNot i f i ca t i on ) n o t i f i c a t i o n ;12 System . out . p r i n t l n ( ”Curs i n i t i a l : ” +13 myNotif . getOldValue ( ) . t oS t r i ng ( ) ) ;14 System . out . p r i n t l n ( ”Curs curent : ” +15 myNotif . getNewValue ( ) . t oS t r i ng ( ) ) ;16 }17 }
Codul clasei client este
1 package c l i e n t ;2 import java . i o . IOException ;3 import javax . management . ∗ ;4 import javax . management . remote . ∗ ;
6 public class C l i e n t N o t i f {7 public stat ic void main ( St r ing [ ] a rgs ) {8 St r ing host=” l o c a l h o s t ” ;9 St r ing port=”1099” ;
10 i f ( args . length <=1){11 System . out . p r i n t l n ( ”The s e r v e r and domain names are r equ i r ed ” ) ;12 System . e x i t ( 0 ) ;13 }14 St r ing serverName=args [ 0 ] ;15 St r ing domain=args [ 1 ] ;16 i f ( args . length >=3) host=args [ 2 ] ;17 i f ( args . length >=4) port=args [ 3 ] ;18 C l i e n t N o t i f obj=new C l i e n t N o t i f ( ) ;19 try {20 // Crearea unui conector RMI s i a o b i e c t u l u i21 // de t i p MBeanServerConnection22 St r ing s u r l=” s e r v i c e : jmx : rmi :/// j n d i /rmi : // ” +23 host+” : ”+port+”/”+args [ 0 ] ;
250 CAPITOLUL 10. JAVA MANAGEMENT EXTENSIONS
24 JMXServiceURL u r l = new JMXServiceURL( s u r l ) ;25 JMXConnector jmxc = JMXConnectorFactory . connect ( ur l , null ) ;26 MBeanServerConnection cs = jmxc . getMBeanServerConnection ( ) ;
28 // Crearea unui MBean Intro29 St r ing className=” bas i cn . IntroN ” ;30 St r ing sObjectName=domain+” : type=”+className ;31 ObjectName mbeanObjectName = new ObjectName ( sObjectName ) ;
33 MBeanInfo i n f o=cs . getMBeanInfo ( mbeanObjectName ) ;34 getMBeanResources ( i n f o ) ;
36 // U t i l i z a r e a n o t i f i c a r i i37 // Crearea unui a s c u l t a t o r38 C l i e n t L i s t e n e r l i s t e n e r = new C l i e n t L i s t e n e r ( ) ;39 // Act ivarea n o t i f i c a t o r u l u i40 cs . a d d N o t i f i c a t i o n L i s t e n e r ( mbeanObjectName , l i s t e n e r , null , obj ) ;
42 Thread . s l e e p ( 5 0 0 ) ;43 // D i s pon 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 i44 System . out . p r i n t l n ( ” Press Enter to f i n i s h ! ” ) ;45 try{46 System . in . read ( ) ;47 }48 catch ( java . i o . IOException e ){}49 cs . r e m o v e N o t i f i c a t i o n L i s t e n e r ( mbeanObjectName , l i s t e n e r ) ;50 // D i s pon i b i l i z a r e a o b i e c t u l u i MBeanObjectName51 cs . unregisterMBean ( mbeanObjectName ) ;52 }53 catch ( Exception e ) {54 System . out . p r i n t l n ( e . getMessage ( ) ) ;55 e . pr intStackTrace ( ) ;56 }57 }
59 private stat ic void getMBeanResources ( MBeanInfo i n f o ) { . . .}
61 }
Clasa Client care creaza MBean-ul trebuie lansata ınaintea clasei ClientNotif. Acestedoua clase pot rula pe calculatoare distincte.
Exemplul 10.1.8 O aplicatie servlet ıntretine un cont. Actiunile ce pot fi ıntreprinsesunt: depunerea unei sume, extragerea unei sume ın limita soldului si consultareacontului. Contul este implementat ca un MBean standard. Se cere urmarirea ladistanta a modificarilor suferite de cont.
Interfata contului (a MBean-ului) este
1 public interface ContMBean {2 // Atr i bu te3 // read−wr i t e4 public double getCont ( ) ;5 public void setCont (double cont ) ;6 }
implementat prin
10.1. STANDARD MBEAN 251
1 import javax . management . ∗ ;
3 public class Cont extends Not i f i c a t i onBroadcas t e rSuppor t4 implements ContMBean{5 private long sequenceNumber=1;6 private double cont ;
8 public synchronized double getCont ( ) {9 return cont ;
10 }
12 public synchronized void setCont (double cont ) {13 double oldCont=this . cont ;14 this . cont=cont ;15 N o t i f i c a t i o n n=new Attr ibuteChangeNot i f i ca t i on (16 this ,17 sequenceNumber++,18 System . cur r entT imeMi l l i s ( ) ,19 ”Schimbarea Cont” ,20 ” cont ” ,21 ” double ” ,22 oldCont ,23 cont ) ;24 s e n d N o t i f i c a t i o n (n ) ;25 }
27 public MBeanNot i f i cat ionInfo [ ] g e t N o t i f i c a t i o n I n f o ( ) {28 St r ing [ ] types = new St r ing [ ] {29 Attr ibuteChangeNot i f i ca t i on .ATTRIBUTE CHANGE30 } ;31 St r ing name = Att r ibuteChangeNot i f i ca t i on . class . getName ( ) ;32 St r ing d e s c r i p t i o n = ”An a t t r i b u t e o f t h i s MBean has changed” ;33 MBeanNot i f i cat ionInfo i n f o =34 new MBeanNot i f i cat ionInfo ( types , name , d e s c r i p t i o n ) ;35 return new MBeanNot i f i cat ionInfo [ ] { i n f o } ;36 }37 }
Codul servletului este
1 mport java . i o . ∗ ;2 import javax . s e r v l e t . ∗ ;3 import javax . s e r v l e t . http . ∗ ;4 import javax . management . ∗ ;5 import javax . management . remote . ∗ ;
7 public class Depoz i tSe rv l e t extends HttpServ l e t {8 MBeanServerConnection cs=null ;9 ObjectName mbeanObjectName=null ;
10 St r ing host ;11 St r ing port=”1099” ;12 St r ing s e r v e r=” s e r v e r ” ;
14 public void i n i t ( Se rv l e tCon f i g c o n f i g ) {15 try {16 super . i n i t ( c o n f i g ) ;17 host=c o n f i g . ge t In i tParameter ( ” jmxServerHost ” ) ;18 St r ing s u r l=” s e r v i c e : jmx : rmi :/// j n d i /rmi : // ”+host+” : ”+port+”/”+s e r v e r ;19 // S t r ing s u r l=”s e r v i c e : jmx : i i o p :/// jnd i / i i o p ://”+ hos t+”:”+port+”/”+serve r ;
252 CAPITOLUL 10. JAVA MANAGEMENT EXTENSIONS
20 JMXServiceURL u r l = new JMXServiceURL( s u r l ) ;21 JMXConnector jmxc = JMXConnectorFactory . connect ( ur l , null ) ;22 cs = jmxc . getMBeanServerConnection ( ) ;23 St r ing domain = cs . getDefaultDomain ( ) ;24 St r ing className=”Cont” ;25 St r ing sObjectName=domain+” : type=”+className ;26 mbeanObjectName = new ObjectName ( sObjectName ) ;27 cs . createMBean ( className , mbeanObjectName , null , null ) ;28 }29 catch ( Exception e ){30 System . out . p r i n t l n ( e . getMessage ( ) ) ;31 System . e x i t ( 0 ) ;32 }33 }
35 public void doGet ( HttpServ letRequest req , HttpServletResponse r e s )36 throws Serv le tExcept ion , IOException{37 ServletOutputStream out=r e s . getOutputStream ( ) ;38 St r ing oper=req . getParameter ( ” oper ” ) ;39 St r ing message=”” ;40 double suma=0;41 i f ( ! oper . equa l s ( ”con” ) ){42 St r ing s=req . getParameter ( ”suma” ) ;43 suma=Double . parseDouble ( s ) ;44 }45 Double objValue=null ;46 try{47 objValue=(Double ) cs . g e tAt t r ibute ( mbeanObjectName , ”Cont” ) ;48 }49 catch ( Exception e ){50 message=”JMX−Error : ”+e . getMessage ( ) ;51 }52 double value=objValue . doubleValue ( ) ;53 int index=−1;54 i f ( oper . equa l s ( ”dep” ) ) index =0;55 i f ( oper . equa l s ( ” ext ” ) ) index =1;56 i f ( oper . equa l s ( ”con” ) ) index =2;57 double x ;58 Attr ibute curs=null ;59 switch ( index ){60 case 0 :61 x=value+suma ;62 curs=new Attr ibute ( ”Cont” , x ) ;63 try{64 cs . s e t A t t r i b u t e ( mbeanObjectName , curs ) ;65 message=”S−a depus suma” ;66 }67 catch ( Exception e ){68 message=”JMX−Error : ”+e . getMessage ( ) ;69 }70 break ;71 case 1 :72 i f ( value>=suma){73 x=value−suma ;74 curs=new Attr ibute ( ”Cont” , x ) ;75 try{76 cs . s e t A t t r i b u t e ( mbeanObjectName , curs ) ;77 message=”S−a ex t ra s suma” ;78 }
10.1. STANDARD MBEAN 253
79 catch ( Exception e ){80 message=”JMX−Error : ”+e . getMessage ( ) ;81 }82 }83 else {84 message=” Cererea nu poate f i i n d e p l i n i t a ” ;85 }86 break ;87 case 2 :88 message=”Suma din cont e s t e ”+value+” un i t . ” ;89 break ;90 }91 r e s . setContentType ( ” text /html” ) ;92 out . p r i n t l n ( ”<html>” ) ;93 out . p r i n t l n ( ”<head><t i t l e >Depozit</ t i t l e ></head>” ) ;94 out . p r i n t l n ( ”<body>” ) ;95 out . p r i n t l n ( ”<h1>Operat iuni Cont</h1>” ) ;96 out . p r i n t l n ( ”<p>” ) ;97 out . p r i n t l n ( message ) ;98 out . p r i n t l n ( ”</p>” ) ;99 out . p r i n t l n ( ”</body></html>” ) ;
100 out . c l o s e ( ) ;101 }
103 public void doPost ( HttpServ letRequest req , HttpServletResponse r e s )104 throws Serv le tExcept ion , IOException{105 doGet ( req , r e s ) ;106 }107 }
Pagina de apelare a servletului fiind (index.html)
1 <html>2 <head>3 <t i t l e> Serv l e t−ul He l lo </ t i t l e>4 </head>5 <body bgcolor=”#aaeeaa ”>6 <center>7 <h1> Pagina de î nt re ţ i n e r e a d e p o z i t u l u i </h1>8 <form method=” post ”9 action=” http :// l o c a l h o s t :8080/ appcont/ appdepozit ”>
10 <p>Introduce ţ i :11 <p>Operaţ i a : <select name=” oper ” >12 <option value=”dep”>Depunere13 <option value=” ext ”>Extragere14 <option value=”con”>Consultare15 </ select>16 <p>17 <input type=” text ” name=”suma” value=”0”>18 <p>19 <input type=”submit” value=”Executa”>20 </form>21 </center>22 </body>23 </html>
Serverul MBean este cel prezentat ın Exemplul 10.1.5. Clientlul care urmareste dela distanta contul are codul
254 CAPITOLUL 10. JAVA MANAGEMENT EXTENSIONS
1 import java . i o . IOException ;2 import javax . management . ∗ ;3 import javax . management . remote . ∗ ;
5 public class C l i e n t N o t i f {6 public stat ic void main ( St r ing [ ] a rgs ) {7 St r ing host=” l o c a l h o s t ” ;8 St r ing port=”1099” ;9 i f ( args . l ength==0){
10 System . out . p r i n t l n ( ”The Server name i s r equ i r ed ” ) ;11 System . e x i t ( 0 ) ;12 }13 i f ( args . length >=2) host=args [ 1 ] ;14 i f ( args . length >=3) port=args [ 2 ] ;15 C l i e n t N o t i f obj=new C l i e n t N o t i f ( ) ;16 try {17 // Crearea unui conector RMI s i a o b i e c t u l u i de18 // t i p MBeanServerConnection19 St r ing s u r l=” s e r v i c e : jmx : rmi :/// j n d i /rmi : // ” +20 host+” : ”+port+”/”+args [ 0 ] ;21 JMXServiceURL u r l = new JMXServiceURL( s u r l ) ;22 JMXConnector jmxc = JMXConnectorFactory . connect ( ur l , null ) ;23 MBeanServerConnection cs = jmxc . getMBeanServerConnection ( ) ;
25 St r ing domain = cs . getDefaultDomain ( ) ;26 System . out . p r i n t l n ( ”DefaultDomain : ” +domain ) ;27 // Crearea unui MBean Intro28 St r ing className=”Cont” ;29 St r ing sObjectName=domain+” : type=”+className ;30 ObjectName mbeanObjectName = new ObjectName ( sObjectName ) ;
32 MBeanInfo i n f o=cs . getMBeanInfo ( mbeanObjectName ) ;33 getMBeanResources ( i n f o ) ;
35 // U t i l i z a r e a n o t i f i c a r i i36 // Crearea unui a s c u l t a t o r37 C l i e n t L i s t e n e r l i s t e n e r = new C l i e n t L i s t e n e r ( ) ;38 // Act ivarea n o t i f i c a t o r u l u i39 cs . a d d N o t i f i c a t i o n L i s t e n e r ( mbeanObjectName , l i s t e n e r , null , obj ) ;
41 Thread . s l e e p ( 5 0 0 ) ;42 // D i s pon 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 i43 System . out . p r i n t l n ( ” Press Enter to f i n i s h ! ” ) ;44 try{45 System . in . read ( ) ;46 }47 catch ( java . i o . IOException e ){}48 cs . r e m o v e N o t i f i c a t i o n L i s t e n e r ( mbeanObjectName , l i s t e n e r ) ;49 // D i s pon i b i l i z a r e a o b i e c t u l u i MBeanObjectName50 cs . unregisterMBean ( mbeanObjectName ) ;51 }52 catch ( Exception e ) {53 System . out . p r i n t l n ( e . getMessage ( ) ) ;54 e . pr intStackTrace ( ) ;55 }56 }
58 private stat ic void getMBeanResources ( MBeanInfo i n f o ) { . . .}59 }
10.1. STANDARD MBEAN 255
61 class C l i e n t L i s t e n e r implements N o t i f i c a t i o n L i s t e n e r {62 public void h a n d l e N o t i f i c a t i o n ( N o t i f i c a t i o n n o t i f i c a t i o n ,63 Object handback ){64 System . out . p r i n t l n ( ”\nReceived n o t i f i c a t i o n : ” + n o t i f i c a t i o n ) ;65 Attr ibuteChangeNot i f i ca t i on myNotif=66 ( Att r ibuteChangeNot i f i ca t i on ) n o t i f i c a t i o n ;67 System . out . p r i n t l n ( ” Sold i n i t i a l : ” +68 myNotif . getOldValue ( ) . t oS t r i ng ( ) ) ;69 System . out . p r i n t l n ( ” Sold curent : ” +70 myNotif . getNewValue ( ) . t oS t r i ng ( ) ) ;71 }72 }
Serverul MBean este cel utilizat ın exemplele anterioare.Serverul MBean este plasat ın servlet (ın catalogul WEB-INF/classes al aplicatiei)
iar clientul care urmareste de la distanta se poate afla oriunde.Dupa instalarea servlet-ului se lanseaza pe masina acestuia server-ul MBean.
Deoarece notificarea presupune existenta MBean-ului, iar acesta se instanteaza prinmetoda init a servlet-ului este nevoie de apelarea servlet-ului, depunand 0 unitati.Dupa aceasta operatie se lanseaza ın executie programul ClientNotif.
256 CAPITOLUL 10. JAVA MANAGEMENT EXTENSIONS
Capitolul 11
Teme de laborator
11.1 Probleme propuse
1. Sa se realizeze conversia temperaturii exprimata ın grade Celsius ın gradeFahrenheit si invers. Formula de transformare este
tF = 1.8tC + 32oF
In RMI, programul server implementeaza interfata (la distanta)
package conversie;
public interface Grade extends java.rmi.Remote{
public double celsiusToFahrenheit(double celsius)
// throws java.rmi.RemoteException;
public double fahrenheitToCelsius(double fahrenheit)
// throws java.rmi.RemoteException;
}
2. Sa se realizeze conversia a unei sume de bani ıntre USD, EURO si RON.
Programul server (RMI) implementeaza interfata
package exchange;
public interface IConversie extends java.rmi.Remote{
public double usdToEuro(double usd)
// throws java.rmi.RemoteException;
public double usdToRol(double usd)
// throws java.rmi.RemoteException;
public double euroToUsd(double euro)
// throws java.rmi.RemoteException;
public double euroToRol(double euro)
// throws java.rmi.RemoteException;
public double rolToEuro(double rol)
// throws java.rmi.RemoteException;
public double rolToUsd(double rol)
// throws java.rmi.RemoteException;
}
257
258 CAPITOLUL 11. TEME DE LABORATOR
Rata zilnica de schimb preia dinamic sub forma unui fisier xml, apelandhttp://www.bnr.ro/nbrfxrates.xml.
3. Sa se realizeze conversia unui numar natural, din cifre arabe ın cifre romanesi invers.
Pentru numere x ∈ (3999, 3999999], x = a ∗ 1000 + b se va folosi scrierea subforma (A)B, unde A,B reprezinta conversiile lui a, respectiv b.
Exemplu: Conversia numarului 2289463 este (MMCCLXXXIX)CDLXIII.
Pentru numere x ∈ (4000000, 3999999999], x = a ∗ 1000000 + b ∗ 1000 + c seva folosi scrierea sub forma [A](B)C, unde A,B,C reprezinta conversiile luia, b, c.
4. Sa se realizeze conversia unui numar dintr-o baza ın alta.
5. Un server aduna la un numar (initializat cu 0) o valoare trimisa de un clientreturnand rezultatul. Exista o singura instanta a numarului, acelasi pentruorice client.
Sa se programeze serviciul descris mai sus.
6. Aplicatia producator – consumator.
Fie un sistem format din doua procese P1 si P2, primul producand niste datecare apoi vor fi preluate de cel de al doilea. Comunicarea ıntre cele douaprocese se realizeaza prin intermediul unei zone de memorie – tampon, – de oanumita dimensiune, ın care procesul P1 introduce informatii (sub forma unorınregistrari), pe care apoi P2 le extrage.
Procesul P2 nu este nevoit sa astepte pentru fiecare ınregistrare ın parte, iarP1 nu astepta pana ce P2 este gata sa receptioneze ınregistrarea produsa.Procesele evolueaza independent unul de celalat, P1 introducand ın tamponınregistrarea produsa, de unde P2 o va extrage la nevoie.
Se impun urmatoarele restrictii:
• Procesul P1 ıncearca sa introduca o ınregistrare ın tampon si constataca acesta s-a umplut. In acest caz, el va trebui sa astepte pana ce seiveste un loc ın tampon (ceea ce se va ıntampla ca urmare a extrageriunei ınregistrari de catre P2).
• Procesul P2 ıncearca sa extraga o ınregistrare si constata ca tamponuleste gol. In acest caz el va trebui sa astepte pana ce apare o ınregistrareca urmare a introduceri unei ınregistrari ın tampon de catre P1.
Se defineste interfata RMI
11.1. PROBLEME PROPUSE 259
package iprodcons;
public interface IBoundedBuffer extends java.rmi.Remote{
public void put(Object obj) throws java.rmi.RemoteException;
public Object get() throws java.rmi.RemoteException;
}
Se cere:
(a) Implementarea interfetei IBoundedBuffer.
(b) Realizarea a doua programe client Producator, care introduce obiecte ıntampon si Consumator pentru extragerea lor.
7. Aplicatie de e-mail.
Un e-mail este definit printr-un ansamblu de 4 variabile de tip String
(de la (from), catre (to), subiect (subject), mesaj (body)).
package iemail;
import java.io.Serializable;
public class Email implements Serializable {
public String from = "";
public String subject = "";
public String to = "";
public String body = "";
public Email() {}
public Email(String from, String to, String subject, String body) {
this.from =from;
this.subject =subject;
this.to =to;
this.body =body;
}
}
Interfata aplicatiei RMI IEmailServer este
package iemail;
import java.rmi.*;
public interface IEmailServer extends Remote {
public boolean login(String name, String password)
throws RemoteException;
public void createUser(String name, String password)
throws RemoteException;
public void writeEmail(String from, String to,
String subject, String body) throws RemoteException,
UnknownUserException;
public void readEmail(String userName,ICallbackEmail ce)
throws RemoteException;
}
260 CAPITOLUL 11. TEME DE LABORATOR
Un client / utilizator al serviciului sau serverului de e-mail este o instanta aclasei User.
package email;
import java.util.*;
import iemail.*;
public class User implements java.io.Serializable{
String name, password;
Vector emails = new Vector();
public User(String name, String password) {
this.name = name;
this.password = password;
}
public void addEmail(Email email) {
emails.addElement(email);
}
}
Pentru a putea folosi serverul de e-mail, un client trebuie ın prealabil sa seınregistreze (createUser).
Un client ınregistrat se poate conecta la serverul de e-mail (login) dupa carepoate scrie (trimite) sau citi (receptiona) mesaje.
Se cere ca la adagarea unui mesaj (deci ınaintea apelarii metodei User.addEmail)sa se verifice daca emitentul este conectat si daca destinatarul este ınregistrat.ın caz contrar se genereaza exceptia UnknownUserException
package iemail;
public class UnknownUserException extends Exception {
public UnknownUserException() {
super();
}
public UnknownUserException(String exception) {
super(exception);
}
}
Citirea mesajelor este lasata la latitudinea clientilor ın sensul ca clientul im-plementeaza metoda printEmail al interfetei ICallbackEmail.
package iemail;
import java.rmi.*;
import java.rmi.server.*;
public interface ICallbackEmail extends Remote {
public void printEmail(Email email) throws RemoteException;
}
11.1. PROBLEME PROPUSE 261
Solicitarea receptionarii mesajelor se realizeaza de catre server prin apelareametodei printEmail pentru fiecare mesaj primit de client.
Se cere:
(a) Implementarea interfetei IEmailServer.
(b) Realizarea a doua programe client AddClient pentru ınregistrarea utiliza-torilor si ClientEmail pentru exploatarea serviciului de e-mail. Fiecaredin cele doua programe are ca parametri numele (identificatorul) clientu-lui, parola si referinta serverului.
8. Integrare numerica.
Scopul aplicatiei este calculul unei integrale de un program server cu functiade integrat detinuta de catre client. In cazul aplicatiei RMI, evaluarile functieicerute de formula de integrare numerica se vor realiza prin apel invers. Inte-grarea numerica va fi executat de un server disponibil clientilor prin mecanis-mul de fabrica de obiecte.
Interfata fabricii de obiecte este
package integ;
import java.rmi.*;
public interface IFabIntegrator extends Remote{
IIntegrator getIntegrator() throws RemoteException;
}
iar interfata IIntegrator este
package integ;
import java.rmi.*;
public interface IIntegrator extends Remote{
double adaptiveSimpson(double leftEnd, double rightEnd,
double epsilon, int initParam) throws RemoteException;
}
declara o metoda ce calculeaza un sir (Imk)k pana ın momentul |Imk
−Imk−1| <
ε.
Propunem utilizarea formulei lui Simpson
∫ b
af(x)dx ≈ Im =
b− a
6m[f(a) + 2
m−1∑i=1
f(a2i) + 4m−1∑i=0
f(a2i+1) + f(b)]
unde ai = a + i b−a2m .
Sirul (mk)k este definit prin mk = 2km0.
Semnificatia parametrilor metodei adaptiveSimpson este
262 CAPITOLUL 11. TEME DE LABORATOR
leftEnd arightEnd bepsilon εinitParam m0
Interfata apelului invers este
package integ;
import java.rmi.*;
double function(double x)throws RemoteException;
}
Se cere implementarea aplicatiei cu minimizarea numarului de apelari a metodeifunction.
9. Agenda telefonica.
Pentru crearea si ıntretinerea unei agende telefonice utilizand RMI consideram:
Un ServerCarteTelefon realizeaza urmatoarele operatii:
• adauga o ınregisrare ın agenda telefonica;
O ınregistrare este alcatuita dintr-o pereche (nume, numar).
package itelef;
import java.io.Serializable;
public class Entry implements Serializable{
public String nume,numar;
public Entry(String nume,String numar){
this.nume=nume;
this.numar=numar;
}
}
• sterge ınregistrarea corespunzatoare unui nume din agenda telefonica.
• interogarea agendei: furnizeaza numarul de telefon al unui nume;
• modificarea numarului de telefon corespunzator unui nume;
• afisarea ınregistrarilor;
• salvarea ınregistrarilor ıntr-un fisier;
• restaurarea ınregistrarilor dintr-un fisier.
Interfata corespunzatoare ICarteTelefon este
package itelef;
import java.rmi.*;
public interface ICarteTelefon extends Remote{
void addEntry(Entry e)throws RemoteException;
String lookupNumber(String p)throws RemoteException;
void deleteEntry(Entry e)throws RemoteException;
11.1. PROBLEME PROPUSE 263
Entry[] list() throws RemoteException;
void save(String file)throws RemoteException;
void restore(String file)throws RemoteException,ClassNotFoundException;
void modifyEntry(Entry e)throws RemoteException;
}
Interfata fabricii de obiecte IFabCarteTelefon este
package itelef;
import java.rmi.*;
public interface IFabCarteTelefon extends Remote{
ICarteTelefon getCarteTelefon() throws RemoteException;
}
Se cere implementarea aplicatiei de creare si ıntretinere a agendei telefonice.
Se extinde aplicatia anterioara cu functiunea suplimentara a serverului de aretine toate modificarile efectuate de catre un client si care la solicitare pot fiafisate.
Modificarile se retin ıntr-o variabila mod de tip Vector. La solicitarea clien-tului, pentru fiecare modificare memorata, programul server apeleaza metodaschimbStare declarata ın interfata
package itelef;
import java.rmi.*;
public interface IApelInvers extends Remote{
void schimbStare(Entry e) throws RemoteException;
}
Metoda schimbStare(Entry e) nu face altceva decat afiseaza campurile vari-abilei e.
Interfata ICarteTelefon declara ın plus metoda
void apelInvers(IApelInvers obj)throws RemoteException;
Aceasta metoda va fi implementata ın programul ServerCarteTelefon.java.Elementelor retinute ın vectorul mod li se aplica metoda schimbStare().
Sa se implementeze acesta functiune utilizand tehnica apelului invers.
Se poate utiliza baza de date AGENDATELEFONICA formata din tabelul
TELEF
ID
NUME
NUMAR
264 CAPITOLUL 11. TEME DE LABORATOR
10. Sa se realizeze programe client avand o interfata grafica. Recomandam uti-lizarea produsului NetBeans.
R. Exemplu de client pentru problema calculului celui mai mare divizor comuna doua numere cu soclu TCP.
import java.net.*;
import java.io.*;
public class VisualCmmdcClient extends javax.swing.JFrame {
public VisualCmmdcClient() {
initComponents();
}
private void initComponents(){
// cod generat de Netbeans
}
private void jButton1MouseClicked(java.awt.event.MouseEvent evt){
long m=(new Long(jTextField1.getText())).longValue();
long n=(new Long(jTextField2.getText())).longValue();
String host=jTextField4.getText();
int port=(new Integer(jTextField5.getText())).intValue();
Socket cmmdcSocket = null;
DataInputStream in=null;
DataOutputStream out=null;
try {
cmmdcSocket = new Socket(host, port);
out=new DataOutputStream(cmmdcSocket.getOutputStream());
in=new DataInputStream(cmmdcSocket.getInputStream());
}
catch(UnknownHostException e) {
System.err.println("Server necunoscut: "+host);
System.exit(1);
}
catch (IOException e) {
System.err.println("Eroare I/O : "+host+" la portul "+port);
System.exit(1);
}
try{
out.writeLong(m);
out.writeLong(n);
long r=in.readLong();
jTextField3.setText(new Long(r).toString());
out.close();
in.close();
cmmdcSocket.close();
}
catch(IOException e){
System.err.println("Imposibilitate de comunicare");
}
}
private void exitForm(java.awt.event.WindowEvent evt) {
System.exit(0);
}
public static void main(String args[]) {
11.1. PROBLEME PROPUSE 265
new VisualCmmdcClient().setVisible(true);
}
private javax.swing.JButton jButton1;
private javax.swing.JLabel jLabel1;
private javax.swing.JLabel jLabel2;
private javax.swing.JLabel jLabel3;
private javax.swing.JLabel jLabel4;
private javax.swing.JTextField jTextField1;
private javax.swing.JTextField jTextField2;
private javax.swing.JTextField jTextField3;
private javax.swing.JTextField jTextField4;
private javax.swing.JTextField jTextField5;
}
11. Sa se determine zodia (chinezeasca) corespunzatoare unei date calendaristice.Obs. Inceputul anului nou chinezesc nu coincide cu ınceputul anului nou cal-endaristic.
Se va crea baza de date AN CHINEZESC alcatuita din tabelul
INCEPUT
AN
LUNA
ZI
12. Se considera baza de date UNITATI DE MASURA formata din tabelul
CONVERSIE
UM SI
UM SIMBOL
DENUMIRE (ROM)
VAL
Exemplu:
1 M INCH Tol 0.02542 M FEET (FT) Picior 0.30483 KG UK ONCE Uncie (UK) 0.0311034 KG UK POUND Livra (UK) 0.373
Sa se realizeze o aplicatie pentru conversia unitatilor de masura extinzandcontinutul bazei de date.
13. Se considera baza de date NORME-DIDACTICE formata din tabelele
CADRU-DIDACTIC MATERIA CURSURI
COD-CADRU-DIDACTIC COD-MATERIE COD-CURS
NUME DENUMIRE COD-CADRU-DIDACTIC
COD-MATERIE
266 CAPITOLUL 11. TEME DE LABORATOR
Sa se elaboreze programe de ıntretinere si interogare a bazei de date.
14. Se considera baza de date APROVIZIONARE formata din tabelele
RESURSA FURNIZOR CONTRACT
COD-RESURSA COD-FURNIZOR COD-CONTRACT
DENUMIRE NUME COD-FURNIZOR
CANTITATE COD-RESURSA
CANTITATE
Sa se elaboreze programe de ıntretinere si interogare a bazei de date.
15. Se considera baza de date DESFACERE formata din tabelele
PRODUSE BENEFICIAR CONTRACT
COD-PRODUS COD-BENEFICIAR COD-CONTRACT
DENUMIRE NUME COD-BENEFICIAR
CANTITATE COD-PRODUS
CANTITATE
Sa se elaboreze programe de ıntretinere si interogare a bazei de date.
16. Validarea codului numeric personal.
Codul Numeric Personal (CNP) constituie numarul de ordine atribuit de Evidenta
populatiei unei persoane la nastere, de cetatenie romana, care se ınscrie ın actele si
certificatele de stare civila si se preia ın celelate acte cu caracter oficial.
Structura unui CMP este
S AA LL ZZ JJ ZZZ C
| | | | | | |-> cifra de control
| | | | | |-> numar de ordine atribuit persoanei
| | | | |-> codul judetului
| | | |-> ziua nasterii
| | |-> Luna nasterii
| |-> Anul nasterii
|-> Cifra sexului (M/F)
1/2 nascuti intre 1 ian 1900 si 31 dec 1999
3/4 nascuti intre 1 ian 1800 si 31 dec 1899
5/6 nascuti intre 1 ian 2000 si 31 dec 2099
7/8 rezidenti
11.1. PROBLEME PROPUSE 267
Verificarea cifrei de control: Se foloseste cheia de testare 279146358279. Primele12 cifre ale CNP se ınmultesc pe rand de la staga spre dreapta cu cifra core-spunzatoare a cheii de testare. Cele 12 produse se aduna, iar suma se ımpartela 11. Daca restul ımpartirii este mai mic decat 10, atunci acesta va fi cifra decontrol. Daca restul ımpartirii este 10 atunci cifra de control este 1.
Sa se elaboreze un program pentru verificarea CNP.
17. Informatiile unui aeroport civil privind decolarile(plecari) si aterizari(sosiri)pe parcursul unei perioade sunt cuprinse ın tabelul activitate al bazei de dateaeroport
ACTIVITATE
IDFEL aterizare/decolareZITIMP ora/minutCOMPANIEOBSERVATIE
Sa se realizeze o aplicatie de furnizare a datelor catre clienti.
268 CAPITOLUL 11. TEME DE LABORATOR
Appendix A
Unealta de dezvoltareapache-ant
Incepem aceasta sectiune prin a introduce cateva elemente privind sintaxa ıntr-un document xml pentru ca apache-ant va face apel la un fisier xml.
XML
EXtensible Markup Language (XML) reprezinta un limbaj pentru definirea mar-cajelor de semantica, care ımpart un document ın parti identificabile ın document.Din 1998, XML este un standard World Wide Web Consortium (W3C).
Totodata XML este un meta-limbaj pentru definirea sintaxei de utilizat ın altedomenii.
XML descrie structura si semantica si nu formatarea.
Structura unui document XML este
<?xml version="1.0" encoding="tip_codare" [standalone="yes"]?>
corpul documentului alcatuit din elemente
Prima linie - preambulul - reprezinta declaratia de document XML. Tipul codariipoate fi utf-8, iso-8859-1.
Corpul documentului este alcatuit din elemente. Inceputul unui element esteindicat printr-un marcaj. Textul marcajului constituie denumirea elementului. El-ementele pot fi cu corp, alcatuit din alte elemente, avand sintaxa
<marcaj>
corpul elementului
</marcaj>
sau fara corp, caz ın care sintaxa este
269
270 APPENDIX A. UNEALTA DE DEZVOLTARE APACHE-ANT
<marcaj/>
Un marcaj poate avea atribute date prin sintaxa
numeAtribut="valoareAtribut"
Valoarea unui atribut este cuprinsa ıntre ghilimele (””).
<marcaj numeAtribut="valoareAtribut" . . .>
corpul elementului
</marcaj>
Exista un singur element radacina. Elementele unui document XML formeazaun arbore. Fiecarui marcaj de ınceput al unui element trebuie sa-i corespunda unmarcaj de sfarsit. Caracterele mari si mici din denumirea unui element sunt distincte(case sensitive).
Elementele ıncuibarite (nested)- incluse ıntr-un alt element - nu se pot amesteca,adica un marcaj de sfarsit corespunde ultimului marcaj de ınceput.
Un comentariu se indica prin
<!--
Text comentariu
-->
Exemplul A.0.1 Fisier XML - denumirile elementelor si continutul lor permit ıntelegereasimpla a semanticii introduse ın document.
1 <?xml version=” 1 .0 ” encoding=” utf−8”?>2 <c u r s u r i>3 <d i s c i p l i n a f e l=” o b l i g a t o r i u ”>4 <nume> Anal iza numerica </nume>5 <fond−de−timp>6 <curs> 2 </ curs>7 <seminar> 1 </ seminar>8 <l a b o r a t o r> 1 </ l a b o r a t o r>9 </ fond−de−timp>
10 </ d i s c i p l i n a>11 <d i s c i p l i n a f e l=” o b l i g a t o r i u ”>12 <nume> Programare d i s t r i b u i t a </nume>13 <fond−de−timp>14 <curs> 2 </ curs>15 <seminar> 0 </ seminar>16 <l a b o r a t o r> 2 </ l a b o r a t o r>17 </ fond−de−timp>18 </ d i s c i p l i n a>19 <d i s c i p l i n a f e l=” o b l i g a t o r i u ”>20 <nume> So f t matematic </nume>21 <fond−de−timp>22 <curs> 2 </ curs>23 <seminar> 0 </ seminar>24 <l a b o r a t o r> 1 </ l a b o r a t o r>25 </ fond−de−timp>26 </ d i s c i p l i n a>27 </ c u r s u r i>
271
Un document XML este bine formatat daca:
• exista preambul;
• fiecare element este ınchis sau ıi corespunde un marcaj de inchidere;
• marcajele ıncuibarite nu se amesteca.
Un document XML este valid daca
• este bine formatat;
• ın cazul ca exista o referinta catre XML Schema atunci documentul XML esteconform schemei.
Prelucrarea unui document XML ın Java se poate face pe baza interfetelor deprogramare:
• Document Object Model - DOM;
• Simple API for XML - SAX;
• Stream API for XML - StAX;
• Java Architecture for XML Binding - JAXB.
Se recomanda utilizarea interfetelor de programare StAX si JAXB.
Amintim faptul ca reprezentarea obiectelor matematice prin elemente XML con-stituie subiectul a doua proiecte MathML si OpenMath. Obiectivul limbajului MathMLeste reprezentarea unui text matematic ıntr-un document HTML, ın timp ce obiec-tivul proiectului OpenMath este reprezentarea semantica a datelor matematice pen-tru realizarea de aplicatii cooperante ıntre sisteme de calcul simbolic - CAS (Com-puter Algebra System).
apache-ant
Utilitarul apache-ant asigura executarea unui sir de comenzi de operare. Acestecomenzi se ınregistreaza ıntr-un fisier de tip xml, cu denumirea build.xml. Astfel,apache-ant se substituie unui fisier de comenzi bat ın Windows sau unui script shelldin Linux/Unix. Avantajul obtinut consta ın independenta fata de platforma decalcul (Windows, Linux).
Instalarea consta ın dezarhivarea fisierului descarcat din Internet.
Lansarea ın executie necesita fixarea variabilei de mediu JAVA HOME, ce continecalea la distributia Java. Lansarea se poate face prin urmatorul fisier de comenzi
272 APPENDIX A. UNEALTA DE DEZVOLTARE APACHE-ANT
set JAVA_HOME=. . .
set ANT_HOME=. . .
%ANT_HOME%\bin\ant.bat %1
Parametrul %1 acestui fisier de comenzi reprezinta obiectivul care se doreste afi atins. Daca se modifica denumirea sau locatia fisierului build.xml atunci fisierulde comenzi se invoca cu optiunea -buildfile.
Un fisier build.xml corespunde unui proiect (project), alcatuit din unul sau maimulte obiective (target). Atingerea fiecararui obiectiv consta din ındeplinirea uneiasau mai multor sarcini (task). Apache-ant contine o familie predefinita de sarcini.Programatorul are datoria fixarii atributelor sarcinilor. Manualul din documentatiaprodusului contine descrierea atributelor cat si exemple. In general, o sarcinareprezinta o operatie executata uzual ın linia de comanda.
Atributele se dau, respectand sintaxa XML
numeAtribut = ”valoareAtribut”
Astfel, un proiect apare sub forma
<project name="numeProiect"
default="obiectiv"
basedir="catalogDeReferinta">
<target name="numeObiectiv">
sarcini
</target>
. . . . . . .
</project>
Daca la apelarea lui Apache-ant lipseste parametrul optional atunci se va executaobiectivul default.
Intr-un proiect se pot defini variabile prin marcajul
<property name=”numeVariabila” value=”valoareVariabila” />
O variabila definita se va utiliza cu sintaxa ${numeVariabila}.
Exemplul A.0.2 Fisierul build pentru executia programelor din §1.2.
1 <p r o j e c t name=” Socket ” default=” Server ” ba s ed i r=” . ”>2 <d e s c r i p t i o n> S o c l u r i TCP </ d e s c r i p t i o n>
4 < !−− s e t g l o b a l p r op e r t i e s f o r t h i s b u i l d −−>5 <property name=” bu i ld ” l o c a t i o n=”work”/>6 <property name=” s r c ” l o c a t i o n=” . ” />
8 <t a r g e t name=” i n i t ”>
273
9 < !−− Create the time stamp −−>10 <tstamp/>11 < !−− Create the b u i l d d i r e c t o r y s t r u c t u r e used by compile −−>12 <d e l e t e d i r=”${ bu i ld }”/>13 <mkdir d i r=”${ bu i ld }”/>14 </ t a r g e t>
16 <t a r g e t name=”Compile” depends=” i n i t ” d e s c r i p t i o n=” compile the source ” >17 <javac s r c d i r=”${ s r c }” d e s t d i r=”${ bu i ld }” inc ludeantrunt ime=” f a l s e ”/>18 </ t a r g e t>
20 <t a r g e t name=” Server ” depends=”Compile”>21 <java classname=”MyMServer” c l a s s pa th=”${ bu i ld }” f o rk=” true ”/>22 </ t a r g e t>
24 <t a r g e t name=” Cl i en t ”>25 <java classname=”VisualCmmdcClient” c l a s sp a t h=”${ bu i ld }” f o rk=” true ”/>26 </ t a r g e t>27 </ p r o j e c t>
Utilizarea lui apache-ant presupune ca toate resursele utilizate, cuprinse uzualın fisiere cu extensia jar (j ava arhive) sunt disponibile pe calculatorul local. Dacacalculatorul este conectat la Internet, atunci resursele publice pot fi descarcateımpreuna cu toate dependintele si utilizate prin apache-ant, folosind suplimentarapache-ivy 1.
In vederea utilizarii lui apache-ivy se copiaza fisierul ivy-*.jar din distributiaapache-ivy ın ANT HOME\lib.
Fisierul build.xml contine ın plus
<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">
1Asemanator cu maven, un alt produs de dezvoltare.
274 APPENDIX A. UNEALTA DE DEZVOLTARE APACHE-ANT
<ivy:report todir="${report.dir}"/>
</target>
. . .
</project>
la care se adauga un fisier ivy.xml, cu dependintele necesare aplicatiei care urmeazaa fi preluate dintr-unul din depozitele ivy - local, shared, public
<ivy-module version="2.0">
<info organisation="cs.unitbv.ro" module="Biblioteca-Ivy"/>
<dependencies>
<dependency org="commons-fileupload" name="commons-fileupload" rev="1.2"/>
. . .
</dependencies>
</ivy-module>
Appendix B
Utilizarea SGBD ın Java
Scopul acestei anexe este prezentarea bazelor utilizarii unui Sistem de Gestiunea Bazelor de Date (SGBD - Data Bases Management System - DBMS) din Java.Exemplificam modul de operare si utilizare pentru crearea si exploatarea unei bazede date corespunzatoare unei agende telefonice.
B.1 Derby / Javadb
Instalarea produsului consta ın dezarhivarea fisierului descarcat.Utilizarea produsului. Va fi utilizata varianta de retea bazata pe un server al
SGBD care utilizeaza implicit portul 1527.Se ıntreprind urmatoarele operatii:
1. Lansarea serverului Derby / Javadb:
set JAVA_HOME=. . .
set DB_HOME=. . .
set PATH=%DB_HOME%\bin;%PATH%
startNetworkServer.bat
2. Crearea bazei de date se va face utilizand utilitarul ij din distributia Derby /Javadb. Acesta se lanseaza prin:
set JAVA_HOME=. . .
set DB_HOME=. . .
set PATH=%DB_HOME%\bin;%PATH%
ij.bat
Exemplul B.1.1
Baza de date AgendaEMail se creaza executand
run ’CreateAgendaE.sql’;
unde fisierul CreateAgendaE.sql este
275
276 APPENDIX B. UTILIZAREA SGBD IN JAVA
1 connect ’ jdbc : derby : AgendaEMail ; c r e a t e=true ’ ;2 create table adrese (3 id int generated always as identity ( s t a r t with 1 , increment by 1)4 primary key ,5 nume char (20) not null ,6 emai l char (30) not null7 ) ;
si ıncarcarea cu date
run ’ValuesAgendaE.sql’;
cu fisierul ValuesAgendaE.sql
1 insert into adrese (nume , emai l ) values ( ’ aaa ’ , ’ aaa@yahoo . com ’ ) ,2 ( ’ bbb ’ , ’ bbb@gmail . com ’ ) , ( ’ ccc ’ , ’ ccc@unitbv . ro ’ ) ,3 ( ’ aaa ’ , ’ xyz@unitbv . ro ’ ) ;
Putem crea tabele si le ıncarca cu valori prin ant. In acest caz, ın prealabiltrebuie creata baza de date prin intermediul utilitarului ij:
connect ’jdbc:derby:AgendaEMail;create=true’;
Fisierul build.xml are codul
<?xml version="1.0"?>
<project name="db" basedir="." default="usage">
<property file="build.properties"/>
<path id="master-classpath">
<pathelement path="${db}"/>
</path>
<target name="createTables">
<echo message="CREATE TABLES USING: ${db.driver} ${db.url}"/>
<sql driver="${db.driver}"
url="${db.url}"
userid="${db.user}"
password="${db.pw}"
onerror="continue"
src="${createTable}">
<classpath refid="master-classpath"/>
</sql>
</target>
<target name="dropTables">
<echo message="DROP TABLES USING: ${db.driver} ${db.url}"/>
<sql driver="${db.driver}"
url="${db.url}"
userid="${db.user}"
password="${db.pw}"
onerror="continue">
<classpath refid="master-classpath"/>
B.2. MYSQL 277
DROP TABLE adrese;
</sql>
</target>
<target name="loadData">
<echo message="LOAD DATA USING: ${db.driver} ${db.url}"/>
<sql driver="${db.driver}"
url="${db.url}"
userid="${db.user}"
password="${db.pw}"
onerror="continue"
src="${valuesTable}">
<classpath refid="master-classpath"/>
</sql>
</target>
<target name="printData">
<echo message="PRINT DATA USING: ${db.driver} ${db.url}"/>
<sql driver="${db.driver}"
url="${db.url}"
userid="${db.user}"
password="${db.pw}"
onerror="continue"
print="true">
<classpath refid="master-classpath"/>
SELECT * FROM adrese;
</sql>
</target>
</project>
Resursele externe utilizate se fixeaza ın fisierul de proprietati build.properties
db.driver=org.apache.derby.jdbc.ClientDriver
db.url=jdbc:derby://localhost:1527/AgendaEMail
db.user=. . .
db.pw=. . .
createTable=AntCreateAdrese.sql
valuesTable=ValuesAgendaE.sql
db=. . ./db-derby-10.5.3.0-bin/lib/derbyclient.jar
B.2 mysql
Instalarea produsului. Pentru instalare s-a descarcat varianta fara instalareautomata mysql-noinstall-*.*.*-win32.zip. Acest fisier se dezarhiveaza ıntr-un cata-log MYSQL HOME.
Implicit, serverul mysql utilizeaza portul 3306, iar fisierele bazelor de date vor figazduite ın catalogul MYSQL HOME\data.
Pentru utilizarea ın aplicatii Java trebuie descarcat un conector mysql-connector-java-*.*.*.tar.gz, continand fisierul mysql-connector-java-*.*.*-bin.jar.
278 APPENDIX B. UTILIZAREA SGBD IN JAVA
Utilizarea produsului.Se ıntreprind urmatoarele operatii:
1. Lansarea serverului mysql :
set MYSQL_HOME=. . .
set PATH=%MYSQL_HOME%\bin;%PATH%
mysqld
2. Unui utilizator i se poate atasa o parola, executand ıntr-o sesiune mysql comen-zile
set password for ’root’@’localhost’=password(’parola’);
set password for ’root’@’127.0.01’=password(’parola’);
Parola se sterge prin
set password for ’root’@’localhost’=password(’’);
set password for ’root’@’127.0.01’=password(’’);
Daca utilizatorul are o parola atunci la apelarea utilitarului mysql va fi prezentasi optiunea -p.
3. Exemplul B.2.1
Crearea bazei de date AgendaEMail se va face prin intermediul fisierului decomenzi
set MYSQL_HOME=d:\mysql-*-win32\bin
set path=%MYSQL_HOME%;%PATH%
mysql -u root < CreateAgendaE.sql
mysql -u root < ValuesAgendaE.sql
unde scriptul CreateAgendaE.sql este
1 create database AgendaEMail ;2 use AgendaEMail ;
4 create table adrese (5 id int primary key auto increment not null ,6 nume char (20) not null ,7 emai l char (30) not null8 ) ;
iar scriptul de populare cu date (ValuesAgendaE.sql) este
1 use AgendaEMail ;2 insert adrese values (1 , ”aaa” , ”aaa@yahoo . com” ) ;3 insert adrese values (2 , ”bbb” , ”bbb@gmail . com” ) ;4 insert adrese values (3 , ” ccc ” , ” ccc@unitbv . ro ” ) ;5 insert adrese values (1 , ”aaa” , ”xyz@unitbv . ro ” ) ;
4. Serverul mysql se opreste prin
set MYSQL_HOME=d:\mysql-*-win32
set PATH=%MYSQL_HOME%\bin;%PATH%
mysqladmin -u root shutdown
B.3. POSTGRESQL 279
B.3 PostgreSQL
Instalarea produsului. PostgreSQL este distribuit gratuit. Vom folosi o ver-siune fara instalare automata, care se dezarhiveaza ın catalogul ...\pgsql.
Comunicatia cu acest server se face prin portul 5432.Pentru utilizarea ın aplicatii Java trebuie descarcat un conector postgresql-*.*-
*.jdbc4.jar.Utilizarea produsului.
• Crearea bazei de date a SGBD (initpg.bat)
set PG_HOME=. . .\pgsql
%PG_HOME%\bin\initdb -D %PG_HOME%\Data
• Lansarea serverului postgresql (server.bat)
set PG_HOME=. . .\pgsql
%PG_HOME%\bin\pg_ctl -D %PG_HOME%\Data start
Serverul se opreste tastand Ctrl+c.
• Crearea unui utilizator (inituser.bat)
set PG_HOME=d:\pgsql
%PG_HOME%\bin\createuser
In cele ce urmeaza vom presupune ca utilizatorul are numele postgres. Nu-mele utilizatorul postgres este predefinit. Daca se alege alt nume atunci se vaexecuta suplimentar
%PG_HOME%\bin\createdb nume_utilizator
• Exemplul B.3.1
Crearea aceleiasi baze de date AgendaTelefonica se face cu fisierul de comenzi(agendat.bat)
set PG_HOME=d:\pgsql
%PG_HOME%\bin\psql -U postgres -f createdb.sql
%PG_HOME%\bin\psql -U postgres -d AgendaEMail -f createtable.sql
%PG_HOME%\bin\psql -U postgres -d AgendaEMail -f insertvalues.sql
Script-urile sql sunt
createdb.sql
create database "AgendaEMail" owner postgres;
createtable.sql
280 APPENDIX B. UTILIZAREA SGBD IN JAVA
create table adrese(id int4 primary key,
nume varchar(20) not null, email varchar(30) not null);
insertvalues.sql
insert adrese values(1,"aaa","[email protected]");
insert adrese values(2,"bbb","[email protected]");
insert adrese values(3,"ccc","[email protected]");
insert adrese values(1,"aaa","[email protected]");
B.4 HyperSQL
Instalarea produsului. Instalarea consta din dezarhivarea fisierului descarcatıntr-un catalog pe care-l notam HSQL HOME. HypereSQL se distribuie gratuit.
Comunicatia cu acest serverul se face prin portul 9001.
Conectorul Java este continut ın distributia produsului si este fisierul hsqldb.jar.
Utilizarea produsului.
• Pornirea serverului si crearea bazei de date AgendaTelefonica
set HSQL_HOME=. . .\hsqldb
set JAVA_HOME=. . .
java -cp %HSQL_HOME%/lib/hsqldb.jar org.hsqldb.server.Server
--database.0 file:AgendaEMail --dbname.0 AgendaEMail
• Crearea tabelei telef si inserarea valorilor initiale
set HSQL_HOME=. . .\hsqldb
set JAVA_HOME=. . .
java -cp %HSQL_HOME%/lib/sqltool.jar org.hsqldb.cmdline.SqlTool
--inlineRc URL=jdbc:hsqldb:hsql://localhost/AgendaEMail,
USER=SA,password= CreateTable.sql
java -cp %HSQL_HOME%/lib/sqltool.jar org.hsqldb.cmdline.SqlTool
--inlineRc URL=jdbc:hsqldb:hsql://localhost/AgendaEMail,
USER=SA,password= InsertValues.sql
unde script-urile sql sunt
CreateTable.sql
\c true
DROP TABLE adrese;
\c false
\p Creating Table adrese
create table adrese(
id integer primary key not null,
nume varchar(20) not null,
email varchar(30) not null
);
B.5. ORACLE XE 10G 281
InsertValues.sql
\p Interting values into telef
insert INTO adrese ("ID","NUME","EMAIL") values(1,’aaa’,’[email protected]’);
insert INTO adrese ("ID","NUME","EMAIL") values(2,’bbb’,’[email protected]’);
insert INTO adrese ("ID","NUME","EMAIL") values(3,’ccc’,’[email protected]’);
insert INTO adrese ("ID","NUME","EMAIL") values(4,’aaa’,’[email protected]’);
commit;
B.5 Oracle XE 10g
Utilizarea produsului ın linie de comanda:
• Intr-o fereastra DOS se lanseaza sqlplus.
• Start → Programs → Oracle Database 10g Express Edition → Run SQL Com-mand Line. In fereastra DOS se lanseaza connect.
Ca user : system putem schimba portul HTTP din 8080 ın 9090(de exemplu),prin
exec dbms_xdb.sethttpport(9090)
Exemplul B.5.1
Baza de date AgendaEMail se creaza executand
1. @CreateAgendaE.sql
unde fisierul CreateAgendaE.sql este
1 create table adrese (2 id int primary key ,3 nume varchar2 ( 20 ) ,4 emai l varchar2 (30)5 ) ;
si ıncarcarea cu date
2. @ValuesAgendaE.sql
cu fisierul ValuesAgendaE.sql
1 insert into adrese values (1 , ’ aaa ’ , ’ aaa@unitbv . ro ’ ) ;2 insert into adrese values (2 , ’ bbb ’ , ’ bbb@yahoo . com ’ ) ;3 insert into adrese values (3 , ’ ccc ’ , ’ ccc@gmail . com ’ ) ;4 insert into adrese values (4 , ’ aaa ’ , ’ xyz@yahoo . com ’ ) ;
282 APPENDIX B. UTILIZAREA SGBD IN JAVA
B.6 Sablonul de utilizare a unei baze de date ıntr-unprogram Java
Interactiunea cu baze de date relationale implica:
1. Stabilirea corespondentei dintre date aflate ın obiecte si atribute / tabele (ob-ject to relational database mapping).
2. Apelarea actiunilor CRUD (Create, Read, Update, Delete).
Pentru realizarea acestor activitati sunt cunoscute mai multe modele:
• Data Access Object DAO
• Java Data Object JDO
Limbajul SQL (Structured Query Language) este dependent de SGBD utilizat.Dezvoltarea modelelor de interactiune dintre un program Java cu o baza de datedintr-un SGBD s-a nascut din dorinta de a asigura independenta stratului Java deSGBD. Solutia gasita consta ın introducerea unui strat suplimentar, ıntre Java siSGBD care asigura corespondenta ıntre obiectele Java cu tabelele unei baze de datesi permite o configurare simpla la schimbarea SGBD.
Materializarea acestor idei (Object Relational Mapping - ORM) se afla ın
• interfata de programare (API) Java Persistence API (JPA);
• produsul Hibernate.
Pentru ınceput vom face abstractie de modelele mentionate anterior si vom trataın modul cel mai simplu realizarea unei aplicatii care interactioneaza cu o baza dedate gestionata de un SGBD.
Pentru a avea acces la o baza de date trebuie stabilita o conexiune la acea bazade date. In acest sens este necesar cunoasterea:
• driver-ului de acces la sistemul de gestiune a bazei de date (SGBD) (StringjdbcDriver)
Tip SGBD Driver Fisieruldriver-ului
access sun.jdbc.odbc.JdbcOdbcDrivermysql com.mysql.jdbc.Driver mysql-connector-java-*.*.*-bin.jar
(www.mysql.com)derby org.apache.derby.jdbc.ClientDriver derbyclient.jarjavadb
(distributia derby)postgresql org.postgresql.Driver postgresql-*.*-*.jdbc4.jarhypeqsql org.hsqldb.jdbcDriver hsqldb.jaroraclexe oracle.jdbc.driver.OracleDriver ojdbc14.jar
Daca ıntr-un servlet se realizeaza o conexiune la o baza de date atunci fisieruldriver-ului trebuie copiat ın catalogul lib al aplicatiei.
B.6. SABLONUL DE UTILIZARE A UNEI BAZE DE DATE 283
• adresa URL a bazei de date (String URLBazaDate), sub forma
Tip SGBD Referinta Baza de Date
mysql jdbc:mysql://host:3306/numeBazaDatederby / javadb jdbc:derby://host:1527/numeBazaDate
postgresql jdbc:postgresql://host:5432/numeBazaDatehypersql jdbc:hsqldb:hsql://host/numeBazaDate
oracle jdbc:oracle:thin:@host:1521:XE
Sablonul de prelucrare este
String jdbcDriver=. . .
String URLBazaDate=. . .
Connection con=null;
try{
Class.forName(jdbcDriver).newInstance();
con=DriverManager.getConnection(URLBazaDate);
...
}
catch(ClassNotFoundException e){. . .}
catch(SQLException e){. . .}
Odata conexiunea cu baza de date stabilita se genereaza un obiect de tip Statement
prin intermediul caruia se executa interogarea SQL.
Statement instructiune=con.createStatement();
String sql=. . . //fraza select;
Rezultatele interogarii bazei de date se obtine prin
try{
ResultSet rs=instructiune.executeQuery(sql);
while(rs.next()){
prelucrarea rezultatului
}
}
catch(SQLException e){...}
Exemplul B.6.1
O interogare simpla a bazei de date AgendaEMail se realizeaza cu programul
1 import java . i o . ∗ ;2 import java . s q l . ∗ ;3 import java . net . ∗ ;
284 APPENDIX B. UTILIZAREA SGBD IN JAVA
4 import java . u t i l . ∗ ;
6 public class AgendaE {7 Statement i n s t r u c t i u n e=null ;
9 public void i n i t ( S t r ing username , S t r ing password ){10 // SGBD Derby11 St r ing jdbcDr iver=” org . apache . derby . jdbc . C l i en tDr ive r ” ;12 St r ing URLBazaDate=” jdbc : derby :// l o c a l h o s t :1527/ AgendaEMail” ;
14 // SGBD mysql15 /∗16 St r ing jdbcDr iver=”com. mysql . j dbc . Driver ” ;17 St r ing URLBazaDate=”jdbc : mysql :// l o c a l h o s t :3306/AgendaEMail? user=root ” ;18 ∗/
20 // PostgreSQL21 /∗22 St r ing jdbcDr iver=”org . p o s t g r e s q l . Driver ” ;23 St r ing URLBazaDate=”jdbc : p o s t g r e s q l :// l o c a l h o s t :5432/AgendaEMail ” ;24 // S t r ing username=pos t g r e s ” ;25 // S t r ing password=”;26 ∗/
28 // HyperSQL29 /∗30 St r ing jdbcDr iver=”org . h s q l d b . jdbcDr iver ” ;31 St r ing URLBazaDate=”jdbc : h s q l d b : h s q l :// l o c a l h o s t /AgendaEMail ” ;32 // S t r ing username=”SA”;33 // S t r ing password=””;34 ∗/
36 // Oracle 10g Express Edi t ion37 /∗38 St r ing jdbcDr iver=”orac l e . j dbc . d r i v e r . OracleDriver ” ;39 St r ing URLBazaDate=”jdbc : o rac l e : t h in : @ loca lhos t : 1521 :XE”;40 ∗/
42 Connection con=null ;43 try{44 Class . forName ( jdbcDr iver ) . newInstance ( ) ;45 i f ( username!=null )46 con = DriverManager . getConnect ion (URLBazaDate , username , password ) ;47 else48 con = DriverManager . getConnect ion (URLBazaDate ) ;49 i n s t r u c t i u n e=con . createStatement ( ) ;50 }51 catch ( ClassNotFoundException e ){52 System . out . p r i n t l n ( ” Driver i n e x i s t e n t JDBC: ”+jdbcDr iver ) ;53 }54 catch ( SQLException e ){55 System . out . p r i n t l n ( ”Baza de date i n e x i s t e n t a ”+URLBazaDate ) ;56 }57 catch ( Exception e ){58 System . out . p r i n t l n ( ” Eroare : ”+e . getMessage ( ) ) ;59 }60 }
62 public stat ic void main ( St r ing [ ] a rgs ) {
B.6. SABLONUL DE UTILIZARE A UNEI BAZE DE DATE 285
63 AgendaE agenda=new AgendaE ( ) ;64 i f ( args . length >0)65 agenda . i n i t ( args [ 0 ] , a rgs [ 1 ] ) ;66 else67 agenda . i n i t (null , null ) ;68 Scanner scanner=new Scanner ( System . in ) ;69 int pre l , no ;70 St r ing ch=”Y” ,nume=”” , emai l=”” , s q l=”” ;71 Resu l tSet r s=null ;72 try{73 while ( ch . s tartsWith ( ”Y” ) ){74 do{75 System . out . p r i n t l n ( ” Continue ? (Y/N) ” ) ;76 ch=scanner . next ( ) . toUpperCase ( ) ;77 }78 while ( ( ! ch . s tartsWith ( ”Y”))&&(! ch . s tartsWith ( ”N” ) ) ) ;79 i f ( ch . s tartsWith ( ”Y” ) ){80 System . out . p r i n t l n ( ”Natura i n t e r o g a r i i ?” ) ;81 System . out . p r i n t l n ( ” (Dupa nume : 1 , Dupa emai l : 2 ) ” ) ;82 do{83 p r e l =0;84 try{85 p r e l=scanner . next Int ( ) ;86 }87 catch ( InputMismatchException e ){}88 }89 while ( ( pre l <1)&&(pre l >2)) ;90 switch ( p r e l ){91 case 1 :92 System . out . p r i n t l n ( ”Numele” ) ;93 nume=’ \ ’ ’+scanner . next ( ) . tr im ()+ ’ \ ’ ’ ;94 s q l=” s e l e c t ∗ from adrese where nume=”+nume ;95 r s=agenda . i n s t r u c t i u n e . executeQuery ( s q l ) ;96 i f ( r s !=null ){97 System . out . p r i n t l n ( ”S−au g a s i t a d r e s e l e de e−mail : ” ) ;98 while ( r s . next ( ) ){99 System . out . p r i n t l n ( r s . g e t S t r i n g ( ” emai l ” ) ) ;
100 }101 }102 else {103 System . out . p r i n t l n ( ”Fara adresa de e−mail ! ” ) ;104 }105 break ;106 case 2 :107 System . out . p r i n t l n ( ”Email” ) ;108 emai l=’ \ ’ ’+scanner . next ( ) . tr im ()+ ’ \ ’ ’ ;109 s q l=” s e l e c t ∗ from adrese where emai l=”+emai l ;110 r s=agenda . i n s t r u c t i u n e . executeQuery ( s q l ) ;111 i f ( r s !=null ){112 System . out . p r i n t l n ( ”S−a g a s i t numele” +113 ” : ” ) ;114 while ( r s . next ( ) ){115 System . out . p r i n t l n ( r s . g e t S t r i n g ( ”nume” ) ) ;116 }117 }118 else {119 System . out . p r i n t l n ( ”Numar i n e x i s t e n t ! ” ) ;120 }121 break ;
286 APPENDIX B. UTILIZAREA SGBD IN JAVA
122 default : System . out . p r i n t l n ( ”Comanda eronata ” ) ;123 }124 }125 }126 }127 catch ( Exception e ){128 System . out . p r i n t l n ( ” Cl i entExcept ion : ”+e . getMessage ( ) ) ;129 }130 }131 }
Fraza select si interogarea se mai putea programa prin
String sql="select * from adrese where nume =?";
PreparedStatement prepStmt=con.prepareStatement(sql);
prepStmt.setString(1,nume);
RezultSet rs=prepStmt.executeQuery();
. . .
prepStmt.close();
In acest caz, valoarea variabilei nume este fara apostroafe.
Compilarea si executia programului necesita declararea ın variabila classpath
a fisierelor
• Varianta Derby
derby.jar, derbytools.jar, derbyclient.jar, derbynet.jar din cata-logul %DERBY INSTALL%\lib.
• Varianta mysql
%MYSQL CONNECTOR JAVA HOME%\mysql-connector-java-*.*.*-bin.jar
Executia programului presupune serverul SGBD activ.
B.7 Modelul DAO
Prezentarea va exemplifica modelul DAO ın cazul bazei de date amintite anterior(AgendaEMail): o agenda de adrese e-mail alcatuita dintr-un singur tabel adrese,cu atributele
id: int, cheia primara
nume: String
email: String
Conexiunea cu baza de date se separa de activitatile care se ıntreprind asuprabazei de date. Pentru stabilirea conexiunii este nevoie doar de adresa URI a bazeide date. Alegem solutia simpla:
B.7. MODELUL DAO 287
1 package agendae . dao ;2 import java . s q l . Connection ;3 import java . s q l . SQLException ;4 import java . s q l . DriverManager ;5 public class DAOBase{6 public Connection getConnect ion ( ) throws Exception {7 St r ing URLDB=” jdbc : derby :// l o c a l h o s t :1527/ AgendaEMail” ;8 Connection connect ion = null ;9 try {
10 connect ion=DriverManager . getConnect ion (URLDB) ;11 }12 catch ( SQLException e ) {13 throw new Exception ( ” Connection Error : ”+e . getMessage ( ) ) ;14 }15 return connect ion ;16 }17 }
Fiecarui tabel al bazei de date i se asociaza:
• O componenta Java (bean) a carei instanta retine (total sau partial) datelecorespunzatoare unei linii a tabelei.
1 package agendae . dao ;2 import java . i o . S e r i a l i z a b l e ;
4 public class Adrese implements S e r i a l i z a b l e {5 private int id ;6 private St r ing nume ;7 private St r ing emai l ;
9 public Adrese ( ){}
11 public Adrese ( int id , S t r ing nume , S t r ing emai l ) {12 this . id = id ;13 this . nume = nume ;14 this . emai l = emai l ;15 }16 public St r ing getNume ( ) {17 return nume ;18 }19 public void setNume ( St r ing nume) {20 this . nume = nume ;21 }22 public St r ing getEmail ( ) {23 return emai l ;24 }25 public void setEmai l ( S t r ing emai l ) {26 this . emai l = emai l ;27 }28 public int get Id ( ) {29 return id ;30 }31 public void s e t I d ( int id ) {32 this . id = id ;33 }34 }
288 APPENDIX B. UTILIZAREA SGBD IN JAVA
• O interfata Java cu actiunile care se ıntreprind asupra tabelei respective.Uzual, daca tabela are numele xyz atunci numele interfetei va fi XyzDAO.java.Prentru cazul exemplificat consideram interfata
1 package agendae . dao ;2 import java . u t i l . L i s t ;
4 public interface AdreseDAO {5 public void createAdrese ( Adrese i n r eg ) throws Exception ;6 public void updateAdrese ( Adrese i n r eg ) throws Exception ;7 public Adrese readAdrese ( int i n r e g I d ) throws Exception ;8 public void de l e t eAdrese ( int i n r e g I d ) throws Exception ;9 public List<Adrese> searchAdrese ( S e a r c h C r i t e r i a s e a r c h C r i t e r i a )
10 throws Exception ;11 }
Cautarea unei ınregistrari se poate face dupa nume sau dupa adresa de email.Unui nume ıi pot corespunde mai multe adrese de email, iar dintr-o adresa nuputem sti cui ıi apartine. Clasa SearchCriteria este o componenta prin care sefixeaza criteriul de catare.
1 package agendae . dao ;2 import java . i o . S e r i a l i z a b l e ;
4 public class S e a r c h C r i t e r i a implements S e r i a l i z a b l e {5 private St r ing nume=null ;6 private St r ing emai l=null ;
8 public St r ing getNume ( ) {9 return nume ;
10 }11 public void setNume ( St r ing nume) {12 this . nume = nume ;13 }14 public St r ing getEmail ( ) {15 return emai l ;16 }17 public void setEmai l ( S t r ing emai l ) {18 this . emai l = emai l ;19 }20 }
Daca nume=null atunci se cere lista numelor care corespund la o adresa email,iar daca email=null atunci se cere lista adreselor de email corespunzatoareunui nume.
Deoarece fiecare SGBD are propriul dialect SQL clasa ce implementeaza interfataDAO este specifica SGBD-ului. Utilizand Derby / JavaDB codul implementariiAdreseDAODerbyImpl este
1 package agendae . dao ;2 import java . s q l . SQLException ;3 import java . s q l . Connection ;4 import java . s q l . PreparedStatement ;5 import java . s q l . Resu l tSet ;6 import java . s q l . Statement ;
B.7. MODELUL DAO 289
7 import java . u t i l . ArrayList ;8 import java . u t i l . L i s t ;
10 public class AdreseDAODerbyImpl extends DAOBase implements AdreseDAO {11 private stat ic f ina l St r ing CREATE Adrese SQL =12 ”INSERT INTO adrese (nume , emai l ) VALUES (? , ?) ” ;13 public void createAdrese ( Adrese i n r eg )throws Exception {14 Connection connect ion = null ;15 PreparedStatement pStatement = null ;16 try {17 connect ion = getConnect ion ( ) ;18 pStatement = connect ion . prepareStatement (CREATE Adrese SQL ) ;19 pStatement . s e t S t r i n g (1 , i n r eg . getNume ( ) ) ;20 pStatement . s e t S t r i n g (2 , i n r eg . getEmail ( ) ) ;21 pStatement . executeUpdate ( ) ;22 pStatement . c l o s e ( ) ;23 }24 catch ( Exception e ) {25 throw new Exception ( ”AdreseDAODerbyImpl : ”+e . getMessage ( ) ) ;26 }27 f ina l ly {28 try{29 connect ion . c l o s e ( ) ;30 }31 catch ( SQLException ex ) {}32 }33 }
35 private stat ic f ina l St r ing UPDATE Adrese SQL =36 ”UPDATE adrese SET nume=?, emai l=? WHERE id = ?” ;37 public void updateAdrese ( Adrese i n r eg ) throws Exception {38 Connection connect ion = null ;39 PreparedStatement pStatement = null ;40 try{41 connect ion = getConnect ion ( ) ;42 pStatement = connect ion . prepareStatement (UPDATE Adrese SQL ) ;43 pStatement . s e t S t r i n g (1 , i n r eg . getNume ( ) ) ;44 pStatement . s e t S t r i n g (2 , i n r eg . getEmail ( ) ) ;45 pStatement . s e t I n t (3 , i n r e g . ge t Id ( ) ) ;46 pStatement . executeUpdate ( ) ;47 pStatement . c l o s e ( ) ;48 }49 catch ( SQLException e ) {50 throw new Exception ( ”AdreseDAODerbyImpl : ”+e . getMessage ( ) ) ;51 }52 f ina l ly {53 try {54 connect ion . c l o s e ( ) ;55 }56 catch ( SQLException ex ) {}57 }58 }
60 private stat ic f ina l St r ing READ Adrese SQL =61 ”SELECT nume , emai l FROM adrese WHERE id = ?” ;62 public Adrese readAdrese ( int i n r e g I d ) throws Exception {63 Connection connect ion = null ;64 PreparedStatement pStatement = null ;65 Resu l tSet r s = null ;
290 APPENDIX B. UTILIZAREA SGBD IN JAVA
66 Adrese i n r e g = new Adrese ( ) ;67 try {68 connect ion = getConnect ion ( ) ;69 pStatement = connect ion . prepareStatement (READ Adrese SQL ) ;70 pStatement . s e t I n t (1 , i n r e g I d ) ;71 r s = pStatement . executeQuery ( ) ;72 i f ( r s . next ( ) ) {73 i n r e g . setNume ( r s . g e t S t r i n g ( ”nume” ) ) ;74 i n r e g . setEmai l ( r s . g e t S t r i n g ( ” emai l ” ) ) ;75 i n r e g . s e t I d ( i n r e g I d ) ;76 }77 r s . c l o s e ( ) ;78 pStatement . c l o s e ( ) ;79 }80 catch ( SQLException e ) {81 throw new Exception ( ”AdreseDAODerbyImpl : ”+e . getMessage ( ) ) ;82 }83 f ina l ly {84 try {85 connect ion . c l o s e ( ) ;86 } catch ( SQLException ex ) {}87 }88 return i n r e g ;89 }
91 private stat ic f ina l St r ing DELETE Adrese SQL =92 ”DELETE FROM adrese WHERE id = ?” ;93 public void de l e t eAdre se ( int i n r e g I d ) throws Exception {94 Connection connect ion = null ;95 PreparedStatement pStatement = null ;96 try {97 connect ion = getConnect ion ( ) ;98 pStatement = connect ion . prepareStatement (DELETE Adrese SQL ) ;99 pStatement . s e t I n t (1 , i n r e g I d ) ;
100 pStatement . executeUpdate ( ) ;101 pStatement . c l o s e ( ) ;102 }103 catch ( SQLException e ) {104 throw new Exception ( ”AdreseDAODerbyImpl : ”+e . getMessage ( ) ) ;105 }106 f ina l ly {107 try {108 connect ion . c l o s e ( ) ;109 }110 catch ( SQLException ex ) {}111 }112 }
114 private stat ic f ina l St r ing SEARCH Adrese SQL =115 ”SELECT id , nume , emai l FROM adrese WHERE ” ;116 public List<Adrese> searchAdrese ( S e a r c h C r i t e r i a s e a r c h C r i t e r i a )117 throws Exception {118 List<Adrese> l i s t = new ArrayList<Adrese >() ;119 Connection connect ion = null ;120 Statement statement = null ;121 Resu l tSet r e s u l t S e t = null ;122 St r ing searchSQL ;123 St r ing nume=s e a r c h C r i t e r i a . getNume ( ) ;124 St r ing emai l=s e a r c h C r i t e r i a . getEmail ( ) ;
B.7. MODELUL DAO 291
125 //System . out . p r i n t l n (” Cr i t e r i a : ”+nume+” ”+email ) ;126 i f (nume==null ){127 searchSQL=SEARCH Adrese SQL+” emai l=”+’ \ ’ ’+emai l+’ \ ’ ’ ;128 }129 else {130 searchSQL=SEARCH Adrese SQL+”nume=”+’ \ ’ ’+nume+’ \ ’ ’ ;131 }132 //System . out . p r i n t l n ( searchSQL ) ;133 try {134 connect ion = getConnect ion ( ) ;135 statement = connect ion . createStatement ( ) ;136 r e s u l t S e t = statement . executeQuery ( searchSQL ) ;137 while ( r e s u l t S e t . next ( ) ) {138 Adrese i n r e g = new Adrese ( ) ;139 i n r e g . s e t I d ( r e s u l t S e t . g e t In t ( ” id ” ) ) ;140 i n r e g . setNume ( r e s u l t S e t . g e t S t r i n g ( ”nume” ) ) ;141 i n r e g . setEmai l ( r e s u l t S e t . g e t S t r i n g ( ” emai l ” ) ) ;142 l i s t . add ( i n r e g ) ;143 }144 r e s u l t S e t . c l o s e ( ) ;145 statement . c l o s e ( ) ;146 }147 catch ( SQLException e ) {148 throw new Exception ( ”AdreseDAODerbyImpl : ”+e . getMessage ( ) ) ;149 }150 f ina l ly {151 try {152 connect ion . c l o s e ( ) ;153 }154 catch ( SQLException ex ) {}155 }156 return l i s t ;157 }158 }
Apelarea unei atiuni CRUD necesita o instanta a clasei AdreseDAODerbyImpl.Crearea acestei instante va fi facuta utilizand sablonul singleton, prin clasa
1 package agendae . dao ;
3 public class DAOFactory {4 private stat ic DAOFactory in s t ance ;5 private stat ic AdreseDAODerbyImpl adreseDAODerbyImpl=null ;6 stat ic {7 i n s t ance = new DAOFactory ( ) ;8 }9 private DAOFactory ( ){
10 adreseDAODerbyImpl=new AdreseDAODerbyImpl ( ) ;11 }12 public stat ic DAOFactory ge t In s tance ( ) {13 return i n s t ance ;14 }
16 public AdreseDAO getAdreseDAO ( ) {17 return adreseDAODerbyImpl ;18 }19 }
Un client fara interfataa grafica este
292 APPENDIX B. UTILIZAREA SGBD IN JAVA
1 package agendae ;2 import java . u t i l . ∗ ;3 import agendae . dao . ∗ ;
5 public class AgendaEClient{6 public stat ic void main ( St r ing [ ] a rgs ) {7 AdreseDAO dao=DAOFactory . g e t In s tance ( ) . getAdreseDAO ( ) ;8 Adrese e n t i t y=null ;9 List<Adrese> l i s t=null ;
10 I t e r a t o r <Adrese> i t e r a t o r=null ;11 S e a r c h C r i t e r i a sc=null ;12 St r ing ch=”Y” ;13 int p r e l ;14 Scanner scanner=new Scanner ( System . in ) ;15 while ( ch . s tartsWith ( ”Y” ) ){16 do{17 System . out . p r i n t l n ( ” Continue ? (Y/N) ” ) ;18 ch=scanner . next ( ) . toUpperCase ( ) ;19 }20 while ( ( ! ch . s tartsWith ( ”Y”))&&(! ch . s tartsWith ( ”N” ) ) ) ;21 i f ( ch . s tartsWith ( ”Y” ) ){22 System . out . p r i n t l n ( ”Natura p r e l u c r a r i i ?” ) ;23 System . out . p r i n t l n ( ”Adaugare ( Create ) : 1 ” ) ;24 System . out . p r i n t l n ( ” S t e r g e r e ( De lete ) : 2 ” ) ;25 System . out . p r i n t l n ( ” Actua l i z a r e ( Update ) : 3 ” ) ;26 System . out . p r i n t l n ( ”Cautare dupa c h e i e (Read ) : 4 ” ) ;27 System . out . p r i n t l n ( ”Cautare (Read ) : 5 ” ) ;28 p r e l=scanner . next Int ( ) ;29 St r ing nume , emai l ;30 int id ;31 switch ( p r e l ){32 case 1 :33 System . out . p r i n t l n ( ”ADAUGARE” ) ;34 System . out . p r i n t l n ( ”Numele : ” ) ;35 nume=scanner . next ( ) . tr im ( ) ;36 System . out . p r i n t l n ( ”Adresa e−mail : ” ) ;37 emai l=scanner . next ( ) . tr im ( ) ;38 e n t i t y=new Adrese ( ) ;39 e n t i t y . setNume (nume ) ;40 e n t i t y . setEmai l ( emai l ) ;41 try{42 dao . c reateAdrese ( e n t i t y ) ;43 System . out . p r i n t l n ( ” Operat ia a f o s t executata cu succe s ! ” ) ;44 }45 catch ( Exception e ){46 System . out . p r i n t l n ( ” Except ie : ”+e . getMessage ( ) ) ;47 }48 break ;49 case 2 :50 System . out . p r i n t l n ( ”STERGERE” ) ;51 System . out . p r i n t l n ( ” Id : ” ) ;52 id=scanner . next Int ( ) ;53 try{54 dao . de l e t eAdrese ( id ) ;55 System . out . p r i n t l n ( ” Operat ia a f o s t executata cu succe s ! ” ) ;56 }57 catch ( Exception e ){58 System . out . p r i n t l n ( ” Except ie : ”+e . getMessage ( ) ) ;59 }
B.7. MODELUL DAO 293
60 break ;61 case 3 :62 System . out . p r i n t l n ( ”ACTUALIZARE” ) ;63 System . out . p r i n t l n ( ”Numele : ” ) ;64 nume=scanner . next ( ) . tr im ( ) ;65 System . out . p r i n t l n ( ”Adresa e−mail : ” ) ;66 emai l=scanner . next ( ) . tr im ( ) ;67 System . out . p r i n t l n ( ”Cheia i n r e g i s t r a r i i ( Id ) : ” ) ;68 id=scanner . next Int ( ) ;69 e n t i t y=new Adrese ( ) ;70 e n t i t y . setNume (nume ) ;71 e n t i t y . setEmai l ( emai l ) ;72 e n t i t y . s e t I d ( id ) ;73 try{74 dao . updateAdrese ( e n t i t y ) ;75 System . out . p r i n t l n ( ” Operat ia a f o s t executata cu succe s ! ” ) ;76 }77 catch ( Exception e ){78 System . out . p r i n t l n ( ” Except ie : ”+e . getMessage ( ) ) ;79 }80 break ;81 case 4 :82 System . out . p r i n t l n ( ”CAUTARE DUPA CHEIE” ) ;83 System . out . p r i n t l n ( ” Id : ” ) ;84 id=scanner . next Int ( ) ;85 try{86 e n t i t y=dao . readAdrese ( id ) ;87 System . out . p r i n t l n ( ”Nume : ”+e n t i t y . getNume ( ) ) ;88 System . out . p r i n t l n ( ”Email : ”+e n t i t y . getEmail ( ) ) ;89 }90 catch ( Exception e ){91 System . out . p r i n t l n ( ” Except ie : ”+e . getMessage ( ) ) ;92 }93 break ;94 case 5 :95 System . out . p r i n t l n ( ” C r i t e r i u l de cautare : ” ) ;96 System . out . p r i n t l n ( ”Dupa nume : 1” ) ;97 System . out . p r i n t l n ( ”Dupa emai l : 2” ) ;98 int c r i t e r i u=scanner . next Int ( ) ;99 switch ( c r i t e r i u ){
100 case 1 :101 System . out . p r i n t l n ( ”Numele : ” ) ;102 nume=scanner . next ( ) . tr im ( ) ;103 sc=new S e a r c h C r i t e r i a ( ) ;104 sc . setNume (nume ) ;105 try{106 l i s t=dao . searchAdrese ( sc ) ;107 i t e r a t o r=l i s t . i t e r a t o r ( ) ;108 while ( i t e r a t o r . hasNext ( ) ){109 Adrese i n r e g =(Adrese ) i t e r a t o r . next ( ) ;110 System . out . p r i n t l n ( i n r eg . ge t Id ()+” : ”+111 i n r e g . getNume()+” : ”+in r e g . getEmail ( ) ) ;112 }113 }114 catch ( Exception e ){115 System . out . p r i n t l n ( ” Except ie : ”+e . getMessage ( ) ) ;116 }117 break ;118 case 2 :
294 APPENDIX B. UTILIZAREA SGBD IN JAVA
119 System . out . p r i n t l n ( ”Adresa e−mail : ” ) ;120 emai l=scanner . next ( ) . tr im ( ) ;121 sc=new S e a r c h C r i t e r i a ( ) ;122 sc . setEmai l ( emai l ) ;123 try{124 l i s t=dao . searchAdrese ( sc ) ;125 i t e r a t o r=l i s t . i t e r a t o r ( ) ;126 while ( i t e r a t o r . hasNext ( ) ){127 Adrese i n r e g =(Adrese ) i t e r a t o r . next ( ) ;128 System . out . p r i n t l n ( i n r eg . ge t Id ()+” : ”+129 i n r e g . getNume()+” : ”+in r e g . getEmail ( ) ) ;130 }131 }132 catch ( Exception e ){133 System . out . p r i n t l n ( ” Except ie : ”+e . getMessage ( ) ) ;134 }135 break ;136 default :137 System . out . p r i n t l n ( ” C r i t e r i u de cautare eronat ” ) ;138 }139 break ;140 default : System . out . p r i n t l n ( ”Comanda eronata ” ) ;141 }142 }143 else144 System . e x i t ( 0 ) ;145 }146 }147 }
B.8 Java Persistence API - JPA
Interfata JPA este standardizarea accesului din Java la un SGBD relational. JPAeste un strat care se interpune ıntre programul Java si SGBD. JPA este dezvoltatpe modelul dat modelul pachetului javax.persistence initiat de Oracle-Sun Mi-croSystems, din Java Enterprise Edition (JEE), dar pentru care exista mai multeimplemaentari. De asemenea, exista mai multe implementari a interfetei JPA.
O alternativa la JPA ıl reprezinta produsul Hibernate.JPA contine:
• Persistence: Clasa javax.persistence.Persistence contine metode staticepentru obtinerea unei instante a clasei EntityManagerFactory, ıntr-o manieraindependenta de producatorul JPA.
• EntityManagerFactory : Clasa javax.persistence.EntityManagerFactory
este producatorul obiectelor EntityManager.
• EntityManager : javax.persistence.EntityManager este actorul JPA prin-cipal ıntr-o aplicatie. Un obiect EntityManager mijloceste ıntretinerea si in-terogarea unei baze de date. Fiecarui obiect de tip EntityManager i se asociazaun obiect de tip javax.persistence.EntityTransaction.
B.8. JAVA PERSISTENCE API - JPA 295
• Entity : Obiectele Entity corespund ınregistrarilor ın tabelele bazei de date.
• EntityTransaction: asigura integritatea bazei de date. Operatiile care privescpersistenta datelor sunt grupate ın unitati de lucru care sunt executate cusucces sau deloc.
• Query : Interfata javax.persistence.Query este specifica implementarii. Prinobiecte de tip Query se asigura accesul la baza de date. Portivit standardu-lui JPA este suportat atat limbajul Structured Query Language (SQL) cat siJava Persistence Query Language (JPQL). Un obiect Query este instantiatprin obiecte EntityManager.
B.8.1 apache-openjpa
Asa cum sugereaza numele produsului, openjpa este implementarea oferita deapache.
Instalarea revine la dezarhivarea fisierului descarcat.Utilizarea. Compilarea si executia unei aplicatii o vom face prin intermediul
lui apache-ant. Construim structura de cataloage si fisiere:
|--> catalogul_aplicatiei
|--> META-INF
| | persistence.xml
| build.xml
Fisierul persistence.xml specifica unitatile de persistenta. Fiecare unitate depersistenta corespunde unui tabel al bazei de date si i se asociaza o clasa Entity,
de fapt o componenta Java. Clasa si tabelul au acelasi nume. Doar tabelele carorali s-a declarat o unitate de persistenta pot fi accesate prin apache-openjpa.
Principial fisierul persistence.xml este
1 <?xml version=” 1 .0 ” encoding=”UTF−8”?>2 <p e r s i s t e n c e xmlns=” ht tp : // java . sun . com/xml/ns/ p e r s i s t e n c e ”3 xmlns :x s i=” h t t p : //www. w3 . org /2001/XMLSchema−i n s t ance ”4 version=” 1 .0 ”>
6 < !−−7 We need to enumerate each p e r s i s t e n t c l a s s f i r s t in the p e r s i s t en c e .xml8 See: h t t p : // i s s u e s . apache . org/ j i r a /browse/OPENJPA−789 −−>
10 <p e r s i s t e n c e−uni t name=”none” t ransac t i on−type=”RESOURCE LOCAL”>11 <c l a s s>Ent i ty c la s s name</ c l a s s>12 </ p e r s i s t e n c e−uni t>
14 < !−−15 A per s i s t en c e un i t i s a s e t o f l i s t e d p e r s i s t e n t e n t i t i e s as we l l16 the con f i gu ra t i on o f an EntityManagerFactory . We con f i gure each17 example in a separa te pe r s i s t ence−uni t .18 −−>19 <p e r s i s t e n c e−uni t name=” Per s i s t ence un i t name ”
296 APPENDIX B. UTILIZAREA SGBD IN JAVA
20 t ransac t i on−type=”RESOURCE LOCAL”>21 < !−−22 The default prov ider can be OpenJPA, or some other product .23 This element i s op t i ona l i f OpenJPA i s the only JPA prov ider24 in the current c l a s s l o a d i n g environment , but can be s p e c i f i e d25 in cases where there are mu l t i p l e JPA implementat ions a v a i l a b l e .26 −−>27 < !−−28 <prov ide r>29 org . apache . openjpa . p e r s i s t en c e . Pers i s t enceProv ider Imp l30 </ prov ide r>31 −−>
33 < !−− We must enumerate each en t i t y in the p e r s i s t en c e un i t −−>34 <c l a s s>appagenda . Te l e f</ c l a s s>
36 <p r o p e r t i e s>37 < !−−38 We can con f i gure the default OpenJPA prope r t i e s here . They39 happen to be commented out here s ince the prov ided examples40 a l l s p e c i f y the va lue s v ia System prop e r t i e s .41 −−>
43 < !−−44 <property name=” openjpa . ConnectionURL”45 value=” jdbc :derby :open jpa−database ; c r e a t e=true ”/>46 <property name=” openjpa . ConnectionDriverName”47 value=” org . apache . derby . jdbc . EmbeddedDriver”/>48 <property name=” openjpa . ConnectionUserName”49 value=” user ”/>50 <property name=” openjpa . ConnectionPassword ”51 value=” s e c r e t ”/>52 −−>53 </ p r o p e r t i e s>54 </ p e r s i s t e n c e−uni t>55 </ p e r s i s t e n c e>
Atributele ce apar ın comentarii, pot fi specificate si prin proprietati System.
Sablonul de prelucrare este
EntityManagerFactory factory=
Persistence.createEntityManagerFactory("nume_unitate_de_persistenta",
System.getProperties());
EntityManager em=factory.createEntityManager();
em.getTransaction().begin();
String sql=fraza SQL sau JPQL
Query query=em.createQuery(sql);
// introducerea unei inregistrari
em.persist(obiect_Entity)
// actualizarea sau stergerea unei inregistrari
query.executeUpdate();
B.8. JAVA PERSISTENCE API - JPA 297
// interogare bazei de date
List result=query.getResultList();
em.getTransaction().commit();
em.close();
factory.close();
Daca fraza SQL este specifica unui SGBD atunci obiectul de tip Query se instantiazaprin
Query query=em.createNativeQuery(sql,clasa_Entity_utilizata.class);
Exemplul B.8.1 Aplicatie pentru ıntretinerea si interogarea bazei de date Agen-daEMail.
Tabelei adrese a bazei de date ıi corespunde clasa Adrese
1 package agendae . dao ;2 import java . i o . S e r i a l i z a b l e ;3 import javax . p e r s i s t e n c e . ∗ ;
5 @Entity6 public class Adrese implements S e r i a l i z a b l e {7 private int id ;8 private St r ing nume ;9 private St r ing emai l ;
11 public Adrese ( ){}
13 public Adrese ( int id , S t r ing nume , S t r ing emai l ) {14 this . id = id ;15 this . nume = nume ;16 this . emai l = emai l ;17 }
19 public int get Id ( ) {20 return id ;21 }22 public void s e t I d ( int id ) {23 this . id = id ;24 }
26 public St r ing getNume ( ) {27 return nume ;28 }29 public void setNume ( St r ing nume) {30 this . nume = nume ;31 }
33 public St r ing getEmail ( ) {34 return emai l ;35 }36 public void setEmai l ( S t r ing emai l ) {37 this . emai l = emai l ;
298 APPENDIX B. UTILIZAREA SGBD IN JAVA
38 }39 }
Accessarea bazei de date se face prin clasa AdreseDAOImpl. Aceasta clasa im-plementeaza interfata AdreseDAO, data ın sectiunea anterioara.
1 package agendae . dao ;2 import java . u t i l . L i s t ;3 import javax . p e r s i s t e n c e . ∗ ;
5 @SuppressWarnings ( ”unchecked” )6 pub l i c c l a s s AdreseDAOImpl implements AdreseDAO{7 EntityManagerFactory f a c t o r y=n u l l ;8 EntityManager em;
10 pub l i c AdreseDAOImpl ( EntityManagerFactory f a c t o r y ){11 t h i s . f a c t o r y=f a c t o r y ;12 }
14 pub l i c void createAdrese ( Adrese i n r eg ){15 St r ing name=i n r e g . getNume ( ) ;16 St r ing emai l=in r e g . getEmail ( ) ;17 em=f a c t o r y . createEntityManager ( ) ;18 em. getTransact ion ( ) . begin ( ) ;19 St r ing s q l=”INSERT INTO adrese (nume , emai l ) VALUES(\ ’ ”+name+” \ ’ ,\ ’ ”+emai l+” \ ’ ) ” ;20 Query query=em. createNativeQuery ( s q l ) ;21 query . executeUpdate ( ) ;22 em. getTransact ion ( ) . commit ( ) ;23 em. c l o s e ( ) ;24 }
26 pub l i c void updateAdrese ( Adrese i n r e g ){27 St r ing nume=” \ ’ ”+in r e g . getNume()+” \ ’ ” ;28 St r ing emai l=” \ ’ ”+in r e g . getEmail ()+” \ ’ ” ;29 i n t i n r e g I d=i n r eg . ge t Id ( ) ;30 em=f a c t o r y . createEntityManager ( ) ;31 em. getTransact ion ( ) . begin ( ) ;32 St r ing s q l=”UPDATE Adrese e n t i t y SET e n t i t y . nume=”+nume+33 ” , e n t i t y . emai l=”+emai l+” WHERE e n t i t y . id=”+i n r e g I d ;34 Query query=em. createQuery ( s q l ) ;35 query . executeUpdate ( ) ;36 em. getTransact ion ( ) . commit ( ) ;37 em. c l o s e ( ) ;38 }
40 pub l i c Adrese readAdrese ( i n t i n r e g I d ){41 em=f a c t o r y . createEntityManager ( ) ;42 em. getTransact ion ( ) . begin ( ) ;43 St r ing s q l=”SELECT e n t i t y FROM Adrese e n t i t y WHERE e n t i t y . id=”+i n r e g I d ;44 Query query=em. createQuery ( s q l ) ;45 Adrese i n r e g =(Adrese ) query . g e t S i n g l e R e s u l t ( ) ;46 em. getTransact ion ( ) . commit ( ) ;47 em. c l o s e ( ) ;48 r e turn in r e g ;49 }
51 pub l i c void de l e t eAdrese ( i n t i n r e g I d ){52 em=f a c t o r y . createEntityManager ( ) ;53 em. getTransact ion ( ) . begin ( ) ;54 St r ing s q l=”DELETE FROM Adrese e n t i t y WHERE e n t i t y . id=”+i n r e g I d ;
B.8. JAVA PERSISTENCE API - JPA 299
55 Query query=em. createQuery ( s q l ) ;56 query . executeUpdate ( ) ;57 em. getTransact ion ( ) . commit ( ) ;58 em. c l o s e ( ) ;59 }
61 pub l i c L i s t<Adrese> searchAdrese ( S e a r c h C r i t e r i a s e a r c h C r i t e r i a ){62 St r ing nume=s e a r c h C r i t e r i a . getNume ( ) ;63 St r ing emai l=s e a r c h C r i t e r i a . getEmail ( ) ;64 St r ing searchSQL ;65 i f (nume==n u l l ){66 searchSQL=” e n t i t y . emai l =\ ’”+emai l+” \ ’ ” ;67 }68 e l s e {69 searchSQL=” e n t i t y . nume=\ ’”+nume+” \ ’ ” ;70 }71 em=f a c t o r y . createEntityManager ( ) ;72 em. getTransact ion ( ) . begin ( ) ;73 St r ing s q l=”SELECT e n t i t y FROM Adrese e n t i t y WHERE ”+searchSQL ;74 System . out . p r i n t l n ( s q l ) ;75 Query query=em. createQuery ( s q l ) ;76 L i s t<Adrese> l i s t =( L i s t<Adrese>) query . g e t R e s u l t L i s t ( ) ;77 em. getTransact ion ( ) . commit ( ) ;78 em. c l o s e ( ) ;79 r e turn l i s t ;80 }81 }
Programul client este acelasi cu cel utilizat anterior (AgendaEClient). iar clientuleste AgendaTClient
Fisierul persistence.xml pentru exemplul de mai sus este
1 <?xml version=” 1 .0 ” encoding=”UTF−8”?>2 <p e r s i s t e n c e xmlns=” ht tp : // java . sun . com/xml/ns/ p e r s i s t e n c e ”3 xmlns :x s i=” h t t p : //www. w3 . org /2001/XMLSchema−i n s t ance ”4 version=” 1 .0 ”>
6 <p e r s i s t e n c e−uni t name=”none” t ransac t i on−type=”RESOURCE LOCAL”>7 <c l a s s>agendae . dao . Adrese</ c l a s s>8 </ p e r s i s t e n c e−uni t>
10 <p e r s i s t e n c e−uni t name=”agendae” t ransac t i on−type=”RESOURCE LOCAL”>11 <c l a s s>agendae . dao . Adrese</ c l a s s>12 </ p e r s i s t e n c e−uni t>13 </ p e r s i s t e n c e>
Structura desfasurata a aplicatiei este
agendae
|--> dao
| | *.class
| AgendaEClient.class
META-INF
| persistence.xml
Fisierul build.xml pentru procesarea prin ant are codul
1 <?xml version=” 1 .0 ” encoding=”UTF−8”?>2 <p r o j e c t default=”run”>
300 APPENDIX B. UTILIZAREA SGBD IN JAVA
3 <property name=” package ” value=”agendae”/>4 <property name=”dbname” value=”AgendaEMail” />5 <property name=” classname ” value=”AgendaEClient” />6 <property name=” bu i ld . d i r ” va lue=” bu i ld ” />
8 < !−− database connect ion p rop e r t i e s −−>
10 <property name=” dbdr iver ”11 value=” org . apache . derby . jdbc . C l i en tDr ive r ”/>12 <property name=” dburl ”13 value=” j d b c : d e r b y : // l o c a l h o s t : 1 5 2 7 /${dbname}”/>
15 < !−−16 <property name=” dbdr iver ”17 value=”com . mysql . jdbc . Dr iver ”/>18 <property name=” dburl ”19 value=” jdbc :mysq l : // l o c a l h o s t : 3 3 0 6 /AgendaEMail? user=root ”/>20 −−>
22 <property name=” dbuser ” value=””/>23 <property name=” dbpass ” value=””/>
25 <path id=” c l a s s pa t h ” >26 <pathelement path=”${ bu i ld . d i r }”/>27 < f i l e s e t d i r=”${ openjpa }/ l i b ”>28 <i n c l ude name=” ∗ . j a r ”/>29 </ f i l e s e t>30 < f i l e s e t d i r=” l i b ”>31 <i n c l ude name=” ∗ . j a r ”/>32 </ f i l e s e t>33 </path>
35 <path id=” javaagent ”>36 < f i l e s e t d i r=”${ openjpa}”>37 <i n c l ude name=”openjpa −∗. j a r ”/>38 </ f i l e s e t>39 </path>40 <pathconvert property=” javaagent ” r e f i d=” javaagent ”/>
42 <t a r g e t name=” i n i t ”>43 <d e l e t e d i r=” bu i ld ”/>44 <mkdir d i r=”${ bu i ld . d i r }”/>45 </ t a r g e t>
47 <t a r g e t name=” compile ” depends=” i n i t ”>48 <javac 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 sp a t h ”49 d e s t d i r=”${ bu i ld . d i r }”50 inc ludeantrunt ime=” f a l s e ” debug=” yes ” />51 </ t a r g e t>
53 <t a r g e t name=”run” depends=” compile ”>54 <mkdir d i r=”${ bu i ld . d i r }/META−INF”/>55 <copy t o d i r=”${ bu i ld . d i r }/META−INF” f i l e=”META−INF/ p e r s i s t e n c e . xml”/>56 <java classname=”${package } . ${ classname }” c l a s s p a t h r e f=” c l a s s pa th ”57 f o rk=” yes ” f a i l o n e r r o r=” yes ”>58 < !−−59 Spec i f y ing the openjpa ja r as the javaagent argument i s60 necessary in order f o r automatic c l a s s−enhancement to work .61 −−>
B.8. JAVA PERSISTENCE API - JPA 301
62 <jvmarg value=”−j avaagen t : ${ javaagent }”/>
64 < !−−65 Spec i f y the system prop e r t i e s to use when con f i gu r ing66 OpenJPA. Note t ha t t he se w i l l on ly be used becuase in the67 packages , the c a l l to ” P e r s i s t e n c e . createEntityManagerFactory ”68 i s passed ”System . g e t P r o p e r t i e s ( ) ” .69 −−>
71 < !−−72 By default , use the stand−alone Derby database ( prov ided ) .73 This can e a s i l y be changes to use your own database ’ s d r ive r ,74 provided you ensure i t i s a c c e s s i b l e in the c l a s sp a th .75 −−>76 <sysproper ty key=”openjpa . ConnectionDriverName”77 value =”${dbdr iver}”/>78 <sysproper ty key=”openjpa . ConnectionURL” value =”${dburl}”/>79 <!−−80 <sysproper ty key=”openjpa . ConnectionUserName” value =”${dbuser}”/>81 <sysproper ty key=”openjpa . ConnectionPassword ” value =”${dbpass}”/>82 −−>83 <!−−84 Te l l OpenJPA to automat i ca l l y c r e a t e t a b l e s in the database85 f o r e n t i t i e s . Note that t h i s should be d i s ab l ed when86 running aga in s t a product ion database , s i n c e you probably87 don ’ t want to be a l t e r i n g the schema at runtime .88 −−>89 <sysproper ty key=” openjpa . jdbc . SynchronizeMappings ”90 value=”buildSchema”/>
92 < !−−93 Output a l l the SQL for educa t i ona l purposes , but s e t the94 genera l l o g g i n g l e v e l to only show warnings .95 −−>96 <sysproper ty key=” openjpa . Log”97 value=” Defau l tLeve l=WARN,SQL=TRACE”/>98 </ java>99 </ t a r g e t>
100 </ p r o j e c t>
302 APPENDIX B. UTILIZAREA SGBD IN JAVA
Bibliografie
[1] ATHANASIU I., COSTINESCU B., DRAGOI O.A., POPOVICI F.I., 1998,Limbajul Java. O perspectiva pragmatica. Ed. Computer Libris Agora, Cluj-Napoca.
[2] BOIAN F.M., BOIAN R. F., 2004, Tehnologii fundamentale Java pentruaplicatii Web. Ed. Albastra, Cluj-Napoca.
[3] BURAGA S.C., 2001, Tehnologii Web. Ed. Matrix Rom,Bucuresti.
[4] BURAGA S. (ed), 2007, Programarea ın Web 2.0., Ed. Polirom, Iasi.
[5] JURCA I., 2000, Programarea retelelor de calculatoare. Ed. de Vest, Timisoara.
[6] HUNTER J., CRAWFORD W., 1998, Java Servlet Programming. O’Reilly.
[7] ALBOAIE L., BURAGA S., 2006, Servicii Web. Ed. Polirom, Iasi.
[8] SCHEIBER E., 2007, Programare concurenta si paralel distribuita ın Java. Ed.Albastra, Cluj-Napoca.
[9] TANASA S., OLARU C., 2005, Dezvoltarea aplicatiilor Web folosind Java. Ed.Polirom, Bucuresti.
[10] * * * , Java 2 SDK /docs/, Sun Microsystems.
[11] * * * , JavaWS Tutorial 1.*, Sun Microsystems.
[12] * * * , J2EE Tutorial, Sun Microsystems.
[13] * * * , Java 2 Tutorial, Sun Microsystems.
303