Programare distribuita in JAVA_E Scheiber.pdf

download Programare distribuita in JAVA_E Scheiber.pdf

of 179

Transcript of Programare distribuita in JAVA_E Scheiber.pdf

  • Universitatea Transilvania din BrasovFacultatea de MatematicaInformatica

    Catedra de Informatica

    ERNEST SCHEIBER

    PROGRAMARE DISTRIBUITA INJAVA

    Brasov

  • Introducere

    Obiectivele cursului

    Retelele locale, internetul, raspandirea pe o arie geografica a resurselor si alocatiilor n care se petrec actiuni ce tin de o activitate bine definita sau sunturmarite, gestionate din alte locuri au drept consecinta existenta aplicatiilordistribuite. Termenul distribuit se refera tocmai la faptul ca componente aleaplicatiei se afla pe calculatoare diferite dar ntre care au loc schimburi de date.Daca partile unei aplicatii sau resursele utilizate se gasesc pe calculatoare dis-tincte atunci aplicatia 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 sistemulde calcul, sistemul de operare si limbajul de programare.

    Astfel se vorbeste de programare distribuita ca mijloc de realizare a aplicatiilordistribuite. Pe langa algortm, structuri de date, limbaj de programare, la re-alizarea unei aplicatii distribuite intervin comunicatiile: schimbul de date dintredoua componente 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)

    2

  • 3 Servlet si JSP (Java Server Pages)

    Portlet

    dispecer-lucrator: Programul dispecer distribuie sarcinile de executatlucratorilor si le coordoneaza activitatea.

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

    socluri Java;

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

    mesageria Java;

    servlet;

    Java server Pages - JSP;

    Portlet si Portal.

    Modelul dispecer-lucrator nu face parte din obiectivul cursului.

    Competente conferite

    Se dezvolta deprinderile de programare distribuita.

  • 4Resurse si mijloace de lucru

    Toate resursele utilizate sunt gratuite, ele se descarca din Internet.Metodele si instrumentele de programare vor fi exemplificate pe problema

    foarte simpla de calcul a celui mai mare divizor comun a doua numere naturale.Codul metodei de calcul este

    public long cmmdc(long m,long n){

    long r,c;

    do{

    c=n;

    r=m%n;

    m=n;

    n=r;

    }

    while(r!=0);

    return c;

    }

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

    Tiparul de nvatare poate fi

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

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

    3. Pentru fiecare tehnologie, citind cursul, se programeaza o alta aplicatie.

    Propunem problemele:

    conversia ntre grade Celsius n grade Fahrenheit (F = 1.8C + 32). Crearea, ntretinerea si utilizarea unei agende de adrese de e-mail.

    Agenda este o baza de date.

    4. In final, se rezolva tema pentru examen.

    Structura cursului

    1. Modulul 1: Programare distribuita cu comunicatii ce nu folosesc pe proto-colul http - HyperText Transfer Protocol.

  • 5(a) UI 1. Socluri TCP.

    (b) UI 2. Datagrame si canale de comunicatii.

    (c) UI 3. Regasirea obiectelor prin servicii de nume.

    (d) UI 4. RMI.

    (e) UI 5. Tipare de programare RMI.

    (f) UI 6. CORBA.

    (g) UI 7. JMS cu comunicatie punctuala.

    (h) UI 8. JMS cu comunicatie bazata pe subiect si protocolul AMPQ.

    2. Modulul 2: Programare distribuita cu comunicatii bazate pe protocolulhttp.

    (a) UI 9. Servlet.

    (b) UI 10. Facilitati de programare cu servlet.

    (c) UI 11. JSP.

    (d) UI 12. Portlet.

    Cerinte preliminare

    Intelegerea cursului presupune cunostinte si deprinderi de programare n lim-bajul Java.

    Evaluarea

    Evaluarea se termina cu un examen care consta din

  • 61. Test scris alcatuit din 10 intrebari, cu calificative (foarte bine (8-10 raspunsuricorecte), bine (6-7), satisfator (4-5) si nesatisfacator (0-3),) avand rol ori-entator pentru aprecierea probei practice. Durata testului este de 12-15minute

    2. Proba practica consta din prezentarea unui aplicatii din fiecare din tehnologi-ile studiate (socluri, RMI sau CORBA, mesagerie, servlet, JSP, portlet),in total sapte aplicatii. Temele aplicatiilor cat si detalii tehnice privindtehnologia de programare se stabilesc de comun acord cu ndrumatorul lab-oratorului.

    Toate aplicatiile se executa pe calculatoarele unui laborator.

    Programele nu contin comentarii explicative. Pentru examen tema si textelesursa ale programelor vor fi listate.

    Ponderea examenului este 100%.Materialul de fata este orientativ. Documentatia la zi este disponibila prin

    intranetul din corpul P al universitatii.

  • Cuprins

    I Programare distribuita fara HTTP 10

    1 Programare cu socluri Java 12

    1.1 Aplicatii client server . . . . . . . . . . . . . . . . . . . . . . . . . 12

    1.2 Notiuni despre retele . . . . . . . . . . . . . . . . . . . . . . . . . . 13

    1.3 Soclu TCP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14

    1.4 Aplicatie client server cu socluri . . . . . . . . . . . . . . . . . . 16

    2 Datagrame si canale de comunicatii 22

    2.1 Datagrame . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22

    2.1.1 Aplicatii client server cu datagrame. . . . . . . . . . . . . 27

    2.1.2 Multicast vs. Broadcast . . . . . . . . . . . . . . . . . . . . 31

    2.2 Canale de comunicatie . . . . . . . . . . . . . . . . . . . . . . . . . 35

    3 Regasirea obiectelor prin servicii de nume 47

    3.1 Java Naming and Directory Interface . . . . . . . . . . . . . . . . . 48

    3.1.1 LDAP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52

    4 Remote Method Invocation - RMI 56

    4.1 Remote Method Invocation . . . . . . . . . . . . . . . . . . . . . . 57

    4.1.1 Crearea unei aplicatii RMI . . . . . . . . . . . . . . . . . . 60

    5 Tipare de programare RMI 66

    5.1 Fabrica de obiecte . . . . . . . . . . . . . . . . . . . . . . . . . . . 66

    5.2 Apelul invers Callback . . . . . . . . . . . . . . . . . . . . . . . . 69

    6 CORBA 73

    6.1 CORBA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73

    6.1.1 Conexiunea RMI - CORBA . . . . . . . . . . . . . . . . . . 74

    6.1.2 Aplicatie Java prin CORBA . . . . . . . . . . . . . . . . . . 79

    7

  • 8 CUPRINS

    7 JMS cu comunicatie punctuala 847.1 Java Message Service (JMS) . . . . . . . . . . . . . . . . . . . . . . 857.2 Open Message Queue . . . . . . . . . . . . . . . . . . . . . . . . . . 867.3 Apache ActiveMQ . . . . . . . . . . . . . . . . . . . . . . . . . . . 877.4 Elemente de programare - JMS . . . . . . . . . . . . . . . . . . . . 87

    7.4.1 Trimiterea unui mesaj . . . . . . . . . . . . . . . . . . . . . 877.4.2 Receptia sincrona a unui mesaj . . . . . . . . . . . . . . . . 927.4.3 Receptia asincrona a unui mesaj . . . . . . . . . . . . . . . 94

    8 JMS cu comunicatie bazata pe subiect 978.1 Publicarea mesajelor . . . . . . . . . . . . . . . . . . . . . . . . . . 97

    8.1.1 Publicarea mesajelor . . . . . . . . . . . . . . . . . . . . . . 978.1.2 Subscrierea si receptia mesajelor . . . . . . . . . . . . . . . 98

    II Programare distribuita cu HTTP 101

    9 Servlet 1039.1 Marcajul . . . . . . . . . . . . . . . . . . . . . . . . . . . 1049.2 Server Web - container de servlet . . . . . . . . . . . . . . . . . . . 1059.3 Realizarea unui servlet . . . . . . . . . . . . . . . . . . . . . . . . . 107

    9.3.1 Codul unui servlet . . . . . . . . . . . . . . . . . . . . . . . 1099.4 Procesare asincrona n Java Servlet 3.0 . . . . . . . . . . . . . . . . 116

    10 Facilitati de programare cu servlet 12010.1 Program client al unui servlet . . . . . . . . . . . . . . . . . . . . . 12010.2 Servlete nlantuite . . . . . . . . . . . . . . . . . . . . . . . . . . . 12310.3 Sesiune de lucru . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12510.4 Cookie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12610.5 Servlet cu conexiune la o baza de date . . . . . . . . . . . . . . . . 12810.6 Imagini furnizate de servlet . . . . . . . . . . . . . . . . . . . . . . 13010.7 Filtru . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132

    11 Java Server Page JSP 13611.1 Tehnologia JSP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136

    11.1.1 Declaratii JSP . . . . . . . . . . . . . . . . . . . . . . . . . 14211.1.2 Directive JSP . . . . . . . . . . . . . . . . . . . . . . . . . . 14311.1.3 Marcaje JSP predefinite . . . . . . . . . . . . . . . . . . . . 14411.1.4 Componenta Java (Java Bean) . . . . . . . . . . . . . . . . 14511.1.5 Pagini JSP cu componente Java . . . . . . . . . . . . . . . 145

    11.2 JSP Standard Tag Library JSTL . . . . . . . . . . . . . . . . . . . 14911.2.1 Biblioteca de baza . . . . . . . . . . . . . . . . . . . . . . . 14911.2.2 Biblioteca de lucru cu baze de date . . . . . . . . . . . . . . 154

  • CUPRINS 9

    12 Portlet 15712.1 Apache-pluto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15912.2 Dezvoltarea unui portlet . . . . . . . . . . . . . . . . . . . . . . . . 16012.3 Elemente de programare . . . . . . . . . . . . . . . . . . . . . . . . 16412.4 Produse Portal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173

    12.4.1 uPortal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17312.4.2 Jetspeed-2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 177

    Bibliografie 179

  • Modulul I

    Programare distribuita cucomunicatii ce nu folosesc

    protocolul HTTP

    10

  • 11

    Introducere

    Se prezinta programarea Java bazate pe

    Protocoalele TCP si UDP; modelul de apel de procedura la distanta (Remote Procedure Call) RMI si

    CORBA;

    serviciul de mesagerie java.

  • Unitatea de nvatare 1

    Programare cu socluri Java

    Durata: 3 ore.

    Introducere

    Limbajul de programare Java ofera facilitati de elaborare ale unor programecare utilizeaza si interactioneaza cu resurse din Internet si din World Wide Web.

    In plus limbajul Java permite utilizarea URL-ului (Universal Resource Loca-tor adresa resurselor n Internet), a soclurilor (socket) si a datagramelor.

    1.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.

    12

  • 1.2. NOTIUNI DESPRE RETELE 13

    componenta client - alcatuita din programe / clase care permit accesul laserver si 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.

    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 serviciiloroferite de server.

    La apelarea serverului, clientul este autentificat - adica i se recunoaste iden-titatea - si apoi i se asigura accesul la servicii n limita drepturilor pe care leare.

    1.2 Notiuni despre retele

    Calculatoarele ce ruleaza n Internet comunica ntre ele folosind protocolulTCP (Transport Control Protocol) sau UDP (User Datagram Protocol).

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

    TCP Cand doua aplicatii comunica ntre ele se stabileste o conexiune prinintermediul careia se schimba date. Folosind protocolul TCP, comunicatia garan-teaza ca datele trimise dintr-un capat ajung n celalalt capat cu pastrarea ordiniin care au fost trimise. Acest tip de comunicatie seamana cu o convorbire tele-fonica. TCP furnizeaza 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 data-

  • 14 UNITATEA DE INVATARE 1. PROGRAMARE CU SOCLURI JAVA

    gramele ajung la destinatie si nici ordinea lor de sosire. Acest tip de comunicatieseamana cu trimiterea scrisorilor prin posta.

    1.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 nivelscazut. Pentru a comunica utilizand TCP programul client si programul serverstabilesc o conexiune sigura. Fiecare program se leaga la conexiune printr-unsoclu (socket). Un soclu este capatul unei cai de comunicatie bidirectional ntredoua programe ce ruleaza n retea. Un soclu este legat de un port prin carenivelul TCP poate identifica aplicatia careia i sunt transmise datele. Din punctde vedere fizic, un port este o adresa de memorie cuprinsa ntre 0 si 65535.

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

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

    Clientul cunoaste numele calculatorului pe care ruleaza serverul cat si portulla care acesta este conectat. Pentru stabilirea conexiunii, clientul ncearca unrendez-vous cu serverul de pe masina serverului si la portul serverului. Dacatotul decurge bine, serverul accepta conexiunea. Dupa acceptare, serverul creazapentru client un nou soclu legat la un alt port n asa fel ncat ascultarea cererilorla soclul initial sa poata continua n timp ce sunt satisfacute cererile clientuluiconectat. Din partea clientului, dupa acceptarea conexiunii soclul este creat sieste utilizat pentru comunicatia cu serverul.

    Clasa java.net.Socket

    Resursele clasei Socket sunt destinate clientului.

    Constructori

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

    Creaza un soclu conectat la calculatorul cu portul specificat.

    public Socket(InetAddress host, int port) throws IOExceptionCreaza un soclu conectat la calculatorul cu portul specificat.

    Metode

  • 1.3. SOCLU TCP 15

    public InputStream getInputStream() throws IOExceptionReturneaza un flux de intrare atasat soclului, pentru citirea (preluarea)informatiilor de la soclu.

    public OutputStream getOutputStream() throws IOExceptionReturneaza un flux de iesire atasat soclului, pentru scrierea (transmiterea)informatiilor la soclu.

    public synchronized void close() throws IOExceptionnchide soclul de referinta.

    Clasa java.net.ServerSocket

    Resursele clasei ServerSocket sunt destinate serverului.

    Constructori

    public ServerSocket(int port) throws IOExceptionCreaza un soclu la portul specificat. Daca port=0, atunci va fi utilizatorice port disponibil. Capacitatea sirului (tamponului) de asteptare pentrucererile de conectare se fizeaza la valoarea implicita 50. Cererile n excesvor fi refuzate.

    public ServerSocket(int port, int lung) throws IOExceptionIn 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 IOExceptionMetoda blocheaza procesul (firul de executie) apelant pana la sosirea uneicereri de conectare si creaza un soclu client prin care se va desfasura comu-nicarea cu solicitantul acceptat.

    public synchronized void close() throws IOExceptionnchide soclul de referinta.

  • 16 UNITATEA DE INVATARE 1. PROGRAMARE CU SOCLURI JAVA

    1.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 schimbulde date cu clientul. Cererile clientilor pot fi satisface concurent/paralel, utilizandfire de executie ce implementeaza serviciul oferit sau secvential - n cazul unorservicii de durata scurta.

    Exemplul 1.4.1 Sistem client - server pentru calculul celui mai mare divizorcomun a 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. 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 ( ) ) ;

  • 1.4. APLICATIE CLIENT SERVER CU SOCLURI 17

    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 }

    Se presupune ca programul server ruleaza pe calculatorul local si utilizeazaportul 7999. Daca acesti parametri se modifica - de exemplu serverul ruleaza nretea pe calculatorul atlantis la portul 8200 - atunci la apelare transmitem acestiparametri prin 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 /

  • 18 UNITATEA DE INVATARE 1. PROGRAMARE CU SOCLURI JAVA

    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 }

    In ciclul while, la receptia unei solicitari de conexiune se creaza si selanseaza un fir de executie a carei metoda run contine actiunile ce raspundsolicitarii.

    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 detransmitere a rezultatului.

    1 import java . net . ;2 import java . i o . ;

    4 public class AppThread extends Thread{5 Socket socket=null ;

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

    11 public void run ( ){

  • 1.4. APLICATIE CLIENT SERVER CU SOCLURI 19

    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 douanumere naturale.

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

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

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

    Aplicatia se va compune din:

    Aplicatia server alcatuita din: Interfata

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

    Implementarea interfetei

    1 package s e r v e r . impl ;2 import s e r v e r . ;3 import i s e r v e r . IMyMServer ;

  • 20 UNITATEA DE INVATARE 1. PROGRAMARE CU SOCLURI JAVA

    4 import java . net . ;5 import java . i o . ;6 import java . u t i l . concurrent . ;

    8 public class MyMServer implements IMyMServer{

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

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

    Clasele AppThread, App sunt cele utilizate anterior.

    Clasa de lansare a serverului

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

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

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

    Aplicatia client este nemodificata.

  • 1.4. APLICATIE CLIENT SERVER CU SOCLURI 21

    Test de evaluare a cunostintelor

    1. Precizati termenul socket (soclu).

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

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

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

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

  • Unitatea de nvatare 2

    Datagrame si canale decomunicatii

    Durata: 4 ore.

    2.1 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 nueste garantata iar momentul de sosire este neprecizat.

    22

  • 2.1. DATAGRAME 23

    Clasa java.net.DatagramPacket.

    Trimiterea unui pachet UDP necesita crearea unui obiectDatagramPacket care contine corpul mesajului si adresa destinatiei. Apoi acestobiect DatagramPacket poate fi pus n retea n vederea trimiterii sale. Prim-irea unui pachet UDP necesita crearea unui obiect DatagramPacket si apoi ac-ceptarea unui pachet UDP din retea. Dupa primire, se poate extrage din obiectulDatagramPacket adresa sursa si continutul mesajului.

    ConstructoriExista doi constructori pentru datagrame UDP. Primul constructor este folosit

    pentru primirea de pachete si necesita doar furnizarea unei memorii tampon, iarcelalalt este folosit pentru trimiterea de pachete si necesita specificarea adreseidestinatarului.

    DatagramPacket(byte[ ] buffer,int lung)Acest contructor este folosit pentru primirea pachetelor. Un pachet se mem-oreaza n tamponul buffer avand lung octeti. Daca lungimea pachetuluidepaseste aceasta lungime, atunci pachetul este trunchiat iar octetii n plusse pierd.

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

    Metode

    InetAddress getAddress()returneaza adresa IP a expeditorului.

    int getPort()returneaza portul expeditorului.

    byte[] getData()returneaza continutul pachetului.

    int getLength()returneaza lungimea pachetului.

    void setAddress(InetAddress adresa)fixeaza adresa IP a pachetului.

  • 24 UNITATEA DE INVATARE 2. DATAGRAME SI CANALE DE COMUNICATII

    void setPort(int port)fixeaza portul.

    void setData(byte[] buffer)fixeaza continutul pachetului.

    void setLength(int lung)fixeaza lungimea pachetului.

    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

    DatagramSocket() throws SocketExceptionCreaza un obiect DatagramSocket cu un numar de port aleator;

    DatagramSocket(int port) throws SocketExceptionCreaza un obiect DatagramSocket cu numarul de port specificat;

    DatagramSocket(int port, InetAddress adresa) throws SocketExceptionCreaza un obiect DatagramSocket la adresa si portul specificat.

    MetodeClasa DatagramSocket contine metode pentru trimiterea si primirea de obiecte

    DatagramPacket, nchiderea soclului, determinarea informatiilor adresei localesi setarea timpului de primire.

    void send(DatagramPacket pachet) throws IOExceptionTrimite pachetul prin retea. Daca se trimit pachete la o destinatie ne-cunoscuta sau care nu asculta, n cele din urma se genereaza o exceptieIOException.

    void receive(DatagramPacket pachet) throws IOExceptionMetoda primeste un singur pachet UDP n obiectul pachet specificat. Apoi,pachetul poate fi inspectat pentru determinarea adresei IP sursa, portulsursa si lungimea mesajului. Executia metodei este blocata pana cand seprimeste cu succes un pachet sau se scurge timpul de asteptare.

  • 2.1. DATAGRAME 25

    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 SocketExceptionMetoda fixeaza timpul de asteptare (n milisecunde) a soclului. Metodareceive() se va bloca pentru timpul de asteptare specificat pentru primireaunui pachet UDP, dupa care va arunca o exceptie Interrupted Exception.Daca valoarea parametrului este 0, atunci soclul este blocat.

    int getSoTimeout() throws SocketExceptionReturneaza timpul de asteptare.

    void setSendBufferSize(int lungime) throws SocketExceptionFixeaza 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 SocketExceptionReturneaza lungimea tamponului de trimitere a soclului.

    void setReceiveBufferSize(int lungime) throws SocketExceptionFixeaza lungimea tamponului de primire a soclului la valoarea specificata.Nu poate fi primit un mesaj UDP de lungime mai mare de aceasta valoare.

    int getReceiveBufferSize() throws SocketExceptionReturneaza lungimea tamponului de primire a soclului.

    void connect(InetAddress adresa, int port) throws SocketExceptionConecteaza soclul la adresa si portul specificat. Aceasta metoda nu esteceruta pentru operatiile uzuale UDP.

    void disconnect()Deconecteaza soclul conectat.

    InetAddress getInetAddress()Returneaza obiectul InetAddress catre care este conectat soclul sau nulldaca acesta nu este conectat.

  • 26 UNITATEA DE INVATARE 2. DATAGRAME SI CANALE DE COMUNICATII

    int getPort()Returneaza portul la care este conectat soclul sau -1 daca acesta nu esteconectat.

    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 UnknownHostExceptionReturneaza un obiect InetAddress corespunzator masinii locale.

    InetAddress getByName(String host) throws UnknownHostExceptionReturneaza un obiect InetAddress corespunzator masinii host, parametrucare poate fi specificat prin nume (de exemplu atlantis) sau prin adresaIP (168.192.0.1).

    InetAddress [ ]getAllByName(String host)throws UnknownHostException

    Returneaza un sir de obiecte InetAddress corespunzator fiecarei adrese IPa masinii host.

    Metodele clasei InetAddress

    byte [ ] getAddress()Returneaza sirul de octeti corespunzator obiectului InetAddress de referinta.

    String getHostName()Returneaza numele masinii gazda.

    String getHostAddress()Returneaza adresa IP a masinii gazda.

    boolean isMulticastAddress()Returneaza true daca obiectul InetAddress reprezinta o adresa IP multi-cast (cuprins ntre 224.0.0.0 si 239.255.255.255).

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

    Exemplul 2.1.1

  • 2.1. DATAGRAME 27

    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

  • 28 UNITATEA DE INVATARE 2. DATAGRAME SI CANALE DE COMUNICATII

    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 destinatarului. Daca packet este unobiect DatagramPacket receptionat atunci metodele getAddress() si getPort()furnizeaza adresa si portul expeditorului

    Receptionarea si transformarea inversa este

    byte[] bin=new byte[256];

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

    socket.receive(packet);

    ByteArrayInputStream bais=new ByteArrayInputStream(bin);

    ObjectInputStream in=new ObjectInputStream(bais);

    obj=in.readObject();

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

    Exemplul 2.1.2 Programam serviciul calculului celui mai mare divizor comuna doua numere.

    In vederea transportului definim clasa

    1 package s e r v e r ;2 import java . i o . ;

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

    10 }

  • 2.1. DATAGRAME 29

    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. Aceasta clasa este disponibila atat serverului cat siclientului.

    Se va utiliza arhitectura de aplicatie dezvoltata n finalul sectiunii anterioare.Aplicatia se va compune din:

    Aplicatia server alcatuita din: Interfata

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

    Implementarea interfetei

    1 package s e r v e r . impl ;2 import s e r v e r . ;3 import i s e r v e r . IMyMServer ;4 import java . net . ;5 import java . i o . ;6 import java . u t i l . concurrent . ;

    8 public class MyMServer implements IMyMServer{

    10 public DatagramSocket getDatagramSocket ( int port ){11 DatagramSocket datagramSocket = null ;12 try{13 datagramSocket = new DatagramSocket ( port ) ;14 }15 catch ( IOException e ) {16 System . e r r . p r i n t l n ( Could not l i s t e n on port : +port ) ;17 System . e r r . p r i n t l n ( e . getMessage ( ) ) ;18 System . e x i t ( 1 ) ;19 }20 System . out . p r i n t l n ( DatagramSocket i s ready . . . ) ;21 return datagramSocket ;22 }

    24 public void myAction ( DatagramSocket datagramSocket ){25 int NTHREADS=100;26 ExecutorServ i ce exec=Executors . newFixedThreadPool (NTHREADS) ;27 while ( true ){28 try{29 AppThread obj=new AppThread ( datagramSocket ) ;30 exec . execute ( obj ) ;31 }32 catch ( Exception e ){33 System . e r r . p r i n t l n ( MyActionException : +e . getMessage ( ) ) ;34 }35 }36 }37 }

  • 30 UNITATEA DE INVATARE 2. DATAGRAME SI CANALE DE COMUNICATII

    Clasa AppThread

    1 package s e r v e r ;2 import java . net . ;3 import java . i o . ;

    5 public class AppThread extends Thread{6 DatagramSocket socke t=null ;

    8 public AppThread ( DatagramSocket socke t ){9 this . s ocke t=socket ;

    10 }

    12 public void run ( ){13 DatagramPacket packet=null ;14 App app=new App ( ) ;15 Protoco l p=null ;16 try{17 byte [ ] bin=new byte [ 4 0 4 8 ] ;18 packet=new DatagramPacket ( bin , bin . l ength ) ;19 socke t . r e c e i v e ( packet ) ;20 ByteArrayInputStream ba i s=new ByteArrayInputStream ( bin ) ;21 ObjectInputStream in=new ObjectInputStream ( ba i s ) ;22 p=(Protoco l ) in . readObject ( ) ;23 p . x=app . cmmdc(p . x , p . y ) ;24 p . y=0;25 ByteArrayOutputStream baos=new ByteArrayOutputStream ( 2 5 6 ) ;26 ObjectOutputStream out=new ObjectOutputStream ( baos ) ;27 out . wr i teObject (p ) ;28 byte [ ] bout=baos . toByteArray ( ) ;29 InetAddress address=packet . getAddress ( ) ;30 int port=packet . getPort ( ) ;31 packet=new DatagramPacket ( bout , bout . length , address , port ) ;32 socke t . send ( packet ) ;33 }34 catch ( Exception e ){35 System . out . p r i n t l n ( e . getMessage ( ) ) ;36 }37 }38 }

    Clasa de lansare a serverului

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

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

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

  • 2.1. DATAGRAME 31

    Aplicatia client1 package c l i e n t ;2 import java . net . ;3 import java . i o . ;4 import s e r v e r . Protoco l ;5 import java . u t i l . Scanner ;

    7 public class CmmdcClient{8 public stat ic void main ( St r ing [ ] a rgs ){9 St r ing hos tServe r= l o c a l h o s t ;

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

    2.1.2 Multicast vs. Broadcast

    Clasa java.net.MulticastSocket

    Prin intermediul unui soclu de tip MulticastSocket se pot receptiona data-grame expediate de un server catre toti clientii cu un asemenea soclu.

    Constructori

    MulticastSocket(int port) throws SocketException

  • 32 UNITATEA DE INVATARE 2. DATAGRAME SI CANALE DE COMUNICATII

    Metode

    void joinGroup(InetAddress adresa) throws SocketExceptionSoclul se conecteaza la grupul definit de adresa IP (de tip D, adica cuprinsntre 224.0.0.0 si 239.255.255.255).

    void leaveGroup(InetAddress adresa) throws SocketExceptionSoclul se deconecteaza la grupul definit de adresa IP.

    void close()Pregatirea clientului n vederea receptionarii datagramelor printr-un soclu de

    tip MulticastSocket consta din

    MulticastSocket socket= new MulticastSocket(port);

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

    socket.joinGroup(adresa);

    In final, clientul se deconecteaza si nchide soclul.

    socket.leaveGroup(adresa);

    socket.close();

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

    Astfel prin multicast serverul trimite pachete la o adresa de grup si la unport fixat. Pachetele emise de server sunt receptionate de orice client ce creazaun soclu de tip MulticastSocket pentru portul la care emite serverul si care sealatura 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 driveru-lui Microsoft Loopback Adapter, care simuleaza existenta unei placi de retea ac-tive.

    Exemplul 2.1.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 serversi cea de client.

  • 2.1. DATAGRAME 33

    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.

  • 34 UNITATEA DE INVATARE 2. DATAGRAME SI CANALE DE COMUNICATII

    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

  • 2.2. CANALE DE COMUNICATIE 35

    2.2 Canale de comunicatie

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

    Utilizam clasele java.nio.channels.SocketChannel, java.nio.channel.DatagramChannel. Informatia transportata n aceste canale de comunicatie tre-buie nglobata n obiecte container de tip Buffer.

    Clasa java.nio.Buffer

    Ierarhia claselor Buffer

    abstract Buffer

    ByteBuffer

    ShortBuffer

    IntBuffer

    LongBuffer

    FloatBuffer

    DoubleBuffer

    CharBuffer

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

    Un obiect de tip Buffer este caracterizat de

    capacitate (capacity) numarul elementelor care pot fi nmagazitate n tam-pon;

    limita (limit) marginea superiora a indicelui; indice (position) valoarea curenta a indicelui, ce corespunde unui cursor

    ce indica nceputul zonei unde se introduc sau de unde se extrag date dintampon.

    Metode generale

    clear() permite unui obiect de tip Buffer sa fie rencarcat. 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.

  • 36 UNITATEA DE INVATARE 2. DATAGRAME SI CANALE DE COMUNICATII

    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, semnalandexistenta n tampon a unor octeti.

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

    Converteste sirul de octeti ntr-un obiect Bytebuffer.

  • 2.2. CANALE DE COMUNICATIE 37

    public final byte[] array()Transformarea inversa, obiectul ByteBuffer este convertit ntr-un sir deocteti.

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

    ByteBuffer bb=ByteBuffer.allocate(10);

    LongBuffer lb=bb.asLongBuffer();

    DoubleBuffer db=bb.asDoubleBuffer();

    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)

    Clasa java.nio.channels.ServerSocketChannel

    Crearea unui obiect de tip ServerSocketChannel se realizeaza prin

    static ServerSocketChannel open() throws IOException

    Unui asemenea obiect i se asociaza un ServerSocket prin metoda

    ServerSocket socket() throws IOException.

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

    void bind(InetSocketAddress endpoint) throws IOException.

    Sablonul de utilizare este

    try{

    ServerSocketChannel ssc=ServerSocketChannel.open();

    ServerSocket ss=ssc.socket();

    InetSocketAddress isa=new InetSocketAddress(addr,port);

    ss.bind(isa);

    }

    catch(Exception e){. . .}

    La apelul unui client, serverul trebuie sa genereze un obiect de tip SocketChannel prin care se vor derula comunicatiile cu clientul. Acest canal de comunicatiese obtine cu metoda accept().

  • 38 UNITATEA DE INVATARE 2. DATAGRAME SI CANALE DE COMUNICATII

    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. Datelese transmit prin metoda

    int write(ByteBuffer sursa)

    si se receptioneaza prin metoda

    int read(ByteBuffer destinatie)

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

    Doar octetii unui obiect de tip ByteBuffer cuprinsi ntre indice si limita sunttransmisi prin canal. Astfel, dupa ncarcarea unui obiectului ByteBuffer cumetode relative trebuie apelata metoda flip().

    Canalul se nchide cu metoda close().

    Exemplul 2.2.1 Calculul celui mai mare divizor comun a doua numere naturale.

    Aplicatie client-server bazat pe canale de comunicatie prin socluri se compunedin:

    Aplicatia server alcatuita din: Interfata

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

    Implementarea interfetei

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

    10 public class MyMServer implements IMyMServer{

  • 2.2. CANALE DE COMUNICATIE 39

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

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

    Clasa AppThread

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

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

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

    14 public void run ( ){15 try{16 ByteBuffer bb = ByteBuffer . a l l o c a t e ( 1 6 ) ;17 //LongBuffer l b = bb . asLongBuffer ( ) ;18 socketChannel . read (bb ) ;19 // Varianta 120 long m=bb . getLong ( 0 ) ;21 long n=bb . getLong ( 8 ) ;22 // Varianta 223 // long m=l b . ge t ( 0 ) ;24 // long n=l b . g e t ( 1 ) ;

  • 40 UNITATEA DE INVATARE 2. DATAGRAME SI CANALE DE COMUNICATII

    25 App app=new App ( ) ;26 long r=app . cmmdc(m, n ) ;27 bb . c l e a r ( ) ;28 // Varianta 129 bb . putLong (0 , r ) ;30 // Varianta 231 // l b . put ( r ) ;32 socketChannel . wr i t e (bb ) ;33 socketChannel . c l o s e ( ) ;34 }35 catch ( IOException e ){36 System . e r r . p r i n t l n ( Server comunication e r r o r : +37 e . getMessage ( ) ) ;38 }39 }40 }

    Clasa de lansare a serverului

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

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

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

    Aplicatia client1 package c l i e n t ;2 import java . i o . ;3 import java . net . ;4 import java . n io . ;5 import java . n io . channe l s . ;6 import java . u t i l . Scanner ;

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

    10 St r ing host= l o c a l h o s t ;11 int port =7999;12 i f ( args . length >0)13 host=args [ 0 ] ;14 i f ( args . length >1)15 port=I n t e g e r . pa r s e In t ( args [ 1 ] ) ;16 SocketChannel sc=null ;17 try{18 InetSocketAddress i s a=new InetSocketAddress ( host , port ) ;19 sc=SocketChannel . open ( ) ;20 sc . connect ( i s a ) ;

  • 2.2. CANALE DE COMUNICATIE 41

    21 }22 catch ( UnknownHostException e ) {23 System . e r r . p r i n t l n ( Server necunoscut : +host+ +e . getMessage ( ) ) ;24 System . e x i t ( 1 ) ;25 }26 catch ( IOException e ) {27 System . e r r . p r i n t l n ( Conectare i m p o s i b i l a l a : +28 host+ pe por tu l +port+ +e . getMessage ( ) ) ;29 System . e x i t ( 1 ) ;30 }31 Scanner scanner=new Scanner ( System . in ) ;32 long m, n , r ;33 System . out . p r i n t l n ( m= ) ;34 m=scanner . nextLong ( ) ;35 System . out . p r i n t l n ( n= ) ;36 n=scanner . nextLong ( ) ;

    38 ByteBuffer bb=ByteBuffer . a l l o c a t e ( 1 6 ) ;39 // Varianta 140 bb . putLong (0 ,m) . putLong (8 , n ) ;41 // Varianta 242 // LongBuffer l b=bb . asLongBuffer ( ) ;43 // l b . put (0 ,m) . put (1 ,n ) ;44 try{45 sc . wr i t e (bb ) ;46 bb . c l e a r ( ) ;47 sc . read (bb ) ;48 // Varianta 149 r=bb . getLong ( 0 ) ;50 // Varianta 251 // r=l b . g e t ( 0 ) ;52 System . out . p r i n t l n ( Cmmdc : +r ) ;53 sc . c l o s e ( ) ;54 }55 catch ( Exception e ){56 System . e r r . p r i n t l n ( Eroare de comunicat ie +e . getMessage ( ) ) ;57 }58 }59 }

    Varianta comentata corespunde cazului n care se utilizeara clasa acoperitoareLongBuffer.

    Clasa java.nio.channels.DatagramChannel

    Sablonul de programare pentru instantierea unui obiect de tip DatagramChanneleste

    DatagramChannel dc=null;

    InetSocketAddress isa=new InetSocketAddress(port);

    try{

    dc=DatagramChannel.open();

    DatagramSocket datagramSocket=dc.socket();

    datagramSocket.bind(isa);

  • 42 UNITATEA DE INVATARE 2. DATAGRAME SI CANALE DE COMUNICATII

    }

    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

    public int send(ByteBuffer src, SocketAddress target) throwsIOException

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

    public SocketAddress receive(ByteBuffer dst) throws IOException

    Obiectul returnat reprezinta adresa expeditorului.

    Exemplul 2.2.2 Calculul celui mai mare divizor comun a doua numere naturale.

    Aplicatia server este alcatuita din: Interfata

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

    Implementarea interfetei

    1 package s e r v e r . impl ;2 import s e r v e r . ;3 import i s e r v e r . IMyMServer ;4 import java . net . ;5 import java . n io . ;6 import java . n io . channe l s . DatagramChannel ;7 import java . u t i l . concurrent . ;8 import java . i o . IOException ;

    10 public class MyMServer implements IMyMServer{

    12 public DatagramChannel getDatagramChannel ( int port ){13 DatagramChannel datagramChannel=null ;14 InetSocketAddress i s a=new InetSocketAddress ( port ) ;15 try{16 datagramChannel = DatagramChannel . open ( ) ;17 DatagramSocket datagramSocket=datagramChannel . socke t ( ) ;18 datagramSocket . bind ( i s a ) ;19 }20 catch ( IOException e ){21 System . out . p r i n t l n ( DatagramChannelError : +e . getMessage ( ) ) ;22 System . e x i t ( 0 ) ;

  • 2.2. CANALE DE COMUNICATIE 43

    23 }24 System . out . p r i n t l n ( Server ready . . . ) ;25 return datagramChannel ;26 }

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

    Clasa AppThread

    1 package s e r v e r ;2 import java . net . SocketAddress ;3 import java . i o . IOException ;4 import java . n io . channe l s . DatagramChannel ;5 import java . n io . ;

    7 public class AppThread extends Thread{8 DatagramChannel datagramChannel=null ;

    10 public AppThread ( DatagramChannel datagramChannel ){11 this . datagramChannel=datagramChannel ;12 }

    14 public void run ( ){15 App app=new App ( ) ;16 try{17 ByteBuffer bb = ByteBuffer . a l l o c a t e ( 1 6 ) ;18 //LongBuffer l b = bb . asLongBuffer ( ) ;19 SocketAddress sa=datagramChannel . r e c e i v e (bb ) ;20 // Varianta 121 long m=bb . getLong ( 0 ) ;22 long n=bb . getLong ( 8 ) ;23 // Varianta 224 // long m=l b . ge t ( 0 ) ;25 // long n=l b . g e t ( 1 ) ;26 long r=app . cmmdc(m, n ) ;27 bb . c l e a r ( ) ;28 // Varianta 129 bb . putLong (0 , r ) ;30 // Varianta 231 // l b . put ( r ) ;32 datagramChannel . send (bb , sa ) ;33 }34 catch ( IOException e ){35 System . e r r . p r i n t l n ( Server comunication e r r o r : +36 e . getMessage ( ) ) ;37 }

  • 44 UNITATEA DE INVATARE 2. DATAGRAME SI CANALE DE COMUNICATII

    38 }39 }

    Clasa de lansare a serverului

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

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

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

    Aplicatia client1 package c l i e n t ;2 import java . i o . ;3 import java . net . ;4 import java . n io . ;5 import java . n io . channe l s . ;6 import java . u t i l . Scanner ;

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

    10 St r ing se rverHost= l o c a l h o s t ;11 int port =7999;12 i f ( args . length >0)13 se rverHost=args [ 0 ] ;14 i f ( args . length >1)15 port=I n t e g e r . pa r s e In t ( args [ 1 ] ) ;16 InetSocketAddress s e r v e r=null , i s a=null ;17 try{18 s e r v e r=19 new InetSocketAddress ( InetAddress . getByName( se rverHost ) , port ) ;20 }21 catch ( UnknownHostException e ){22 System . out . p r i n t l n ( Unknown host : +e . getMessage ( ) ) ;23 System . e x i t ( 1 ) ;24 }25 i s a=new InetSocketAddress ( 0 ) ;26 DatagramChannel dc=null ;27 try {28 dc=DatagramChannel . open ( ) ;29 DatagramSocket socke t = dc . socket ( ) ;30 socke t . bind ( i s a ) ;31 }32 catch ( IOException e ) {33 System . e r r . p r i n t l n ( Couldn t open the DatagramChannel +34 e . getMessage ( ) ) ;

  • 2.2. CANALE DE COMUNICATIE 45

    35 System . e x i t ( 1 ) ;36 }37 long m, n , r ;38 Scanner scanner=new Scanner ( System . in ) ;39 System . out . p r i n t l n ( m= ) ;40 m=scanner . nextLong ( ) ;41 System . out . p r i n t l n ( n= ) ;42 n=scanner . nextLong ( ) ;43 ByteBuffer bb=ByteBuffer . a l l o c a t e ( 1 6 ) ;44 // Varianta 145 bb . putLong (0 ,m) . putLong (8 , n ) ;46 // Varianta 247 // LongBuffer l b=bb . asLongBuffer ( ) ;48 // l b . put (0 ,m) . put (1 ,n ) ;49 try{50 dc . send (bb , s e r v e r ) ;51 bb . c l e a r ( ) ;52 dc . r e c e i v e (bb ) ;53 // Varianta 154 r=bb . getLong ( 0 ) ;55 // Varianta 256 // r=l b . g e t ( 0 ) ;57 System . out . p r i n t l n ( Cmmdc = +r ) ;58 }59 catch ( Exception e ){60 System . e r r . p r i n t l n ( C l i en t e r r o r : +e . getMessage ( ) ) ;61 }62 f ina l ly {63 i f ( dc !=null ) dc . d i s connec t ( ) ;64 }65 }66 }

    Test de evaluare a cunostintelor

    1. Precizati termenul multicast.

    2. In ce consta participarea serverului la transmisie multicast ?

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

    4. Precizati termenul broadcast.

    5. In ce consta participarea serverului la transmisie broadcast ?

  • 46 UNITATEA DE INVATARE 2. DATAGRAME SI CANALE DE COMUNICATII

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

    7. Care este rolul unui obiect de tip DatagramPacket ?

    8. Precizati metodele clasei DatagramSocket utilizate la expedierea si la receptiaunui datagram.

    9. Ce parametri caracterizeaza un obiect de tip Buffer ?

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

  • Unitatea de nvatare 3

    Regasirea obiectelor prinservicii de nume

    Durata: 2 ore.

    Introducere

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

    Exemple date prin sablonul (Nume Referinta Obiect)1. Accesul la o carte ntr-o biblioteca:

    Titlul cartii Referinta cartii din biblioteca Carte2. Contactul telefonic cu o persoana:

    47

  • 48 UNITATEA DE INVATARE 3. REGASIREA OBIECTELOR PRIN SERVICII DE NUME

    Nume persoana Numar telefon PersoanaUn serviciu de nume contine asocieri dintre nume de obiecte si obiecte si poate

    oferi facilitati de regasire a obiectelor.

    3.1 Java Naming and Directory Interface

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

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

    Alaturi de interfata JNDI, arhitectura JNDI mai contine interfata ServiceProvider Interface - SPI. Implementarea interfetei SPI de un furnizor de serviciiJNDI are ca efect 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 cuobiectul corespunzator.

    DNS - Domain Name System are ca obiect asocierea dintre adresa Internetcu adresa IP.

    RMI registry utilizat n aplicatii RMI, din Java. Are ca obiect asociereantre un nume de serviciu de invocare ale obiectelor la distanta cu un delegatal serviciului (stub).

    COS - Common Object Service Naming utilizat n aplicatii CORBA. Areca obiect asocierea ntre numele unui serviciu de invocare ale obiectelor ladistanta cu 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)

  • 3.1. JAVA NAMING AND DIRECTORY INTERFACE 49

    void unbind(String nume) Object lookup(String nume) NamingEnumeration list(String nume)

    Returneaza lista cu nume obiectelor mpreuna cu tipul lor.

    NamingEnumeration listBindings(String nume)Returneaza lista cu nume obiectelor mpreuna cu tipul si locatia acestora.

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

    Constructori.

    public InitialContext() throws NamingException public void InitialContext(Hashtable environment)throwsNamingException

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

    Acest parametru se poate da n mai multe moduri:

    Includerea n obiectul Hashtable care apare n constructorul clasei InitalContext.

    Hashtable env=new Hashtable()

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

    Context ctx=InitialContext(env);

    sau

    Hashtable env=new Hashtable()

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

    Context ctx=new InitialContext(env);

    Ca parametru de sistem furnizat la lansarea programului Java, prin

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

    Parametrul se poate da n interiorul programului prin

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

  • 50 UNITATEA DE INVATARE 3. REGASIREA OBIECTELOR PRIN SERVICII DE NUME

    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 ntabelul

    Serviciul de nume Clasa

    Filesystem com.sun.jndi.fscontext.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

    Exemplul 3.1.1 Utilizand serviciul JNDI Filesystem se creaza un context prinintermediul 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 ) {

  • 3.1. JAVA NAMING AND DIRECTORY INTERFACE 51

    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 ) ;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.

  • 52 UNITATEA DE INVATARE 3. REGASIREA OBIECTELOR PRIN SERVICII DE NUME

    3.1.1 LDAP

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

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

    1. o=organization,c=country

    2. o=organization

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

    De exemplu, dc=example,dc=com

    4. uid=user id,ou=organization unit

    De exemplu, uid=admin,ou=system

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

    Implementari gratuite LDAP sunt:

    OpenDS (Open Directory Service); ApacheDS (Apache Directory Service). Apache Directory Studio incor-

    poreaza si ofera interfata grafica pentru ApacheDS.

    Vom utiliza produsul OpenDS.Instalarea consta din:

    1. dezarhivarea distributiei;

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

    3. se executa OpenDS-*\setup.bat. Prin intermediul unei interfete 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

  • 3.1. JAVA NAMING AND DIRECTORY INTERFACE 53

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

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

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

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

    autentificare: datele necesare sunt DN si parola; conectare (bind) / deconectare (unbind) la un punct de intrare. Conectarea

    implica crearea unui punct de intrare precizat prin cn;

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

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

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

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

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

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

  • 54 UNITATEA DE INVATARE 3. REGASIREA OBIECTELOR PRIN SERVICII DE NUME

    34 System . out . p r i n t l n ( I n t r o d u c e t i va loa rea a t r i b u t u l u i \cn\ +35 +a o b i e c t u l u i Cmmdc ) ;36 System . out . p r i n t l n ( cn= ) ;37 St r ing cmmdcObj=scanner . next ( ) . tr im ( ) ;

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

    Codul clasei Cmmdc este

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

    10 }

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

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

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

    10 Scanner scanner=new Scanner ( System . in ) ;11 System . out . p r i n t l n ( A l e g e t i f u r n i z o r u l LDAP: ) ;12 System . out . p r i n t l n ( 1 : OpenDS ) ;13 System . out . p r i n t l n ( 2 : Apache Di rec to ry S e r v i c e ) ;14 int prov ide r=scanner . next Int ( ) ;15 Hashtable env = new Hashtable ( ) ;16 env . put ( Context . INITIAL CONTEXT FACTORY,17 com . sun . j n d i . ldap . LdapCtxFactory ) ;18 i f ( prov ide r==1){

  • 3.1. JAVA NAMING AND DIRECTORY INTERFACE 55

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

  • Unitatea de nvatare 4

    Remote Method Invocation -RMI

    Durata: 3 ore.

    Introducere

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

    Se vor prezenta doua cazuri:

    Invocarea procedurilor la distanta n cazul mediului omogen Java. Denu-mirea tehnologiei n acest caz este Invocarea metodelor la distanta RemoteMethod Invocation (RMI). Prin mediu omogen se ntelege faptul ca atatcompontenta server cat si componenta client sunt programate n acelasi

    56

  • 4.1. REMOTE METHOD INVOCATION 57

    limbaj de programare, Java n cazul de fata.

    Invocarea procedurilor la distanta n cazul medii neomogene. Solutia nacest caz este dat de Common Object Request Brocker Arhitecture (CORBA).

    4.1 Remote Method Invocation

    Regasirea obiectelor la distanta. Ideea gasirii unui obiect la distantaeste ca serverul nscrie un reprezentant al sau numit stub (ciot) ntr-un obiectregistry - registru. Acest obiect se creaza cu programul rmiregistry.exe dindistributia java si 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 real-izeaza comunicatia cu programul server.

    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.Acesta este 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 obiectesunt transmise ntr-un format care nu se bazeaza pe referinte. Pentru obiecte seutilizeaza serializarea obiectelor Java.

    Serializarea datelor reprezinta transformarea acestora din tipuri de date diferitentr-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

    receptionat invocand 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 arunceo exceptie java.rmi.RemoteException. Obiectele care circula prin retea trebuiesa implementeze interfata java.io.Serializable.

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

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

  • 58 UNITATEA DE INVATARE 4. REMOTE METHOD INVOCATION - RMI

    2. Aplicatia server care poate implementa serviciile interfetei la distanta sinscrie 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 componenteevolueaza pe 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.

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

    Renregistreaza n registry obiectul obj ce implementeaza interfata Remotesub numele numeServiciu.

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

    String[] list()throws RemoteException, AccessExceptionReturneaza 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 cla-sei LocateRegistry.

    public static Registry getRegistry() throws RemoteException public static Registry getRegistry(String host)throws RemoteException

    public static Registry getRegistry(int port)throws RemoteException

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

  • 4.1. REMOTE METHOD INVOCATION 59

    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 urmeazaa fi apelate de pe alta masina virtuala Java.

    Un obiect de tip UnicastRemoteObject mijloceste transmiterea obiectelor siserveste la generarea unui stub unui serviciu. Generarea stub-ului unui serviciuse obtine prin intermediul metodei statice

    static Remote UnicastRemoteObject.exportObject(Remote obj,int port)

    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 ascultaserviciul;

    numele sub care serviciul s-a nregistrat n registry;

    metodele puse la dispozitie de serviciu.

  • 60 UNITATEA DE INVATARE 4. REMOTE METHOD INVOCATION - RMI

    4.1.1 Crearea unei aplicatii RMI

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

    Pentru exemplele2 care urmeaza, presupunem ca textele sursa se retin nsubcataloage ale unui catalog src, la care are acces doar programatorul, iar claseleobtinute prin compilare se depun n subcataloagele unui catalog public\classes,accesibil prin 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.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 2 I n t e r f a c e a c t i o n s 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

    7 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

    10 11 12 13

    2Sistemul de operare utilizat este Windows

  • 4.1. REMOTE METHOD INVOCATION 61

    14 15

    17 18 < ! Create the time stamp >19 20 21 22

    24 26 28 31 32

    3. Implementarea interfetei remote prin construirea aplicatiei server.

    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 CmmdcI