(varianta pdf)

SwRTc – Proiect

Procesul dezvoltarii unui sistem software orientat spre obiecte (II)

 

P.2. Utilizarea diagramelor UML ca suport pentru procesul de dezvoltare a unui sistem software (II)

 

P.2.1. Evaluarea versiunii anterioare a sistemului software OO

 

 

Dezvoltarea sistemelor software complexe este de obicei realizata in mai multe iteratii in care:

- sunt reluate activitatile de analiza, proiectare, implementare, testare,

- sunt adaugate activitatile de

- evaluare a iteratiei anterioare si de

- planificare a iteratiilor ulterioare.

 

Rezultatele iteratiei anterioare sunt fie o versiune a sistemului software, fie doar un prototip al acestuia.

 

Evaluarea rezultatelor iteratiei anterioare consta, printre altele, din:

- verificarea functionarii corecte a sistemului (conformitatii cu specificatiile),

- evaluarea documentatiei si a codului (analiza codului),

- evaluarea gradului in care versiunea obtinuta corespunde asteptarilor utilizatorilor.

 

 

In ceea ce priveste evaluarea sistemului de comunicatie pentru conversatie textuala, dezvoltat in iteratia anterioara, pot fi facute, printre altele, urmatoarele observatii:

- interfata grafica este rudimentara, modul de conectare la server putand fi imbunatatit,

- utilizatorii sunt identificati pe baza numelui de utilizator de pe masina pe care ei lanseaza componentele client, in loc sa isi poata alege un nume de utilizator al sistemului de conversatie (nickname)

- bara de defilare a zonei de text ar fi preferabil sa fie in mod automat actualizata astfel incat sa fie vizibile intotdeauna ultimele mesaje primite,

- utilizatorii nu au nici o informatie despre ceilalti utilizatori prezenti in conversatie

- pe un server poate exista doar un singur grup de utilizatori la un moment dat (alternativa ar fi posibilitatea crearii unor “camere”, grupuri, etc.)

- nu exista posibilitatea crearii unor canale de comunicatie private, pentru conversatia intre 2 utilizatori

- etc. (lista va fi largita prin discutii la laborator/proiect).

 

 

 

P.2.2. Actualizarea cerintelor sistemului

 

In urma acestei evaluari, presupunem ca s-a decis ca in iteratia urmatoare sa fie realizate urmatoarele imbunatatiri:

- posibilitatea oferita utilizatorilor de a-si alege un nume de utilizator (nickname)

- actualizarea automata a barei de defilare a zonei de text pentru ca ultimele mesaje primite sa fie vizibile

- difuzarea de catre server a numelor de utilizator catre toti utilizatorii si informarea de catre client a utilizatorilor despre modificarile in componenta grupului de utilizatori

 

Desigur, raman nerezolvate anumite posibile cerinte ale utilizatorilor, cum ar fi

- posibilitatea crearii mai multor “camere” sau grupuri pe un server

- posibilitatea crearii unor canale de comunicatie private

- etc (lista va fi largita prin discutii la laborator/proiect).

 

P.2.3. Actualizarea analizei OO a sistemului

 

Actualizarea analizei OO presupune:

- actualizarea diagramei UML a cazurilor de utilizare,

- actualizarea descrierii cazurilor de utilizare

- actualizarea listei claselor principale ale sistemului

- actualizarea diagramelor UML de secventa care descriu scenariile componente ale cazurilor de utilizare

- actualizarea diagramelor UML de colaborare corespunzatoare

 

Varianta de nivel inalt a diagramei de secventa pentru scenariul conectarii unui nou client.

 

 

Varianta de nivel inalt a diagramei de secventa pentru scenariul deconectarii unui client.

 

 

Varianta de nivel inalt a diagramei de secventa pentru scenariul conversatiei intre clienti.

 

 

 

 

 

P.2.4. Actualizarea proiectarii sistemului

 

Actualizarea proiectarii OO presupune:

- actualizarea proiectarii interfetei grafice cu utilizatorul

- actualizarea diagramelor UML de secventa si de colaborare

- actualizarea diagramelor UML de clase

- actualizarea diagramelor UML de stari

- actualizarea diagramelor UML de activitati

 

Interfata grafica prezentata initial unui nou utilizator, pentru alegerea numelui in vederea conectarii, este o fereastra de dialog:

 

In cazul in care utilizatorul propune un nume care exista deja in lista serverului, acesta respinge inregistrarea iar clientul prezinta urmatoarea fereastra de dialog:

 

Presupunem urmatorul scenariu:

- primul utilizator isi alege numele isw2004,

- al doilea utilizator isi alege numele swrtc2004 (moment in care ambii utilizatori sunt informati, unul de existenta celuilalt),

- cei doi utilizatori schimba cateva mesaje,

- se conecteaza al treilea utilizator, care isi alege numele rtc2004 (moment in care primii doi utilizatori sunt informati de existenta celui de-al treilea, iar acesta de existenta celorlalti doi),

- cei trei utilizatori schimba cateva mesaje,

- utilizatorul cu numele swrtc2004 paraseste conversatia (moment in care ceilalti doi utilizatori sunt informati).

 

 

Continutul interfetei grafice pentru cei trei utilizatori va fi urmatorul:

- pentru utilizatorul cu numele swrtc2004:

 

 

- pentru utilizatorul cu numele isw2004:

 

 

- pentru utilizatorul cu numele rtc2004:

 

 

Diagrama de clase actualizata a clientului este urmatoarea:

 

 

 

 

 

Diagrama de clase actualizata a serverului este urmatoarea:

P.2.5. Actualizarea implementarii OO a sistemului

 

Codul sursa Java pentru clientul de chat (si fisierul pentru compilarea si lansarea clientului)

 

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

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

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

//Source file: ClientDeChat_v2.java

 

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_v2 extends JFrame implements Runnable {

  private String numeUser;

  private String adresaLocala;

  private int portLocal;

 

  /**

   * Vector de obiecte cu informatii privind ceilalti clienti

   */

  private static Vector altiClienti = new Vector ();

 

  /**

   * 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 iaLocala;

 

  JScrollBar baraDefilareVerticala;

 

  /**

   * 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_v2(String title, InputStream inRetea,

                                       OutputStream outRetea) {

    // Stabilire titlu fereastra (JFrame)

    super();                                  

    // ----------------------------------------------------------------

    // Trimiterea catre server a informatiilor privind clientul

    // ----------------------------------------------------------------

 

    this.inRetea = new DataInputStream (new BufferedInputStream (inRetea));

    this.outRetea = new DataOutputStream (new BufferedOutputStream (outRetea));

 

    // -----------------------------------------------------------------------

    // Afisarea in consola si trimiterea catre server a info. privind clientul

    // -----------------------------------------------------------------------

 

    // Obtinerea numarului de port local

    portLocal = this.socket.getLocalPort();

 

    try {                     

      // Obtinerea adresei locale ca obiect InetAddress

      iaLocala = InetAddress.getLocalHost();

 

      // Obtinerea formei String a adresei locale

      adresaLocala = iaLocala.getHostAddress();

 

      System.out.println("\n Clientul are adresa " + adresaLocala +

                         " si portul " + portLocal);

 

      // Scrierea adresei IP pe fluxul de iesire spre retea

      this.outRetea.writeUTF(adresaLocala);

 

      // Scrierea portului TCP pe fluxul de iesire spre retea

      this.outRetea.writeInt(portLocal);

 

      // --------------------------------------------------------------

      // Trimiterea (si eventual modificarea) numelui utilizatorului

      // --------------------------------------------------------------

 

      boolean existaDeja;

 

      String mesajDialog = "Alegeti numele de utilizator!";

 

 

 

      do {

        // Alegerea numelui de utilizator

        numeUser = JOptionPane.showInputDialog(mesajDialog);

 

        // Scrierea numelui utilizatorului pe fluxul de iesire spre retea

        this.outRetea.writeUTF(numeUser);

        // Fortarea trimiterii (fortarea golirii bufferului)

        this.outRetea.flush ();          

 

        // Citirea rezultatului din fluxul de intrare dinspre retea

        String rezultat = this.inRetea.readUTF();          

 

        existaDeja = rezultat.equals("Numele a fost deja alocat");

 

        mesajDialog = "Numele ales exista deja. Alegeti alt nume!";

 

      } while (existaDeja);

 

      System.out.println("\n Clientul are numele " + numeUser);

    }

 

    // --------------------------------------------------------------

    // Tratarea erorilor de conexiune

    // --------------------------------------------------------------

    catch (IOException ex) {

      // Afisarea exceptiei

      ex.printStackTrace();

    }

 

    // --------------------------------------------------------------

    // Initializari grafice

    // --------------------------------------------------------------

    this.setTitle("Client  " + numeUser + " : " + title);

 

    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 panouDefilabil = new JScrollPane(outTextGrafic,

                                 JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,

                                 JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);

    baraDefilareVerticala = panouDefilabil.getVerticalScrollBar();

    containerCurent.add("Center", panouDefilabil);

    outTextGrafic.setEditable (false);

 

    // Camp de text editabil de intrare

    inTextGrafic = new JTextField(40);

    containerCurent.add("South", inTextGrafic);

 

    System.out.println("\n Configurata interfata grafica \n");     

 

    // --------------------------------------------------------------

    // Tratarea evenimentelor interfetei grafice (intrarea de text)

    // --------------------------------------------------------------

 

    // 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 = null;    

        }

        // Pregatirea intrarii de text pentru noul mesaj (golirea intrarii)

        inTextGrafic.setText ("");

      }     

    };

 

    // Inregistrarea "ascultatorului" de "evenimente actionare" la

    // "obiectul sursa" intrare text

    inTextGrafic.addActionListener(ascultatorInText);

 

    // ----------------------------------------------------------------

    // Tratarea evenimentelor interfetei grafice (inchiderea ferestrei)

    // ----------------------------------------------------------------

    // 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 = null;                  

        }

        // Terminarea programului

        System.exit(0);                                    

      }

    };

    // Inregistrarea "ascultatorului" de "evenimente fereastra" la "sursa"

    // (fereastra curenta)

    this.addWindowListener(ascultatorInchidere);

 

    // --------------------------------------------------------------

    // Lansarea interfetei grafice

    // --------------------------------------------------------------

 

    // 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();

 

    // --------------------------------------------------------------

    // Lansarea firului de executie de receptie

    // --------------------------------------------------------------

 

    // 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() {    

 

    // --------------------------------------------------------------

    // Tratarea mesajelor serverului (citirea si interpretarea lor)

    // --------------------------------------------------------------

    try {

      while (true) {                                

        // Citirea mesajului din fluxul de intrare dinspre server

        String line = inRetea.readUTF ();       

 

        // --------------------------------------------------------------

        // Inregistrarea unui client nou sau preexistent

        // --------------------------------------------------------------

 

        if (line.equals("Client nou")) {

          // Citirea mesajului din fluxul de intrare dinspre server

          String numeClient = inRetea.readUTF ();       

          // Citirea mesajului din fluxul de intrare dinspre server

          String adresaClient = inRetea.readUTF ();       

          // Citirea mesajului din fluxul de intrare dinspre server

          int portClient = Integer.parseInt(inRetea.readUTF());       

 

          // Incapsularea informatiilor privind clientul

          InfoClient clientNou = new

                        InfoClient(numeClient, adresaClient, portClient);

 

          // Inregistrarea clientului curent in lista (Vector)

          altiClienti.addElement (clientNou);          

 

          System.out.println("Client nou: " + numeClient +

                             " [" + adresaClient +

                             " : " + portClient + "]");

 

          System.out.println("Lista clientilor:\n" + altiClienti.toString());

 

          // Anuntarea in iesirea de text a noului client    

          outTextGrafic.append ("Participa la conversatie si: " + numeClient +

                             " [" + adresaClient +

                             " : " + portClient + "] \n");     

        }

 

        // ---------------------------------------------------------------

        // Eliminarea inregistrarii unui client care a parasit conversatia

        // ---------------------------------------------------------------

 

        else if (line.equals("Client eliminat")) {

          // Citirea mesajului din fluxul de intrare dinspre server

          String numeClient = inRetea.readUTF ();       

          // Citirea mesajului din fluxul de intrare dinspre server

          String adresaClient = inRetea.readUTF ();       

          // Citirea mesajului din fluxul de intrare dinspre server

          int portClient = Integer.parseInt(inRetea.readUTF());       

 

          // Incapsularea informatiilor privind clientul

          InfoClient clientEliminat = new

                        InfoClient(numeClient, adresaClient, portClient);

 

          altiClienti.removeElement (clientEliminat); 

 

          System.out.println("Client eliminat: " + numeClient +

                             " [" + adresaClient +

                             " : " + portClient + "]");

 

          System.out.println("Lista clientilor:\n" + altiClienti.toString());

 

          // Anuntarea in iesirea de text a eliminarii clientului

          outTextGrafic.append ("A parasit conversatia: " + numeClient +

                             " [" + adresaClient +

                             " : " + portClient + "] \n");     

        }

 

        // --------------------------------------------------------------

        // Afisarea mesajului (propriu-zis) receptionat

        // --------------------------------------------------------------

 

        else {

          // Adaugare textului primit in iesirea de text   

          outTextGrafic.append (line + "\n");     

        }

 

        // Solutie pentru a avea afisate intotdeauna ultimele

        // mesaje primite (exista o solutie alternativa???)

        int zonaVizibila = baraDefilareVerticala.getVisibleAmount();

        int valoareaMaxima = baraDefilareVerticala.getMaximum();

 

        baraDefilareVerticala.setValue(valoareaMaxima - zonaVizibila);

        validate();

        repaint();

      }

    }

 

    // --------------------------------------------------------------

    // Tratarea erorilor 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 {

 

    // Adresa serverului

    String adresaServer =

             JOptionPane.showInputDialog("Introduceti adresa serverului");

 

    // Portul serverului

    String numarPort = JOptionPane.showInputDialog(

                           "Introduceti numarul de port al serverului");

 

    int portServer = Integer.parseInt(numarPort);

 

 

    // Crearea socketului catre server

    socket = new Socket (adresaServer, portServer);

 

    System.out.println ("\n Client TCP lansat catre serverul  [" +

                    socket.getInetAddress() + ":" + socket.getPort() + "]");

 

    // Crearea fluxurilor, crearea si lansarea clientului grafic

    new ClientDeChat_v2 (socket.getLocalPort() +

                  "  (Server  " + adresaServer + " : " + numarPort + ")",

                     socket.getInputStream (), socket.getOutputStream ());  

 

  }

}

 

class InfoClient {

  String nume;

  String adresa;

  int port;

  Thread fir;

 

  /**

   * @param nume

   * @param adresa

   * @param port

   * @param fir

   */

  public InfoClient(String nume, String adresa, int port, Thread fir) {

    this.nume = nume;

    this.adresa = adresa;

    this.port = port;

    this.fir = fir;  

  }

 

  /**

   * @param nume

   * @param adresa

   * @param port

   * @param fir

   */

  public InfoClient(String nume, String adresa, int port) {

    this.nume = nume;

    this.adresa = adresa;

    this.port = port;

    this.fir = null;  

  }

 

  public void setFir(Thread fir) {

    this.fir = fir;  

  }

 

  /**

   * @return java.lang.String

   */

  public String toString() {

    return "\t" + nume + "/" + adresa + ":" + port + "\n";  

  }

 

  /**

   * @return boolean

   */

  public boolean equals(Object obj) {

    if ((obj != null) && (obj instanceof InfoClient)) {

      InfoClient celalaltClient = (InfoClient)obj;

      return ((this.nume.equals(celalaltClient.nume)) &&

              (this.adresa.equals(celalaltClient.adresa)) &&

              (this.port == celalaltClient.port));

    }

    return false;

  }

}

 

 

Codul sursa Java pentru serverul de chat (si fisierul pentru compilarea si lansarea serverului)

 

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

//Source file: ServerDeChat_v2.java

 

/**

 * Server chat simplu - componenta server pentru noi conexiuni

 */

import java.net.*;

import java.io.*;

import java.util.*;

 

public class ServerDeChat_v2 {

  private TratareClientDeChat_v2 firTratare;

  private Socket socket;

 

  public ServerDeChat_v2(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().getHostAddress() + "(" +

                           client.getInetAddress().getHostName() + ")" +

                           ":" + client.getPort() + "]...");

      System.out.println ("pe portul local: " + client.getLocalPort());

 

      // Crearea unui fir de executie pentru tratare client nou

      firTratare = new TratareClientDeChat_v2 (client);

 

      // Lansarea firului de executie - se va executa: firTratare.run()

      firTratare.start ();                        

     }  

  }

 

  public static void main(java.lang.String[] args) throws IOException {

    if (args.length != 1)

      throw new RuntimeException ("Sintaxa: ServerDeChat_v2 <numarPort>");

 

    new ServerDeChat_v2 (Integer.parseInt (args[0]));  

  }

}

 

Codul sursa Java pentru firul de tratare a clientului de chat.

 

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

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

//Source file: TratareClientDeChat_v2.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_v2 extends Thread {

 

  /**

   * Vector de referinte la obiecte care trateaza clienti (ptr. inregistrare)

   */

  private static Vector listaClienti = new Vector ();

 

  /**

   * Socket flux (TCP)

   */

  private Socket socket;

 

  /**

   * Flux de intrare dinspre retea

   */

  private DataInputStream inRetea;

 

  /**

   * Flux de iesire catre retea

   */

  private DataOutputStream outRetea;

  private InfoClient client;

 

 

  /**

   * Initializeaza obiectul (firul) care trateaza un nou client

   * @param socket

   * @throws java.io.IOException

   */

  public TratareClientDeChat_v2(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 {

 

      // ----------------------------------------------------------------

      // Obtinerea informatiilor de la client

      // ----------------------------------------------------------------

 

      // Citirea adresei clientului din fluxul de intrare de la client

      String adresaClient = inRetea.readUTF();

 

      // Citirea portului clientului din fluxul de intrare de la client

      int portClient = inRetea.readInt();

 

      // ----------------------------------------------------------------------

      // Obtinerea si verificarea (eventual modificarea) numelui utilizatorului

      // ----------------------------------------------------------------------

      // Numele clientului

      String numeClient;

 

      // Rezultatul verificarii existentei numelui in lista

      boolean existaDeja;

 

      // Receptia numelui si eventuala cerere de modificare

      do {

        // Citirea numelui clientului din fluxul de intrare de la client

        numeClient = inRetea.readUTF();

 

        existaDeja = false;

 

        // Enumerare creata pornind de la lista clientilor   

        Enumeration enum = listaClienti.elements ();          

 

        // Cat timp mai sunt elemente in enumerare

        while (enum.hasMoreElements ()) {           

 

          // Protectie la acces concurent la Vectorul clientilor

          synchronized (listaClienti) {              

  

            // Obtinerea informatiilor privind clientul curent tratat

            InfoClient infoClient = (InfoClient) enum.nextElement(); 

 

            if (numeClient.equals(infoClient.nume)) {

              existaDeja = true;

              break;

            }

          }                                         

        }  

        if (existaDeja) {

          // Scrierea mesajului in fluxul de iesire al firului curent

          outRetea.writeUTF("Numele a fost deja alocat");     

        }

        else {

          // Scrierea mesajului in fluxul de iesire al firului curent

          outRetea.writeUTF("Client inregistrat");     

        }

        // Fortarea trimiterii

        outRetea.flush();     

 

      } while (existaDeja);

 

      // -------------------------------------------------------------------

      // Trimiterea listei clientilor deja existenti (catre clientul tratat)

      // -------------------------------------------------------------------

 

      // Enumerare creata pornind de la lista clientilor   

      Enumeration enum = listaClienti.elements ();          

 

      // Cat timp mai sunt elemente in enumerare

      while (enum.hasMoreElements ()) {           

 

        // Protectie la acces concurent la Vectorul clientilor

        synchronized (listaClienti) {              

 

          // Obtinerea informatiilor privind clientul curent tratat

          InfoClient infoClient = (InfoClient) enum.nextElement(); 

 

          // Scrierea mesajului in fluxul de iesire al firului curent

          outRetea.writeUTF("Client nou");     

          outRetea.writeUTF(infoClient.nume);     

          outRetea.writeUTF(infoClient.adresa);     

          outRetea.writeUTF(new Integer(infoClient.port).toString());     

        }                                         

      }  

 

      // Fortarea trimiterii

      outRetea.flush();     

 

      // -------------------------------------------------------------------

      // Anuntarea existentei clientului curent (catre ceilalti clienti)

      // -------------------------------------------------------------------

      System.out.println("Difuzare informatii client nou ");

      difuzare("Client nou");

      difuzare(numeClient);

      difuzare(adresaClient);

      difuzare(new Integer(portClient).toString());

 

      // -------------------------------------------------------------------

      // Inregistrarea informatiilor clientului tratat

      // -------------------------------------------------------------------

 

      // Inregistrarea informatiilor clientului curent

      client = new InfoClient(numeClient, adresaClient, portClient, this);

 

      // Inregistrarea clientului curent in lista (de tip Vector)

      listaClienti.addElement (client);          

 

      // -------------------------------------------------------------------

      // Afisarea in consola a informatiilor clientului curent tratat

      // -------------------------------------------------------------------

 

      System.out.println("\nNoul client [" + numeClient +

                         "] are adresa [" + adresaClient +

                         "] si portul [" + portClient +"]");

      System.out.println("Lista clientilor actualizata:\n" +

                                            listaClienti.toString()+"\n");

 

      // --------------------------------------------------------------

      // Tratarea mesajelor clientului (citirea si difuzarea mesajelor)

      // --------------------------------------------------------------

 

      // Bucla infinita (repetare pana la inchiderea firului curent)

      while (true) {  

                    

        // Citirea mesajului din fluxul de intrare de la client

        String mesaj = inRetea.readUTF ();

 

        System.out.println("Difuzare mesaj: " + mesaj);

 

        // Difuzarea catre toti clientii curent inregistrati

        difuzare (mesaj);                   

 

        System.out.println();

      }

    }

 

    // --------------------------------------------------------------

    // Tratarea erorilor de conexiune

    // --------------------------------------------------------------

 

    catch (IOException ex) {     

      // Afisare exceptie

      ex.printStackTrace ();          

    }

 

    // --------------------------------------------------------------

    // Curatenie finala

    // --------------------------------------------------------------

 

    finally {                          

      // Eliminarea clientului curent din lista (de tip Vector)

      listaClienti.removeElement (client); 

 

      System.out.println("\nClient eliminat...");

      System.out.println("Lista clientilor actualizata:\n" +

                                         listaClienti.toString()+"\n");

 

      // -------------------------------------------------------------------

      // Anuntarea eliminarii clientului curent (catre ceilalti clienti)

      // -------------------------------------------------------------------

      System.out.println("Difuzare informatii client eliminat ");

      difuzare("Client eliminat");

      difuzare(client.nume);

      difuzare(client.adresa);

      difuzare(new Integer(client.port).toString());

 

      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 clientilor   

    Enumeration enum = listaClienti.elements ();           

 

    // Cat timp mai sunt elemente in enumerare

    while (enum.hasMoreElements ()) {           

 

      // Referinta catre firul curent initializata cu null

      TratareClientDeChat_v2 firDestinatie = null;                    

 

      // Protectie la acces concurent la Vectorul clientilor

      synchronized (listaClienti) {              

  

        // Obtinerea informatiilor privind clientul curent

        InfoClient infoClient = (InfoClient) enum.nextElement(); 

 

        System.out.print(" - catre: " + infoClient.toString());

 

        // Obtinerea referintei catre firul curent

        firDestinatie = (TratareClientDeChat_v2) infoClient.fir; 

 

        // 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

            listaClienti.remove(infoClient);

            firDestinatie = null;                           

          }

        }                                         

      }

    }  

  }

}

 

 

class InfoClient {

  String nume;

  String adresa;

  int port;

  Thread fir;

 

  /**

   * @param nume

   * @param adresa

   * @param port

   * @param fir

   */

  public InfoClient(String nume, String adresa, int port, Thread fir) {

    this.nume = nume;

    this.adresa = adresa;

    this.port = port;

    this.fir = fir;  

  }

 

  /**

   * @return java.lang.String

   */

  public String toString() {

    return fir.toString() + "(" + nume + "/" + adresa + ":" + port + ")\n";  

  }

 

  /**

   * @return boolean

   */

  public boolean equals(Object obj) {

    if ((obj != null) && (obj instanceof InfoClient)) {

      InfoClient celalaltClient = (InfoClient)obj;

      return ((this.nume.equals(celalaltClient.nume)) &&

              (this.adresa.equals(celalaltClient.adresa)) &&

              (this.port == celalaltClient.port));

    }

    return false;

  }

}