diff --git a/README.md b/README.md index cd5d004..ec3acf2 100644 --- a/README.md +++ b/README.md @@ -1 +1,2 @@ -devoir-java +## Chat Application - 2017/03 +This is my first Java project basing on Client-Server structure (with sockets), realised with 3 of my University colleagues. diff --git a/bin/client/Client.class b/bin/client/Client.class index 0c4e478..c05f89f 100644 Binary files a/bin/client/Client.class and b/bin/client/Client.class differ diff --git a/src/View/ClientUI.java b/src/View/ClientUI.java index 1457977..1eac9d0 100644 --- a/src/View/ClientUI.java +++ b/src/View/ClientUI.java @@ -1,5 +1,6 @@ package View; +import java.util.ArrayList; import java.util.Observable; import java.util.Observer; @@ -9,16 +10,13 @@ import java.awt.event.ActionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; -import java.awt.image.BufferedImage; import java.io.IOException; -import javax.imageio.ImageIO; import javax.swing.BorderFactory; import javax.swing.Box; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; -import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.JTextField; @@ -28,8 +26,8 @@ import utils.ImagePanel; /** - * ClientUI - * @author Corentin + * ClientUI is the user interface. Each ClientUI create and observe a new Client. + * @author Corentin, Raphael */ public class ClientUI extends JFrame implements Observer{ @@ -41,6 +39,7 @@ public class ClientUI extends JFrame implements Observer{ public ClientUI(Client client) throws IOException { this.client = client; + // Client is observed by ClientUI client.addObserver(this); createUI(); } @@ -49,7 +48,6 @@ public ClientUI(Client client) throws IOException { * @throws IOException */ private void createUI() throws IOException { - // TODO :: supprimer la mapView de la Frame à part et l'intégrer à ClientUI JFrame map = new MapView(this.client); ImagePanel mapPanel = (ImagePanel) map.getContentPane(); mapPanel.setBorder(BorderFactory.createLineBorder(Color.black)); @@ -66,11 +64,6 @@ private void createUI() throws IOException { add(box, BorderLayout.SOUTH); add(new JScrollPane(boxUsers), BorderLayout.EAST); inputTextField = new JTextField(); - for(int i=0; i<5;i++){ - JLabel userName = new JLabel("user"+i); - boxUsers.add(userName); - } - //JTextArea usersList = new JTextArea("users List"); sendButton = new JButton("Send"); sendButton.setBackground(new Color(59,89,182)); sendButton.setForeground(Color.WHITE); @@ -79,9 +72,8 @@ private void createUI() throws IOException { inputTextField.setForeground(Color.BLACK); box.add(inputTextField); box.add(sendButton); - //boxUsers.add(usersList); - // Action for the inputTextField and the goButton + // Send text line message to client ActionListener sendListener = new ActionListener() { public void actionPerformed(ActionEvent e) { String str = inputTextField.getText(); @@ -108,12 +100,21 @@ public void windowClosing(WindowEvent e) { public void update(Observable o, Object arg) { SwingUtilities.invokeLater(new Runnable() { public void run() { - //System.out.println(arg); textArea.append(arg.toString()); textArea.append("\n"); + boxUsers.removeAll(); + JLabel titre = new JLabel("Liste des utilisateurs connectés : "); + boxUsers.add(titre); + ArrayList clientsList = client.getClientsData(); + for (Client c : clientsList) { + if(c != null){ + JLabel userName = new JLabel(c.getName()); + boxUsers.add(userName); + } + } + System.out.println("ClientUI update : " + clientsList); } }); - //System.out.println(arg); } public static void main(String[] args) throws IOException { diff --git a/src/View/GridView.java b/src/View/GridView.java index 1466096..9f903db 100644 --- a/src/View/GridView.java +++ b/src/View/GridView.java @@ -31,20 +31,19 @@ public class GridView extends JPanel { private MapManager mapManager; /** Draw borders for the client scope */ + /* public void paintComponent(Graphics g){ super.paintComponent(g); g.drawOval(-200, -200, 400, 400); - //g.drawRect(0, -200, 400, 400); + //g.drawRect(-200, -200, 400, 400); //g.drawRoundRect(000, -200, 400, 400,100,100); // TODO :: La portée est affichée en brut ici, à changer dynamiquement ! - } + }*/ public GridView(MapManager mapManager, Client currentClient) { super(); this.mapManager = mapManager; - - // Image du marqueur ImageIcon pinIcon = new ImageIcon(getClass().getResource("/res/pin.png")); // load the image to a imageIcon @@ -54,7 +53,7 @@ public GridView(MapManager mapManager, Client currentClient) { // Listener permettant de gérer le drag n drop MouseListener ml = new MouseListener() { - + @Override public void mouseClicked(MouseEvent e) {} @@ -63,6 +62,8 @@ public void mousePressed(MouseEvent e) { GridCase jc = (GridCase)e.getSource(); TransferHandler th = jc.getTransferHandler(); + + currentClient.sendPosition(); // Permet d'éviter de pouvoir déplacer une case vide if(jc.getIcon() != null) @@ -76,12 +77,12 @@ public void mouseReleased(MouseEvent e) { // Calcul de la nouvelle position du client currentClient.setX(jc.getPosition() % mapManager.getSize()); currentClient.setY(jc.getPosition() / mapManager.getSize()); + currentClient.sendPosition(); - System.out.println(currentClient); + //System.out.println(currentClient); // Évite de dupliquer les marqueurs jc.setIcon(null); - currentClient.sendPosition(); } @Override diff --git a/src/client/Client.java b/src/client/Client.java index 70ed5e1..abcea9f 100644 --- a/src/client/Client.java +++ b/src/client/Client.java @@ -12,19 +12,19 @@ /** - * Client allows a user to send messages to the server. + * Client allows a user to send messages to the server. This class communicates with ClientUI (Obs) and ClientThread with ObjectStream + * This is a serializable class that allow it to be send in ObjectStream (only with position and name) * @author Corentin - * */ public class Client extends Observable implements Serializable { - private String name = "test"; + // Serializabled attributes + private String name; private int position_x; private int position_y; + private ArrayList clientsData = new ArrayList<>(); // Client knows its Client's pair. - - private ArrayList clientsData = new ArrayList<>(); - + // Sockets and streams attributes private Socket socket = null; private OutputStream outputStream; private ObjectOutputStream objectOutputStream; @@ -33,6 +33,7 @@ public Client(){ super(); } + /** This constructor is used to send this into socket **/ public Client(String name, int position_x, int position_y){ this.name = name; this.position_x = position_x; @@ -49,28 +50,28 @@ public void InitSocket(String server, int port) throws IOException { receivingThread.start(); } + /** ClientUI is updating with arg by this method **/ public void notifyObservers(Object arg) { super.setChanged(); super.notifyObservers(arg); } - /** Send a line of text */ + /** Send a text Message to ClientThread */ public void send(String text) { try { - Message message = new Message(Message._TEXT_, text, this.name, this.position_x, this.position_y); + Message message = new Message(Message._TEXT_, text, this.name, this.position_x, this.position_y, null); objectOutputStream.writeObject(message); - //objectOutputStream.flush(); } catch (IOException e) { notifyObservers(e); } } - /** Send a line of text */ + /** Send a position Message to ClientThread */ public void sendPosition() { try { - Message message = new Message(Message._POSITION_, "", this.name, this.position_x, this.position_y); + Message message = new Message(Message._POSITION_, "", this.name, this.position_x, this.position_y, null); + System.out.println("Client.SendPosition :" +message); objectOutputStream.writeObject(message); - //objectOutputStream.flush(); } catch (IOException e) { notifyObservers(e); } @@ -80,7 +81,7 @@ public void sendPosition() { public void close() { try { socket.close(); - Message message = new Message(Message._DISCONNECT_, "", this.name, 0, 0); + Message message = new Message(Message._DISCONNECT_, "", this.name, 0, 0, null); objectOutputStream.writeObject(message); } catch (IOException ex) { notifyObservers(ex); @@ -116,10 +117,9 @@ public int getY() { public void setY(int position_y) { this.position_y = position_y; } - + public void setClientsData(ArrayList clients){ this.clientsData = clients; - System.out.println(clients); } public ArrayList getClientsData(){ @@ -128,9 +128,8 @@ public ArrayList getClientsData(){ @Override public String toString() { - return "Client [name=" + name + ", position_x=" + position_x + ", position_y=" + position_y + "]"; + return "Client [name=" + name + ", position_x=" + position_x + ", position_y=" + position_y + ", clientsData=" + + clientsData + ", socket=" + socket + ", outputStream=" + outputStream + ", objectOutputStream=" + + objectOutputStream + "]"; } - - - } diff --git a/src/client/ClientThread.java b/src/client/ClientThread.java index aabd726..3a7b29b 100644 --- a/src/client/ClientThread.java +++ b/src/client/ClientThread.java @@ -11,17 +11,12 @@ import model.MessageValidator; /** - * ClientThread + * ClientThread is the thread that communicates with Server and Client. It receives Message from Client and sends Message to Client. * @author Corentin */ - -public class ClientThread extends Thread{ - private String clientName = null; - private int clientPosX = 0; - private int clientPosY = 0; - +public class ClientThread extends Thread{ + // Client Data (Name, posX, posY) saved in thread, not real Client instanced in ClientUI. private Client clientData; - private ObjectInputStream streamIn = null; private ObjectOutputStream streamOut = null; @@ -34,6 +29,7 @@ public ClientThread(Socket clientSocket, ArrayList threads) { } public synchronized void run() { + // Each ClientThread knows its ClientThread's pair. ArrayList threads = this.threads; try { @@ -41,20 +37,20 @@ public synchronized void run() { ObjectInputStream streamIn = new ObjectInputStream(is); streamOut = new ObjectOutputStream(clientSocket.getOutputStream()); - streamOut.writeObject(new Message(Message._TEXT_,"Quel est votre nom ?", "", 0, 0)); - streamOut.flush(); + // Ask to Client it's username and save him into clientData + streamOut.writeObject(new Message(Message._TEXT_,"Quel est votre nom ?", "BOT", 0, 0, getClients())); Message msgName = (Message)streamIn.readObject(); - clientName = msgName.text; + String clientName = msgName.text; this.clientData = new Client(clientName, 0, 0); - + for(ClientThread thread : threads){ if(thread != this){ - streamOut.writeObject(new Message(Message._TEXT_," s'est connecté !", clientName, 0, 0)); + streamOut.writeObject(new Message(Message._TEXT_," s'est connecté !", clientName, 0, 0, getClients())); } else { - streamOut.writeObject(new Message( Message._NAME_, "Bonjour " + clientName + " et bienvenue dans le chat. Pour communiquer avec les utilisateurs, il est nécessaire de se positionner à leur portée", clientName, 0, 0)); + streamOut.writeObject(new Message( Message._NAME_, "Bonjour " + clientName + " et bienvenue dans le chat. Pour communiquer et voir les utilisateurs connectés, il est nécessaire de se positionner à leur portée à l'aide d'un drag and drop", clientName, 0, 0, getClients())); } - //streamOut.flush(); + ArrayList clients = getClients(); } /* Start the conversation. */ @@ -63,11 +59,8 @@ public synchronized void run() { Message msg = (Message)streamIn.readObject(); messages.add(msg); if(msg != null){ - refreshClientData(msg.clientName, msg.posX, msg.posY); switch(msg.type){ case Message._TEXT_: - Message clientsMsg = new Message(Message._CLIENTS_, "", "", 0, 0, getClients()); - messages.add(clientsMsg); sendMessages(messages); break; @@ -76,7 +69,7 @@ public synchronized void run() { break; case Message._POSITION_: - System.out.println(msg.clientName+" position updated"); + refreshClientData(msg.clientName, msg.posX, msg.posY); break; default: @@ -90,16 +83,22 @@ public synchronized void run() { } } + /** This method allows threads to send Messages to every Client **/ public synchronized void sendMessages(ArrayList messages){ + ArrayList clients = getClients(); for(ClientThread thread : threads){ for(Message message : messages){ try { - MessageValidator val = new MessageValidator(this.clientData, thread.clientData); + // All clients connected to server are saved into Message to allow Client to know them each other. + message.clients = clients; + /*MessageValidator val = new MessageValidator(this.clientData, thread.clientData); if(this == thread || val.isClientsNear() == true) thread.streamOut.writeObject(message); else - System.out.println("Hors de portée"); + System.out.println("Hors de portée");*/ + thread.streamOut.writeObject(message); + System.out.println("ClientThread.sendMessages :" + message); } catch (IOException e) { e.printStackTrace(); } @@ -107,17 +106,27 @@ public synchronized void sendMessages(ArrayList messages){ } } + public synchronized void sendMessage(Message message){ + ArrayList messages = new ArrayList<>(); + messages.add(message); + sendMessages(messages); + } + + /** Save Client new position **/ public synchronized void refreshClientData(String name, int posX, int posY){ - clientName = name; - clientPosX = posX; - clientPosY = posY; this.clientData.setName(name); this.clientData.setX(posX); this.clientData.setY(posY); - System.out.println(name+" is refreshing position"); + System.out.println(name+" position updated" + clientData); + } + + public synchronized Message createClientsMessage(){ + ArrayList clients = getClients(); + return (new Message(Message._CLIENTS_, clients)); } + /** Return the list of Thread's Clients **/ public ArrayList getClients(){ ArrayList clients = new ArrayList<>(); for(ClientThread thread : threads){ @@ -129,7 +138,7 @@ public ArrayList getClients(){ public synchronized void disconnect(){ try{ for(ClientThread thread : threads){ - thread.streamOut.writeObject(new Message(Message._TEXT_, clientName + "s'est déconnecté !", "", 0, 0)); + thread.streamOut.writeObject(new Message(Message._TEXT_, clientData.getName() + "s'est déconnecté !", "", 0, 0, getClients())); if(thread == this) thread = null; } diff --git a/src/client/ReceivingThread.java b/src/client/ReceivingThread.java index f0fd665..f5797eb 100644 --- a/src/client/ReceivingThread.java +++ b/src/client/ReceivingThread.java @@ -8,7 +8,7 @@ import model.Message; /** - * ReceivingThread + * ReceivingThread allows Client to listen ClientThread * @author Corentin */ public class ReceivingThread implements Runnable{ @@ -26,17 +26,19 @@ public void run() try { InputStream is = socket.getInputStream(); ObjectInputStream streamIn = new ObjectInputStream(is); + Message msg = null; while(true){ msg = (Message)streamIn.readObject(); if(msg.type == Message._NAME_){ this.client.setName(msg.clientName); + msg.clientName = "BOT"; } - if(msg.type == Message._CLIENTS_){ - this.client.setClientsData(msg.clients); - continue; - } + // Set Clients array to Client + this.client.setClientsData(msg.clients); + // Notify all observers that ClientThread just send a Message this.client.notifyObservers("<"+msg.clientName+">"+msg.text); + System.out.println("ReceivingThread.run Message :" + msg); } } catch (IOException | ClassNotFoundException e) { diff --git a/src/model/Message.java b/src/model/Message.java index 08bc088..2d875bb 100644 --- a/src/model/Message.java +++ b/src/model/Message.java @@ -15,6 +15,7 @@ public class Message implements Serializable { public final static int _CLIENTS_ = 2; public final static int _DISCONNECT_ = 3; public final static int _POSITION_ = 4; + public final static int _CONNECT_ = 5; public int type; public String text; @@ -24,29 +25,24 @@ public class Message implements Serializable { public ArrayList clients; - public Message(int type, String text, String clientName, int posX, int posY){ + public Message(int type, String text, String clientName, int posX, int posY, ArrayList clients){ this.type = type; this.text = text; this.clientName = clientName; this.posX = posX; this.posY = posY; + this.clients = clients; } - - public String getClientName() { - return clientName; - } - - public Message(int type, String text, String clientName, int posX, int posY, ArrayList clients){ - this(type, text, clientName, posX, posY); + public Message(int type, ArrayList clients){ + this.type = type; this.clients = clients; } - + @Override public String toString() { - return "Message [text=" + text + ", clientName=" + clientName + ", type=" + type + ", posX=" + posX + ", posY=" - + posY + "]"; - } - + return "Message [type=" + type + ", text=" + text + ", clientName=" + clientName + ", posX=" + posX + ", posY=" + + posY + ", clients=" + clients + "]"; + } } diff --git a/src/server/Server.java b/src/server/Server.java index 039d537..47c2220 100644 --- a/src/server/Server.java +++ b/src/server/Server.java @@ -8,7 +8,7 @@ import client.ClientThread; /** - * Server allow the communication between many clients. + * Server allow the communication between many ClientThread. * @author Corentin * */ pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy