In aceasta lucrare de laborator vor fi
acoperite total sau partial urmatoarele probleme:
·    Diagramele UML (de cazuri de utilizare, de secvente, de colaborare, de
clase, etc.) ca suport pentru documentarea, generarea automata si testarea
sistemelor software OO
·   
Capturarea si specificarea
cerintelor sistemelor software OO (orientate spre obiecte)
·   
Analiza cerintelor
si a domeniului sistemelor software OO
·   
Proiectarea
arhitecturala si de detaliu a sistemelor software OO
·   
Implementarea in limbajul Java a sistemelor software OO pornind de la
diagramele UML
·    Generarea codului Java din diagrame de clase UML 
· (Depanarea, Testarea, Livrarea - instalarea, Suportul tehnic - mentinerea, …)
_________________________________________________________________
Programarea sau implementarea (scrierea codului, compilarea, executia si depanarea lui) este
activitatea centrala a oricarui proces de dezvoltare a unui sistem software. Fara aceasta activitate
sistemul nu poate fi realizat. Insa alte etape, premergatoare sau ulterioare,
sunt necesare pentru succesul proiectelor software,
cu atat mai multe si mai ample cu cat complexitatea sistemului si riscul de
esec al proiectului sunt mai mari.
Stabilirea
arhitecturii, structurii, comportamentului si a algoritmilor utilizati este o etapa anterioara programarii,
numita conceptie sau proiectare. In
functie de complexitatea sistemului, aceasta poate merge de la o simpla
organigrama sau un simplu pseudocod, pana la descrieri formale complexe (ce pot
permite, daca exista instrumentele software
adecvate, generarea automata a
codului, totala sau partiala). 
O sub-activitate initiala de proiectare arhitecturala (de ansamblu, de nivel inalt) poate fi
necesara in cazul sistemelor software complexe,
pentru a stabili elementele esentiale, structurale, ale viitoarei solutii. Ea
va fi urmata de o sub-activitate de proiectare
a detaliilor, care va tine seama mai mult de constrangerile de
implementare.
In cazul sistemelor software mari, devin importante activitati anterioare proiectarii,
cum ar fi specificarea si analiza
cerintelor si analiza domeniului
problemei a posibilelor solutii.
Dezvoltarea sistemelor software complexe porneste in general de la un caiet de sarcini initial, care poate fi
apoi dezvoltat (corectat, actualizat, etc.) odata cu sistemul.
O activitatea necesara uneori stabilirii caietelor
de sarcini este studiul de oportunitate (studiul
de piata, financiar, de risc, etc.) al produsului pe care si-l propune drept
tinta procesul de dezvoltare. 
In cazul sistemelor software complexe, programarea nu este ultima activitate a procesului de dezvoltare, ea fiind urmata in general de testarea sistemului software creat. Si aceasta activitate poate fi divizata intr-o prima faza de testare unitara, a fiecarui element (bloc, modul, obiect, componenta, subsistem) nou creat, urmata de testarea de ansamblu (de integrare) a sistemului.
In plus, in cazul sistemelor software complexe,
produsul trebuie sa fie insotit de o documentatie de instalare, utilizare,
etc., ceea ce poate impune o activitate de documentare
desfasurata (de preferinta) in paralel cu celelalte activitati de
dezvoltare).
Dupa finalizarea produsului poate fi necesara de
asemenea instalarea si configurarea lui
la beneficiar, si asigurarea intretinerii
lui, si eventual a generatiilor sau versiunilor succesive, intr-o forma
evolutiva.
Mai jos sunt prezentate principalele activitati ale unui proces de dezvoltare a unui sistem software complex, si rezultatele acestor activitati (artefactele).
Specificarea initiala a cerintelor (functionale si calitative) se face in general
printr-un caiet de sarcini
initial (uneori rezultat in urma unui studiu de oportunitate).
Iata un set de cerinte initial, pentru un sistem de comunicatie distribuit,
client-server, bazat pe conexiune (socketuri TCP), suport pentru conversatie textuala (chat).
 
   
 
  
   
   
Analiza OO intentioneaza sa captureze si sa descrie toate
cerintele domeniului si sa creeze un model care defineste clasele cheie ale
domeniului in sistem (ce se intampla in sistem). Scopul este sa
ofere o intelegere si sa asigure o comunicatie despre sistem intre
dezvoltatori si oameni stabilind cerintele (utilizatori/client). Din aceste
motive analiza este indrumata de obicei in cooperare cu utilizatorul sau
clientul. Analiza nu este restrictionata de o solutie tehnica sau detalii.
Dezvoltatorul nu trebuie sa gandeasca in termeni de cod ori de programe in
timpul acestei faze; este primul pas inspre adevarata intelegere a cerintelor
si a realitatii sistemului in proiectare.
Analiza cerintelor incearca sa identifice cerintele, sa clasifice
cerintele, sa stabileasca prioritatile in satisfacerea cerintelor, etc. 
Primul pas al analizei cerintelor este definirea cazurilor de utilizare care descriu ce ofera sistemul
biblioteca in termeni de functionalitate – cerintele functionale ale
sistemului. Analiza unui caz de utilizare implica citirea si analizarea
specificatiilor ca si discutia sistemului cu potentialii utilizatori (clienti)
ai sistemului. 
Analiza incepe prin cautarea
actorilor (categoriilor de utilizatori ai)
sistemului. Un actor reprezinta rolul jucat de catre o persoana sau de
catre un lucru care interactioneaza cu sistemul. Nu este intotdeauna usoara
determinarea limitei sistemului. Prin definitie, actorii sunt exteriori
sistemului.
Actorii se gasesc, de exemplu, printre
utilizatorii sistemului si printre cei responsabili cu configurarea si
intretinerea sa. 
Actorii identificati pentru sistemul chat sunt utilizatorii lui.

Un caz de utilizare este o abstractie a unei parti a comportamentului sistemului. Cazul de
utilizare este instantiat la fiecare utilizare a sistemului de catre o instanta
a unui actor. Dupa intervievarea utilizatorilor, se obtine descompunerea
cerintelor functionale ale categoriilor de actori.
 
   
 
  
   
   
Cazurile de utilizare identificate pentru sistemul chat sunt conectarea utilizatorului
si conversatia intre utilizatori.

Cazurile de utilizare sunt implementate pe tot parcursul dezvoltarii sistemului, pentru a oferi descrieri ale cerintelor functionale ale sistemului. Ele sunt folosite in analiza ca sa verifice daca clasele potrivite ale domeniului au fost definite, si ele pot fi folosite in timpul proiectarii pentru a confirma ca solutia tehnica este suficienta pentru asigurarea functionalitatilor cerute. Cazurile de utilizare pot fi vizualizate in diagrame de secventa, care detaliaza realizarea lor.
Cazul de utilizare Conectare corespunde specificatiei primei faze de lucru a
sistemului:
Utilizatorul lanseaza
componenta client a
sistemului. Clientul se conecteaza
la server, ofera
o interfata grafica utilizatorului,
.... Serverul accepta conexiunile si creaza fire de executie pentru tratarea clientilor
….
Cazul de utilizare Conversatie corespunde specificatiei celei de-a doua faze de lucru
a sistemului:
Clientul … trimite
mesaje catre server, preluate de la utilizator prin interfata grafica. … Fiecare fir de tratare a
unui client va primi mesaje de la clientul
tratat si va difuza aceste mesaje catre toti clientii. Fiecare client preia mesajele de la server si le prezinta
utilizatorului in interfata grafica.
Un caz de utilizare trebuie caracterizat prin:
1. Nume (cat mai sugestiv, pentru a sintetiza cazul
de utilizare). 
            Ex. Conectare
2. Scurta descriere.
            Ex. Clientul se conecteaza
la server, care accepta conexiunea si se pregateste
pentru tratarea 
clientului.
3. Actori (entitati exterioare sistemului modelat,
implicate in cazul de utilizare).
            
Ex. Utilizator.
4. Preconditii (conditiile necesare pentru declansarea
cazului de utilizare).
            
Ex. Serverul e aflat in executie. Clientul
cunoaste adresa si numarul de port pe care asculta 
serverul.
5. Evenimentul care declanseaza cazul de utilizare.
Ex. Utilizatorul lanseaza componenta client a sistemului.
6. Descriere a interactiunii
dintre actori si fiecare caz de utilizare.
            
Ex. I. Utilizatorul lanseaza componenta client a sistemului, care se conecteaza la serverul 
cunoscut.
Serverul accepta conexiunea si se pregateste pentru tratarea
clientului.
II. Clientul ofera o
interfata grafica utilizatorului
7. Alternative la cazul de
utilizare principal.
            
Ex. Daca serverul nu este lansat, conectarea esueaza,
iar clientul anunta acest lucru 
utilizatorului.
8. Evenimentul care produce
oprirea cazului de utilizare.
            
Ex. Clientul prezinta utilizatorului o
interfata grafica.
9. Postconditii (efectele incheierii cazului de utilizare)
            
Ex. Sistemul
este pregatit pentru ca utilizatorul sa
poata conversa cu alti utilizatori prin 
intermediul
interfetei grafice.
E important sa fie clar prezentate:
- schimburile de informatii (parametrii
interactiunilor)
            Ex. Utilizatorul se conecteaza la sistem si isi da numele si
parola.
- originea informatiilor si ordinea schimbarii lor
- repetitiile comportamentului 
            Ex. Prin constructii
pseudocod de genul:
                        loop                                         bucla
                            …                sau                       …
                        end
loop                                  sfarsit
bucla
sau
                        while
(condition)                   cat timp
(conditie)
                            …                sau                       …
                        end
while                                sfarsit
cat timp
- situatiile optionale
            Ex. Utilizatorul alege unul dintre elementele urmatoare (eventual de mai multe ori)
                        a) optiunea X
                        b) optiunea Y
            apoi continua cu …
Cazul de utilizare Conversatie ar putea avea urmatoarea descriere:
1. Nume
            Conversatie
2. Scurta descriere.
            Clientii
preiau mesaje de la utilizatori, le trimit catre server,
care le difuzeaza catre toti clientii, iar acestia le prezinta catre utilizatori.
3. Actori 
            Utilizatori
4. Preconditii 
            Cazul de utilizare Conversatie s-a incheiat cu succes.
5. Evenimentul care declanseaza cazul de
utilizare.
            Un utilizator
scrie un mesaj in interfata grafica a clientului
sau.
6. Descriere a interactiunii dintre actori si cazul de utilizare
(Transmisie si receptie).
            I. Utilizatorul scrie
mesajul in interfata grafica a clientului
sau, clientul trimite mesajul la server. 
II. Clientul primeste
inapoi mesajul difuzat de server, si prezinta mesajul in interfata grafica a utilizatorului
7. Alternativa la cazul de utilizare principal (Doar receptie).
Clientul primeste
mesajul trims de alt utilizator,
mesaj difuzat de server, si prezinta mesajul in interfata grafica a utilizatorului sau.
8. Evenimentul care produce oprirea cazului de utilizare.
            Clientul a prezentat utilizatorului mesajul primit.
9. Postconditii 
            Sistemul este pregatit pentru ca utilizatorul sa poata continua conversatia cu alti
utilizatori prin intermediul interfetei grafice, sau pentru a incheia conversatia prin inchiderea
interfetei grafice.
Analiza domeniului detaliaza domeniul in care isi desfasoara
activitatea sistemul, stabilind clasele
cheie in sistem. Pentru
a realiza o analiza a domeniului, cititi specificatiile si cazurile de
utilizare si uitati-va care
"concepte" trebuie tratate de catre sistem. Sau, organizati o dezbatere cu utilizatorii si cu
expertii in domeniu pentru a incerca sa identificati toate conceptele
cheie care trebuie tratate, impreuna cu relatiile dintre ele.
Clasele
domeniului sunt doar "schitate" in acest stadiu. Operatiile si atributele definite nu
sunt cele finale. Ele sunt acelea
care par potrivite pentru aceste clase in acest moment. 
In cazul sistemului chat, urmatoarele clase pot fi considerate necesare:

Clasele identificate,
Client si Server pot deveni, in fazele de proiectare si implementare, prin detaliere, subsisteme.
Unele din operatiuni sunt definite prin schitarea diagramelor de secventa peste
cazurile de utilizare. Pentru a descrie comportamentul
dinamic al claselor domeniu, oricare din diagramele UML dinamice poate fi folosita: de secventa, de
colaborare, sau de activitati. 
Bazele diagramelor de secventa sunt
cazurile de utilizare,
unde fiecare caz de utilizare este descris cu impactul sau asupra claselor
domeniu, pentru a ilustra cum clasele domeniu colaboreaza pentru a realiza
cazul de utilizare in interiorul sistemului. 
Functionalitatile descrise prin cazuri de utilizare si detaliate
prin diagrame de secventa sunt dezvoltate
in continuare prin intermediul colaborarilor
intre obiectele domeniului. Prin simplificarea diagramelor de colaborare,
acestea sunt transformate in diagrame de obiecte. Obiectele fiind instante ale
claselor, diagramele de obiecte conduc in continuare la diagrame de clase.
Anumite clase au diagrame UML de stari care sa arate diferitele stari pe care
obiectele acelor clase le pot avea, impreuna cu evenimentele care le fac sa-si
schimbe starea.
In cazul sistemului chat, urmatoarea diagrama
de secventa poate modela comportamentul intregului sistem, in relatia
lui cu Utilizatorii, in cazul de utilizare Conversatie:

Diagrama de colaborare echivalenta diagramei de secventa anterioara este urmatoarea:

Daca utilizam cele doua clase identificate, Client si Server, se poate detalia
diagrama de secventa care modeleaza
comportamentul sistemului, in relatia lui cu Utilizatorii, in cazul de
utilizare Conversatie:

Diagrama de colaborare echivalenta diagramei de secventa anterioara este urmatoarea:

In aceasta faza, putem observa necesitatea existentei unor obiecte ale subsistemului Server care sa se ocupe cu tratarea fiecarui client in parte, sub forma clasei TratareClient, aflata in relatie de subordonare fata de clasa Server.

Se pot acum detalia suplimentar diagramele de secventa care modeleaza cazurile de utilizare Conectare
si Conversatie:

Diagrama de colaborare echivalenta diagramei de secventa anterioara este urmatoarea:


Cand modelam
cu diagrame de secventa, devine evident ce
ferestre sau dialoguri sunt necesare pentru a asigura o interfata actorilor. In analiza este suficient sa fie
constientizate ferestrele interfata care sunt necesare si identificarea
interfetelor de baza.
Interfata de utilizator detaliata nu este specificata la acest moment;
din nou, aceasta este doar o
schita a ceea ce interfata de utilizator include. Pentru a separa in
analiza clasele fereastra de clasele domeniu, clasele fereastra sunt grupate de obicei
intr-un pachet distinct. 
In cazul sistemului chat, se poate decide existenta unei interfete grafice formata dintr-o intrare de text pentru editarea
mesajelor de trimis, si o zona grafica de text pentru prezentarea mesajelor
receptionate de la server.
La acest moment, aplicatiei i se poate da, de
asemenea, un nume.
Proiectarea OO extinde si detaliaza modelul obtinut prin analiza tinand cont de toate implicatiile tehnice
si restrictiile. Scopul proiectarii este sa specifice o solutie care
functioneaza, care poate fi usor trecuta in cod de programare. Clasele definite
in analiza sunt detaliate si clase noi sunt adaugate pentru a rezolva ariile
tehnice, cum ar fi bazele de date, interfata cu utilizatorul, comunicatia,
dispozitivele si altele.
Proiectarea arhitecturii este o proiectare de nivel inalt, unde sunt definite pachetele (subsistemele), incluzand dependentele si mecanismele primare de comunicatie intre pachete. Desigur, scopul este o arhitectura limpede si simpla, unde sunt dependente putine si dependentele bidirectionale sunt evitate pe cat posibil.
O arhitectura
bine proiectata este baza unui sistem
usor extensibil si modificabil. Pachetele pot sa aiba fie preocuparea
manevrarii unui domeniu functional specific, fie a unui domeniu tehnic
specific. Este vital sa separam logica
aplicatiei (clasele domeniului) de logica tehnica astfel incat schimbarile
din oricare din aceste segmente sa poata fi realizate fara prea mare impact in
nici una din parti. 
Scopurile cheie, cand definim arhitectura, sunt identificarea si stabilirea unor reguli
pentru dependentele intre pachete, in asa fel incat sa nu fie creata nici o
dependenta bidirectionala intre pachete (se evita ca pachetele sa devina prea
strans integrate intre ele), si identificarea nevoii de biblioteci
standard si gasirea
bibliotecilor utilizabile. Bibliotecile disponibile pe piata de azi a
domeniilor tehnice sunt: interfata cu
utilizatorul, bazele de date,
sau comunicatiile, dar, mai
multe biblioteci specifice aplicatiei,
sunt asteptate, de asemenea, sa apara.
In cazul sistemului chat, urmatoarele biblioteci pot fi considerate necesare:
– biblioteca standard Java pentru comunicatii la nivel de socket-uri (java.net) 
– biblioteca extensie standard Java pentru interfete grafice avansate (javax.swing) si bibliotecile grafice asociate (java.awt si java.awt.event)
– biblioteca standard Java pentru fluxuri de intrare-iesire (java.io) 
– biblioteca standard Java pentru clase utilitare (java.util) 
Proiectarea
detaliata detaliaza
continutul pachetelor, in asa fel incat clasele sunt descrise destul de
amanuntit pentru a da specificatii clare programatorului care va crea codul
claselor. Modelele dinamice din UML sunt utilizate pentru a demonstra cum
obiectele claselor se comporta in situatii specifice.
Scopul proiectarii detaliate este sa descrie noile clase tehnice – clase
din interfata cu utilizatorul si din
pachetele bazei de date – si sa extinda si sa detalieze descrierea
claselor domeniului, care au fost deja schitate in analiza. Aceasta se face
creand noi diagrame de clase, diagrame de stare si diagrame dinamice (cum ar fi
cele de secventa, de colaborare si de activitate). 
Sunt aceleasi
diagrame ca cele folosite in analiza, dar aici ele sunt definite la un nivel tehnic si de detaliere
mai ridicat. Descrierile cazului de utilizare din analiza sunt folosite
pentru verificarea fiabilitatii cazurilor de utilizare in proiectare; iar
diagramele de secventa sunt folosite pentru a ilustra cum fiecare din cazurile
de utilizare este realizat tehnic in sistem.
Mai intai pot fi create diagrame UML de secventa (a mesajelor) si de colaborare (a obiectelor) de nivel inalt, care sa reflecte cazurile de utilizare sis a
detalieze aspecte tehnice legate de implementare.
Varianta de cel mai inalt nivel al diagramei de
secventa prezinta serverul in ansamblu,
fara a detalia interactiunile dintre el
si firele de tratare a clientilor.

Prima parte a diagramei de secventa a mesajelor,
scenariul Conectare, corespunde cazului
de utilizare Conectare, a doua parte
a diagramei, scenariul Conversatie,
corespunde cazului de utilizare Conversatie.
Scenariul Trimitere
si Receptie corespunde situatiei in care clientul curent preia un mesaj de
la utilizatorul sau, trimite mesajul catre server, firul de executie al
serverului care trateaza acest client difuzeaza mesajul, care e preluat
inclusiv de clientul utilizatorului curent si prezentat acestuia. 
Scenariul Receptie
corespunde situatiei in care clientul curent preia un mesaj de la server, mesaj
difuzat de un alt client, si prezinta mesajul utilizatorului sau.
Diagramele de secventa au ca echivalent (biunivoc) diagrame
de colaborare. Diagramele de secventa a mesajelor prezinta mai degraba
aspectul temporal, comportamental, al obiectelor implicate in colaborare, pe
cand diagramele de colaborare a obiectelor prezinta mai degraba aspectul
static, structural.
Altfel spus, este complicat sa se inteleaga
structura sistemului privind o diagrama de secventa complexa (cum este cazul nostru).
De asemenea, este complicat sa se inteleaga comportamentul sistemului privind o
diagrama de colaborare, dar numerotarea mesajelor poate simplifica intelegerea.
Diagrama de colaborare de cel mai inalt nivel,
care prezinta serverul in ansamblu, fara a detalia interactiunile dintre el si
firele de tratare a clientilor, este urmatoarea.

Pentru a avansa cu proiectarea, catre implementare, se poate trece la detalierea diagramelor de secventa si colaborare. Varianta diagramei
de secventa care prezinta serverul care
accepta conexiunile separat de firele de tratare a clientilor detaliaza
interactiunile interne serverului ca ansamblu.



Diagrama de colaborare care prezinta serverul care accepta conexiunile separat de firele de tratare a clientilor (echivalenta diagramei de secventa anterioare) este urmatoarea.

Se poate merge mai departe cu detalierea diagramelor UML de secventa
si de colaborare pentru sistemul chat, pe masura ce sunt decise
detalii de implementare (numele metodelor Java).
Diagrama de secventa pentru client se poate detalia, la nivel de apeluri de metode
Java, astfel:

Prima parte a diagramei de secventa a mesajelor
pentru client corespunde scenariului
Conectare, a doua parte a diagramei
corespunde scenariului Conversatie.
Diagrama de colaborare pentru client, echivalenta diagramei de secventa anterioara, este
urmatoarea.

Diagrama de secventa pentru server se poate detalia, la nivel de apeluri de metode
Java, astfel:

Prima parte a diagramei de secventa a mesajelor
pentru server si firele de tratare a clientilor corespunde
cazului de utilizare Conectare, a
doua parte a diagramei corespunde cazului de utilizare Conversatie.
Diagrama de colaborare pentru si firele de tratare a clientilor,
echivalenta diagramei de secventa anterioara este urmatoarea.

Se poate trece acum la crearea diagramelor UML de clase pentru sistemul chat in forma cea mai detaliata.
Diagrama de clase a clientului este urmatoarea:

Diagrama de clase a serverului este urmatoarea:

Comportamentul principalelor clase din sistem poate fi detaliat prin diagrame UML de stari (si tranzitii).
Diagrama de stari a clientului este urmatoarea:

Starea Conversatie a clientului poate fi detaliata pentru firul de executie care trateaza evenimentele din interfata grafica Swing:

Starea Conversatie
a clientului poate fi detaliata
pentru firul de executie care trateaza receptia mesajelor de la server:

Diagrama de stari a serverului este urmatoarea:

Diagrama de stari a firului de tratare a clientilor este urmatoarea:

O alternativa
la modelarea comportamentului prin diagrame de stari, este modelarea
lui prin diagrame UML de activitati.
Diagrama de activitati a clientului este urmatoarea:

In mod asemanator poate fi creata si o diagrama de
activitati a serverului.
Se observa ca diagramele
de activitati se aseamana cu organigramele, mijloace clasice de modelare a
algoritmilor.
Crearea proiectului interfetei cu utilizatorul ("felul cum arata ea") este o activitate speciala executata in timpul fazei de proiectare. Initiata in timpul fazei de analiza, aceasta este facuta separat, dar in paralel cu alte activitati de proiectare.
In cazul sistemului chat, se poate decide existenta unei interfete grafice formata dintr-o intrare de text (sub forma unei
linii) pentru editarea mesajelor de
trimis, si o zona grafica de text (multilinie si cu posibilitati de
defilare) pentru prezentarea mesajelor
receptionate de la server.
Iata cum ar putea arata o astfel de interfata grafica, pentru doi utilizatori aflati in conversatie:


Implementarea OO bazata pe generare automata a codului pornind de la modele UML obtinute in faza de proiectare (ingineria software directa – forward engineering) a facut obiectul lucrarii de laborator anterioare.
Aplicarea unui proces de dezvoltare iterativ este usurat de posibilitatea aplicarii ingineriei software inverse (reverse engineering), care consta in generarea modelului UML din cod sursa. Acest proces iterativ ia forma ingineriei software iterative (round-trip engineering).
Descrierile cazurilor de utilizare pot fi folosite pentru verificarea fiabilitatii cazurilor de utilizare in proiectare, iar diagramele de secventa din faza de proiectare pot fi folosite pentru a testa felul in care fiecare din cazurile de utilizare este realizat tehnic in sistem.
In continuare va fi prezentat codul sursa pentru clasele componente ale
sistemului chat (versiunea 1), mai intai in forma finala, apoi
doar partea de cod care poate fi
obtinuta prin generare automata a codului din diagramele de clasa ale modelului UML (versiunea 1).
O varianta evoluata de cod sursa (versiunea 1+).
Codul sursa al clientului de chat (versiunea 1):
(rulat local cu fisierul batch)
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | import java.net.*;               // ClientDeChat_v1.java import java.io.*; import java.util.*; import java.awt.*; import
  java.awt.event.*; import javax.swing.*; import
  java.util.Properties; /**  * Client de chat simplu - aplicatie de sine
  statatoare  * Aplicatie
  grafica Swing (extinde JFrame)   * care poate
  lansa in executie un fir nou (implementeaza Runnable)  */ public class ClientDeChat_v1 extends JFrame implements
  Runnable {   private Properties proprietatiSistem;   private
  String numeUser;   private
  String adresaLocala;   private
  int portLocal;      /** 
  Flux de intrare dinspre retea */   private
  DataInputStream inRetea;      /**    * Zona de text (configurata ca
  non-editabila)    */   private JTextArea outTextGrafic;      /**    * Intrare de
  text (editabila)    */   private
  JTextField inTextGrafic;      /**    * Fir de executie    */   private
  Thread firReceptie;      /**    * Socket flux (TCP)    */   private
  static Socket socket;      /**    * Flux de
  iesire catre retea    */   private DataOutputStream outRetea;   private
  InetAddress localHost;      /**    * Initializeaza obiectul de tip
  ClientDeChat_v1    * @param
  title      Titlul ferestrei    * @param inRetea    Flux de intrare dinspre retea    * @param outRetea   Flux de iesire catre retea    */   public
  ClientDeChat_v1(String title, InputStream inRetea,                                         OutputStream outRetea) {     // Stabilire titlu fereastra (JFrame)     super
  (title);                                  
       this.inRetea = new DataInputStream (new
  BufferedInputStream (inRetea));     this.outRetea = new DataOutputStream (new
  BufferedOutputStream (outRetea));    
  Container containerCurent = this.getContentPane();    
  containerCurent.setLayout(new BorderLayout());     // Zona de text non-editabila de iesire (cu posibilitati de defilare)     outTextGrafic = new JTextArea(8, 40);    
  JScrollPane scrollPane = new JScrollPane(outTextGrafic,                                 
  JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,                                   JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);     containerCurent.add("Center", scrollPane);     outTextGrafic.setEditable
  (false);     // Camp de text editabil de intrare     inTextGrafic = new JTextField(40);    
  containerCurent.add("South", inTextGrafic);     // Variabila locala finala (folosita in clasa interna anonima de tip      // ActionListener)     final
  DataOutputStream outR = this.outRetea;     //
  Crearea unui "ascultator" de "evenimente actionare"     
  ActionListener ascultatorInText = new ActionListener() {       // Tratarea actionarii intrarii de text
  (apasarea tastei "Enter")       public
  void actionPerformed(ActionEvent ev) {         // Citire mesajului din intrarea de
  text        
  String intrare = inTextGrafic.getText();                          try
  {                                 // Scrierea mesajului pe fluxul de
  iesire spre retea              outR.writeUTF(numeUser + "
  [" + adresaLocala + ":" + portLocal +                          "]> " +
  intrare);            // Fortarea trimiterii mesajului
  (fortarea golirii bufferului)           outR.flush ();                    }          // In cazul unei erori legata de
  conexiune        
  catch (IOException ex) {           // Afisarea exceptiei          
  ex.printStackTrace();           
  // Inchiderea firului de executie care efectueaza receptia          
  firReceptie.stop ();              }         // Pregatirea intrarii de text pentru
  noul mesaj (golirea intrarii)         inTextGrafic.setText ("");        }     
       };     // Inregistrarea
  "ascultatorului" de "evenimente actionare" la      // "obiectul sursa" intrare
  text      inTextGrafic.addActionListener(ascultatorInText);     // Crearea unui "adaptor pentru ascultator" de
  "evenimente fereastra"     
  WindowAdapter ascultatorInchidere = new WindowAdapter() {       // Tratarea inchiderii ferestrei
  curente       public
  void windowClosing(WindowEvent ev) {         // Daca mai exista firul de executie de receptie         if (firReceptie != null) {           // Inchiderea firului de receptie           
  firReceptie.stop ();                  
           }         //
  Terminarea programului         System.exit(0);                                           }     };     //
  Inregistrarea "ascultatorului" de "evenimente fereastra"
  la "sursa"      // (fereastra curenta)    
  this.addWindowListener(ascultatorInchidere);     // Impachetarea (compactarea)
  componentelor in container    
  pack();                         
       // Fereastra devine vizibila - echivalent cu frame.setVisible(true)     show();                          // Cerere focus pe intrarea de text din
  fereastra curenta          inTextGrafic.requestFocus();     // Fir de
  executie pentru receptia mesajelor de la server     firReceptie = new Thread (this);      // Lansarea firului de executie - se
  executa run()       
  firReceptie.start ();      }      /**    * Metoda
  principala a firului care receptioneaza mesaje de la server    */   public void run() {          try {       // Obtinerea obiectului care incapsuleaza
  proprietatile sistemului de        // operare (obtinerea variabilelor
  mediului de executie)      
  proprietatiSistem = System.getProperties();       // Obtinerea valorii variabilei de mediu
  "USER"       numeUser =
  proprietatiSistem.getProperty("user.name");       // Obtinerea adresei locale ca obiect
  InetAddress      
  localHost = InetAddress.getLocalHost();       // Obtinerea formei String a adresei locale       adresaLocala =
  localHost.getHostAddress();       //
  Obtinerea numarului de port local       portLocal =
  socket.getLocalPort();       //
  Tratarea mesajelor serverului (citirea si interpretarea lor)       while
  (true) {                                
           // Citirea mesajului din fluxul de
  intrare dinspre server        
  String line = inRetea.readUTF
  ();                 // Adaugarea textului primit in
  iesirea de text             outTextGrafic.append (line +
  "\n");             }     }      // In cazul unei erori legata de
  conexiune     catch (IOException ex) {             // Afisarea
  exceptiei       ex.printStackTrace ();                }      // Curatenie finala     finally {                                             //
  Inchiderea firului de receptie curent       firReceptie = null;                                   //
  Ascunderea intrarii de text       inTextGrafic.setVisible(false);                       //
  Reasezarea interfetei grafice       validate ();                                          try {         //
  Inchiderea fluxului de iesire spre retea         outRetea.close
  ();                                    }        // In cazul unei erori legata de
  conexiune       catch (IOException ex) {         // Afisarea exceptiei         ex.printStackTrace ();       }     }  
     }         /**    * Metoda principala - creaza socketul,
  fluxurile si lanseaza clientul    * @param
  args[]    * @param args    * @throws
  java.io.IOException    */   public static void main(java.lang.String[]
  args) throws IOException {        if
  (args.length != 2)       throw
  new RuntimeException ("Sintaxa: ClientDeChat_v1 <host>
  <port>");     // Adresa serverului - primul parametru primit din
  linia de comanda     String adresaServer = args[0];     // Portul
  serverului - al doilea parametru primit din linia de comanda     int portServer = Integer.parseInt
  (args[1]);     // Crearea socketului catre server      socket = new Socket (adresaServer, portServer);    
  System.out.println ("Client TCP lansat catre server [" +                     
  socket.getInetAddress() + ":" + socket.getPort() +
  "]...");    
  System.out.println ("pe portul local: " +
  socket.getLocalPort());     // Crearea fluxurilor, crearea si
  lansarea clientului grafic      new
  ClientDeChat_v1 ("Client pe portul " + socket.getLocalPort() +                           " pentru serverul [" + args[0] +
  ":" + args[1] + "]",                       socket.getInputStream
  (), socket.getOutputStream ());      } } | 
Codul sursa al clientului de chat care poate obtinut prin generare automata din diagrama
de clase:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | //Source file: ClientDeChat_v1.java (cod generat din
  diagrama UML) import java.net.*; import java.io.*; import java.util.*; import java.awt.*; import
  java.awt.event.*; import javax.swing.*; import
  java.util.Properties; /**  * Client de chat simplu - aplicatie de sine
  statatoare  * Aplicatie grafica Swing (extinde JFrame)   * care poate lansa in executie un fir nou
  (implementeaza Runnable)  */ public class ClientDeChat_v1 extends JFrame implements
  Runnable {   private Properties proprietatiSistem;   private
  String numeUser;   private
  String adresaLocala;   private
  int portLocal;      /**    * Flux de
  intrare dinspre retea    */   private
  DataInputStream inRetea;      /**    * Zona de
  text (configurata ca non-editabila)    */   private JTextArea outTextGrafic;      /**    * Intrare de text (editabila)    */   private
  JTextField inTextGrafic;      /**    * Fir de
  executie    */   private
  Thread firReceptie;   /**    * Socket
  flux (TCP)    */   private
  static Socket socket;      /**    * Flux de iesire catre retea    */   private DataOutputStream outRetea;   private
  InetAddress localHost;      /**    * Initializeaza obiectul de tip
  ClientDeChat_v1    * @param title     
  Titlul ferestrei    * @param
  inRetea    Flux de intrare dinspre
  retea    * @param
  outRetea   Flux de iesire catre retea    */   public ClientDeChat_v1(String
  title,InputStream inRetea,OutputStream outRetea) {   }      /**    * Metoda principala a firului care
  receptioneaza mesaje de la server    */   public void run()
  {       }      /**    * Metoda principala - creaza socketul,
  fluxurile si lanseaza clientul    * @param args[]    * @param args    * @throws java.io.IOException    */   public static
  void main(java.lang.String[] args) throws IOException {       } } | 
_________________________________________________________________
Codul sursa al serverului de chat (versiunea 1):
(rulat local cu fisierul batch)
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | import java.net.*;          // ServerDeChat_v1.java import java.io.*; import java.util.*; /**  * Server chat simplu - componenta server
  pentru noi conexiuni  */ public class
  ServerDeChat_v1 {   private
  TratareClientDeChat_v1 firTratare;   private
  Socket socket;      /**    * @param port    * @throws java.io.IOException    */   public ServerDeChat_v1(int port) throws
  IOException {     // Server pentru asteptarea cererilor de
  conectare    
  ServerSocket server = new ServerSocket (port);     System.out.println ("Server TCP lansat pe port " + port  + "...");     // Bucla
  infinita     while (true) {       //
  Asteptarea cererilor de conectare si returnarea unui nou socket       Socket client = server.accept ();       System.out.println ("Acceptata
  conexiunea de la: [" +                    client.getInetAddress() +
  ":" + client.getPort() + "]...");       System.out.println ("pe portul
  local: " + client.getLocalPort());       // Crearea unui fir de executie pentru
  tratare client nou       firTratare = new TratareClientDeChat_v1 (client);        // Lansarea firului de executie - se va executa: firTratare.run()       firTratare.start ();                               }      }      /**    * @param args    * @throws java.io.IOException    */   public static void main(java.lang.String[]
  args) throws IOException {     if
  (args.length != 1)       throw
  new RuntimeException ("Sintaxa: ServerDeChat_v1
  <numarPort>");     new
  ServerDeChat_v1 (Integer.parseInt (args[0]));      } } | 
Codul sursa al serverului de chat care poate obtinut prin generare automata din diagrama
de clase:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | //Source file: 
  ServerDeChat_v1.java /**  * Server chat simplu - componenta server pentru
  noi conexiuni  */ import java.net.*; import java.io.*; import java.util.*; public class
  ServerDeChat_v1 {   private
  TratareClientDeChat_v1 firTratare;   private
  Socket socket;      /**    * @param port    * @throws java.io.IOException    */   public ServerDeChat_v1(int port) throws
  IOException {       }      /**    * @param
  args    * @throws
  java.io.IOException    */   public static void main(java.lang.String[]
  args) throws IOException {   } } | 
_________________________________________________________________
Codul sursa al firului de tratare al
clientului de
chat (versiunea 1):
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | import java.net.*; // TratareClientTextChat_v1.java import java.io.*; import java.util.*; import
  java.util.Vector; /**  * Server chat simplu - componenta de tratare
  a unei conexiuni  */ public class
  TratareClientTextChat_v1 extends Thread {      /**    * Vector de referinte la obiecte care
  trateaza clienti (ptr. inregistrare)    */   private
  static Vector listaFire = new Vector ();      /**    * Socket flux (TCP)    */   private
  Socket socket;      /**    * Flux de
  intrare dinspre retea    */   private DataInputStream inRetea;      /**    * Flux de
  iesire catre retea    */   private DataOutputStream outRetea;      /**    * Initializeaza obiectul (firul) care
  trateaza un nou client    * @param
  socket    * @throws java.io.IOException    */   public TratareClientTextChat_v1(Socket
  socket) throws IOException {    
  this.socket = socket;     inRetea
  = new DataInputStream (new                        BufferedInputStream
  (socket.getInputStream ()));     outRetea
  = new DataOutputStream (new                        BufferedOutputStream
  (socket.getOutputStream ()));      }      /**    * Metoda
  principala a firului de executie.    * Primeste mesajele si apeleaza difuzarea lor.    */   public void run() {                           try {       // Inregistrarea firului curent in
  lista (Vector)      
  listaFire.addElement (this);          
        
  System.out.print("\nNou fir de executie ...");      
  System.out.println(this.toString());      
  System.out.println(listaFire.toString()+"\n");       //
  Tratarea mesajelor clientului (citirea si difuzarea mesajelor)       while
  (true) {                                  // Citirea mesajului din fluxul de intrare de la client         String mesaj = inRetea.readUTF ();         // Difuzarea catre toti clientii
  curent inregistrati         difuzare (mesaj);                   
         }     }      // In cazul unei erori legata de conexiune     catch (IOException ex) {             // Afisare
  exceptie       ex.printStackTrace ();                }      //
  Curatenie finala     finally
  {                                 // Eliminarea firului curent din lista
  (Vector)      
  listaFire.removeElement (this); 
         System.out.print("\nFir de executie eliminat...");       System.out.println(this.toString());      
  System.out.println(listaFire.toString()+"\n");       try {         // Inchiderea socketului        
  socket.close ();                      }        // In cazul
  unei erori legata de conexiune       catch (IOException ex) {               //
  Afisarea exceptiei         ex.printStackTrace ();                  }      }      }      /**    * Difuzeaza mesajul primit catre clienti    * @param mesaj    */   private static void difuzare(String mesaj)
  {        // Enumerare creata pornind de la lista
  firelor de executie        
  Enumeration enum = listaFire.elements ();                // Cat timp mai sunt elemente in
  enumerare     while
  (enum.hasMoreElements ()) {                   // Referinta catre firul curent initializata cu null       TratareClientTextChat_v1 firDestinatie
  = null;                            //
  Protectie la acces concurent la Vectorul firelor       synchronized (listaFire) {                            // Obtinerea referintei catre firul
  curent          firDestinatie = (TratareClientTextChat_v1) enum.nextElement ();         }                                                 // Daca referinta e valida       if
  (firDestinatie  != null) {                                   try {          //
  Protectie la acces concurent la fluxul de iesire          synchronized
  (firDestinatie.outRetea) {                         //
  Scrierea mesajului in fluxul de iesire al firului curent             firDestinatie.outRetea.writeUTF
  (mesaj);                 }           //
  Fortarea trimiterii mesajului           firDestinatie.outRetea.flush
  ();                           }          // In
  cazul unei erori legata de conexiune         catch (IOException ex) {           //
  Inchiderea firului curent           firDestinatie.stop ();                                     }       }     }  
     } } | 
Codul sursa al firului de tratare al clientului de chat
care poate obtinut prin generare
automata din diagrama de clase:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | //Source file: TratareClientDeChat_v1.java /**  * Server chat simplu - componenta de tratare
  a unei conexiuni  */ import java.net.*; import java.io.*; import java.util.*; import
  java.util.Vector; public class
  TratareClientDeChat_v1 extends Thread {      /**    * Vector
  de referinte la obiecte care trateaza clienti (ptr. inregistrare)    */   private
  static Vector listaFire = new Vector ();      /**    * Socket
  flux (TCP)    */   private
  Socket socket;      /**    * Flux de intrare dinspre retea    */   private DataInputStream inRetea;      /**    * Flux de iesire catre retea    */   private DataOutputStream outRetea;      /**    * Initializeaza obiectul (firul) care
  trateaza un nou client    * @param socket    * @throws java.io.IOException    */   public TratareClientDeChat_v1(Socket
  socket) throws IOException {       }      /**    * Metoda principala a firului de executie.    * Primeste mesajele si apeleaza difuzarea
  lor.    */   public void run() {       }      /**    *
  Difuzeaza mesajul primit catre clienti    * @param
  mesaj    */   private static void difuzare(String mesaj)
  {       } } | 
_________________________________________________________________