├── ChatClient.java ├── ChatServer.java └── README.md /ChatClient.java: -------------------------------------------------------------------------------- 1 | import javafx.application.Application; 2 | import javafx.application.Platform; 3 | import javafx.collections.FXCollections; 4 | import javafx.collections.ObservableList; 5 | import javafx.geometry.Insets; 6 | import javafx.geometry.Pos; 7 | import javafx.scene.Scene; 8 | import javafx.scene.control.*; 9 | import javafx.scene.layout.*; 10 | import javafx.scene.paint.Color; 11 | import javafx.scene.text.Font; 12 | import javafx.stage.Stage; 13 | import java.io.*; 14 | import java.net.Socket; 15 | import java.util.ArrayList; 16 | import java.util.Arrays; 17 | import java.util.List; 18 | 19 | 20 | /* 21 | Created by Bikram Shrestha 22 | ChatClient class provide the user with GUI to setup 23 | connection with the server and communicate with the 24 | server to send messages and receive message from 25 | other user as well as other relevant information 26 | regarding the active userList. Thread has been created 27 | to handle receiving message to the server while message 28 | is send to the server only when btJoin when userName is 29 | not registered to the server and btSend is pressed after 30 | userName has been registered to the server. 31 | */ 32 | public class ChatClient extends Application { 33 | 34 | // Label was created to label different UI components. 35 | Label labelName = new Label("Name"); 36 | Label labelMessages = new Label("Compose "); 37 | Label labelReceived = new Label("Messages"); 38 | Label labelTitle = new Label(); 39 | Label labelActiveUser = new Label("Active User"); 40 | Label errorLabel = new Label(""); 41 | 42 | /* 43 | ArrayList for user and chat message was created 44 | so that it can be used to create observable list. 45 | */ 46 | ArrayList userList = new ArrayList<>(); 47 | ArrayList chatMessages = new ArrayList<>(); 48 | 49 | // List view for user and message was declared. 50 | ListView userListView = new ListView(); 51 | ListView messageListView = new ListView(); 52 | 53 | /* 54 | ObservableList for ListView was created using 55 | the arrayList of user and chat message. 56 | */ 57 | ObservableList userItems = 58 | FXCollections.observableArrayList (userList); 59 | 60 | ObservableList messageItem = 61 | FXCollections.observableArrayList (chatMessages); 62 | 63 | 64 | // Setting text field for user to enter name and message. 65 | TextField tfName = new TextField(); 66 | TextArea taComposeMessage = new TextArea(); 67 | 68 | // Setting button to join, send and exit the chat. 69 | Button btJoin = new Button("Join"); 70 | Button btSend = new Button("Send"); 71 | Button btDisconnect = new Button("Exit"); 72 | 73 | // Declaring dataInput and Output streams. 74 | DataOutputStream dataOutputStream; 75 | DataInputStream dataInputStream; 76 | 77 | /* 78 | By default the new user is set to be not jointed or 79 | joined = false till it meet the criteria, then the 80 | unique user is set to be joined. 81 | */ 82 | boolean joined = false; 83 | 84 | //Socket is declared. 85 | private Socket socket; 86 | 87 | // User name is being used in various methods. 88 | private String userName; 89 | 90 | private boolean connection = true; 91 | 92 | 93 | @Override // Override the start method. 94 | public void start(Stage primaryStage) { 95 | 96 | // Creating BorderPane to arrange all the node. 97 | BorderPane borderPane = new BorderPane(); 98 | borderPane.setPadding(new Insets(10)); 99 | 100 | //Setting Title of the application 101 | Font titleFont = new Font("Times New Roman",20); 102 | labelTitle.setText("Welcome to Anonymous Chat Application"); 103 | labelTitle.setFont(titleFont); 104 | Color titleColor = new Color(0.1, 0, 0.5,1); 105 | labelTitle.setTextFill(titleColor); 106 | 107 | 108 | // Setting Prompt for user text field and area. 109 | tfName.setPromptText("Enter User Name"); 110 | taComposeMessage.setPromptText("Enter your Message"); 111 | 112 | // Setting size of the compose text area. So, user can send 113 | // multiline messages. 114 | taComposeMessage.setPrefHeight(2*(tfName.getHeight())); 115 | taComposeMessage.setPrefWidth(250); 116 | 117 | // Creating GridPane for the Center part of BorderPane. 118 | GridPane centreGridPane = new GridPane(); 119 | centreGridPane.setPadding(new Insets(10)); 120 | centreGridPane.setHgap(20); 121 | centreGridPane.setVgap(10); 122 | 123 | // Adding item to the centreGridPane 124 | centreGridPane.add(labelName,0,0); 125 | centreGridPane.add(tfName,1,0); 126 | centreGridPane.add(btJoin,2,0); 127 | centreGridPane.add(labelReceived,0,2); 128 | centreGridPane.add(errorLabel,1,1,2,1); 129 | centreGridPane.add(messageListView,1,2,2,1); 130 | 131 | //Setting content to display for the ListVIew 132 | messageListView.setItems(messageItem); 133 | userListView.setItems(userItems); 134 | 135 | // user and message list view is made uneditable. 136 | userListView.setEditable(false); 137 | messageListView.setEditable(false); 138 | 139 | // Setting size of user ListView. 140 | userListView.setMaxWidth(180); 141 | userListView.setMaxHeight(250); 142 | 143 | 144 | //Creating and adding item to right of BorderPane 145 | VBox rightVBox = new VBox(); 146 | rightVBox.setPadding(new Insets(20,0,10,0)); 147 | rightVBox.setSpacing(10); 148 | rightVBox.getChildren().addAll(labelActiveUser,userListView); 149 | borderPane.setRight(rightVBox); 150 | 151 | 152 | //Creating and adding note to bottomGridPane. 153 | GridPane bottomGridPane = new GridPane(); 154 | bottomGridPane.add(labelMessages,0,0); 155 | bottomGridPane.add(taComposeMessage,1,0); 156 | bottomGridPane.add(btSend,4,0); 157 | bottomGridPane.add(btDisconnect,7,0); 158 | bottomGridPane.setHgap(20); 159 | bottomGridPane.setPadding(new Insets(10,0,10,10)); 160 | btSend.setAlignment(Pos.BASELINE_RIGHT); 161 | 162 | //Adding item to the Top of BorderPane 163 | borderPane.setTop(labelTitle); 164 | borderPane.setAlignment(labelTitle,Pos.CENTER); 165 | 166 | //Adding item to the Center of BorderPane 167 | borderPane.setCenter(centreGridPane); 168 | 169 | //Adding item to the Bottom of BorderPane. 170 | borderPane.setBottom(bottomGridPane); 171 | 172 | //Creating new scene and placing borderPane. 173 | Scene scene = new Scene(borderPane,580,400); 174 | primaryStage.setScene(scene); //Setting scene. 175 | primaryStage.setTitle("Anonymous Chat"); //Setting title. 176 | primaryStage.show(); //Display Stage. 177 | 178 | /* 179 | As socket need to be closed properly for the best 180 | user experience of the application, it is made 181 | sure that socket is closed when user close the 182 | application. 183 | */ 184 | primaryStage.setOnCloseRequest(t -> closeSocketExit()); 185 | //Send is disable until username is accepted. 186 | btSend.setDisable(true); 187 | 188 | // Setting listener for the buttons. 189 | btJoin.setOnAction(event -> joinChat()); 190 | btSend.setOnAction(e -> process()); 191 | btDisconnect.setOnAction(event -> closeSocketExit()); 192 | 193 | try { 194 | // Create a socket to connect to the server 195 | socket = new Socket("localhost", 8000); 196 | 197 | // Create an input stream to receive data from server. 198 | dataInputStream = 199 | new DataInputStream(socket.getInputStream()); 200 | 201 | // Create an output stream to send data to the server 202 | dataOutputStream = 203 | new DataOutputStream(socket.getOutputStream()); 204 | 205 | // Start a new thread for receiving messages 206 | new Thread(() -> receiveMessages()).start(); 207 | } 208 | // Providing feedback to user to notify connection issues. 209 | catch (IOException ex) { 210 | errorLabel.setTextFill(Color.RED); 211 | errorLabel.setText("Unable to establish connection."); 212 | System.err.println("Connection refused."); 213 | } 214 | } 215 | 216 | 217 | /* 218 | As socket need to be closed properly for the best user 219 | experience of the application, this method is created to 220 | make sure that the socket is closed and stage is closed 221 | when this method is called. 222 | */ 223 | private void closeSocketExit() { 224 | try { 225 | //If socket doesn't exit, no need to close. 226 | if(socket!=null){ 227 | socket.close(); 228 | } 229 | Platform.exit(); // Close UI. 230 | } 231 | catch (IOException e) { 232 | e.printStackTrace(); 233 | } 234 | } 235 | 236 | 237 | /* 238 | This method receive message for server and read the 239 | message to be displayed in proper place and relevant 240 | information is shown to user. It can be related to 241 | showing in errorLabel whether username has been 242 | successfully added to server or whether the message 243 | is to be displayed in user or chat list view. 244 | */ 245 | public void receiveMessages(){ 246 | try{ 247 | while(connection){ 248 | String message; 249 | /*If user has not joined the server, 250 | only addUserName() is allowed to 251 | perform and other information is 252 | not shared with user. 253 | */ 254 | 255 | if(!joined){ 256 | addUserName(); 257 | } 258 | /* 259 | Once userName has been accepted, other 260 | information like active userList and 261 | messages is transmitted. 262 | */ 263 | else{ 264 | /* 265 | If message start with "[" that is 266 | arrayList of user and this is 267 | added to user List view. 268 | */ 269 | message = dataInputStream.readUTF(); 270 | if(message.startsWith("[")){ 271 | addMessageToUserListView(message); 272 | } 273 | else{ 274 | // Display to the message list view. 275 | Platform.runLater(() -> { 276 | messageItem.add(message); 277 | }); 278 | } 279 | } 280 | } 281 | } catch (IOException ex) { 282 | System.out.println("Socket is closed.receive"); 283 | Platform.runLater(() -> { 284 | errorLabel.setTextFill(Color.RED); 285 | errorLabel.setText("Unable to establish connection."); 286 | }); 287 | connection = false; 288 | } 289 | } 290 | 291 | 292 | /* 293 | joinChat method allow user to send the userName to 294 | be approved to the server, as "," is being processed 295 | in other code to convert arrayList.toString back to 296 | arrayList, this is not allowed as userName. Else, the 297 | userName is send to the server and error message is 298 | handled as so. 299 | */ 300 | private void joinChat(){ 301 | userName = tfName.getText(); 302 | if(userName.contains(",")){ 303 | Platform.runLater(() -> { 304 | // Update UI here. 305 | errorLabel.setTextFill(Color.RED); 306 | errorLabel.setText("Cannot contain ','."); 307 | }); 308 | } 309 | else{ 310 | try { 311 | dataOutputStream.writeUTF(userName); 312 | } 313 | catch (IOException e) { 314 | e.printStackTrace(); 315 | } 316 | } 317 | } 318 | 319 | 320 | /* 321 | This method recreate an arrayList from the message and 322 | add the name to the userListView excluding its own name 323 | as it is not useful information. 324 | */ 325 | private void addMessageToUserListView(String s) { 326 | List list = 327 | Arrays.asList( 328 | s.substring(1, s.length() - 1).split(", ") 329 | ); 330 | Platform.runLater(() -> { 331 | // Update UI here. 332 | userItems.clear(); 333 | for(int i = 0; i < list.size(); i++){ 334 | if(!(list.get(i).equals(userName))){ 335 | userItems.add(list.get(i)); 336 | } 337 | } 338 | }); 339 | } 340 | 341 | 342 | /* 343 | If the server send response to the user and it says accepted, 344 | then the status of boolean joined is set to be true and this 345 | is updated in errorLabel to show that the user has joined 346 | the conversation and the join button is disabled and send 347 | message button is enabled. 348 | If it is not accepted, that mean there is userName is in the 349 | server arrayList so error message is shown letting user 350 | that the user name exist. 351 | */ 352 | private void addUserName() { 353 | String response; 354 | try { 355 | response = dataInputStream.readUTF(); 356 | if (response.startsWith("Accepted")){ 357 | joined = true; 358 | Platform.runLater(() -> { 359 | System.out.println("User Connected as "+ userName); 360 | btSend.setDisable(false); 361 | btJoin.setDisable(true); 362 | tfName.setEditable(false); 363 | errorLabel.setTextFill(Color.GREEN); 364 | errorLabel.setText("Joined as " + userName); 365 | }); 366 | } 367 | else if(response.equals(userName)){ 368 | Platform.runLater(() -> { 369 | // Update UI here. 370 | tfName.clear(); 371 | errorLabel.setTextFill(Color.RED); 372 | errorLabel.setText("User with same name exist."); 373 | }); 374 | } 375 | } catch (IOException e) { 376 | System.out.println("Socket is closed.add"); 377 | Platform.runLater(() -> { 378 | errorLabel.setTextFill(Color.RED); 379 | errorLabel.setText("Unable to establish connection."); 380 | connection = false; 381 | }); 382 | } 383 | } 384 | 385 | 386 | /* 387 | This method send message to server by adding name to the message, so 388 | that the message can be send to all the user in the chat group. 389 | Special care has been taken to make sure that the formatting of the 390 | multiline text is preserved. 391 | */ 392 | private void process() { 393 | try { 394 | // Get the text from the text field 395 | String string = tfName.getText().trim() + ":\n " + 396 | taComposeMessage.getText().trim(); 397 | 398 | // Send the text to the server 399 | dataOutputStream.writeUTF(string); 400 | 401 | // Clear text area. 402 | taComposeMessage.setText(""); 403 | } 404 | catch (IOException ex) { 405 | System.err.println(ex); 406 | } 407 | } 408 | } 409 | 410 | 411 | -------------------------------------------------------------------------------- /ChatServer.java: -------------------------------------------------------------------------------- 1 | import java.io.*; 2 | import java.net.*; 3 | import java.util.*; 4 | import javafx.application.Application; 5 | import javafx.application.Platform; 6 | import javafx.collections.FXCollections; 7 | import javafx.collections.ObservableList; 8 | import javafx.geometry.Insets; 9 | import javafx.scene.Scene; 10 | import javafx.scene.control.Label; 11 | import javafx.scene.control.ListView; 12 | import javafx.scene.layout.GridPane; 13 | import javafx.stage.Stage; 14 | 15 | 16 | /* 17 | Created by Bikram Shrestha 18 | ChatServer class provide a GUI for the user to see 19 | the various connection that is been established as 20 | well as current active user list. This is performed 21 | with the help of multi threading, The server listen 22 | for connection from client continuously and create 23 | a new thread to handle the communication with the 24 | connected socket. 25 | When the user try to connect to the server for the 26 | first time, as client side can only send the userName, 27 | it is checked whether there is user with same name in 28 | the userList maintained in server side and if the 29 | user name is unique, an accepted message is send to 30 | the client and client is then only allow to receive 31 | message and active userList. 32 | */ 33 | public class ChatServer extends Application { 34 | 35 | // Label was create to label logList and userList. 36 | Label lbLog = new Label("Log"); 37 | Label lbUserList = new Label("Active User"); 38 | 39 | /* 40 | ArrayList for user and chat message was created 41 | so that it can be used to create observable list. 42 | */ 43 | private ArrayList logList = new ArrayList<>(); 44 | private ArrayList userList = new ArrayList<>(); 45 | 46 | // List view for log and user was declared. 47 | ListView logListView = new ListView(); 48 | ListView userListView = new ListView(); 49 | 50 | /* 51 | ObservableList for ListView was created using 52 | the arrayList of log and user list. 53 | */ 54 | ObservableList logItems = 55 | FXCollections.observableArrayList (logList); 56 | ObservableList userItems = 57 | FXCollections.observableArrayList (userList); 58 | 59 | // Mapping of sockets to output streams 60 | private Hashtable outputStreams = new Hashtable(); 61 | 62 | //ArrayList of all open Socket. 63 | private ArrayList socketList = new ArrayList<>(); 64 | 65 | // Server socket 66 | private ServerSocket serverSocket; 67 | 68 | @Override // Override the start method in the Application class 69 | public void start(Stage primaryStage) { 70 | 71 | //Setting content to display for the ListVIew 72 | userListView.setItems(userItems); 73 | logListView.setItems(logItems); 74 | logListView.setMinWidth(430); 75 | 76 | // Creating GridPane to arrange all the node. 77 | GridPane gridPane = new GridPane(); 78 | gridPane.setPadding(new Insets(10)); 79 | 80 | //All the nodes are added to the gridPane. 81 | gridPane.add(lbLog,0,0); 82 | gridPane.add(logListView,0,1); 83 | gridPane.add(lbUserList,0,2); 84 | gridPane.add(userListView,0,3); 85 | // Create a scene and place it in the stage 86 | Scene scene = new Scene(gridPane, 450, 400); 87 | primaryStage.setTitle("Server"); // Set the stage title 88 | primaryStage.setScene(scene); // Place the scene in the stage 89 | primaryStage.show(); // Display the stage 90 | /* 91 | Special care is taken to make sure that all the connection 92 | to the client is been closed properly before closing the 93 | application. 94 | */ 95 | primaryStage.setOnCloseRequest(t -> closeSocketExit()); 96 | 97 | // Start a new thread to listen for connection. 98 | new Thread(() -> listen()).start(); 99 | } 100 | 101 | 102 | /* 103 | When this method is called, it make sure that all the 104 | open socket, or connection to the client is terminated 105 | properly. 106 | */ 107 | private void closeSocketExit() { 108 | try { 109 | for(Socket socket:socketList){ 110 | //If socket doesn't exit, no need to close. 111 | if(socket!=null){ 112 | socket.close(); 113 | } 114 | } 115 | Platform.exit(); // Close UI. 116 | } catch (IOException e) { 117 | e.printStackTrace(); 118 | } 119 | } 120 | 121 | 122 | /* 123 | This thread create a new serverSocket using the port 8000 124 | and wait for user to connect. This is done in a loop so 125 | that this server will be waiting and creating a new 126 | connection as user join the server. 127 | */ 128 | private void listen() { 129 | try { 130 | // Create a server socket 131 | serverSocket = new ServerSocket(8000); 132 | Platform.runLater(() -> 133 | logItems.add("MultiThreadServer started at " + new Date())); 134 | 135 | while (true) {// Listen for a new connection request 136 | Socket socket = serverSocket.accept(); 137 | 138 | //Add accepted socket to the socketList. 139 | socketList.add(socket); 140 | 141 | // Display the client socket information and time connected. 142 | Platform.runLater(() -> 143 | logItems.add("Connection from " + socket + " at " + new Date())); 144 | 145 | // Create output stream 146 | DataOutputStream dataOutputStream = 147 | new DataOutputStream(socket.getOutputStream()); 148 | 149 | // Save output stream to hashtable 150 | outputStreams.put(socket, dataOutputStream); 151 | 152 | // Create a new thread for the connection 153 | new ServerThread(this, socket); 154 | } 155 | } 156 | catch(IOException ex) { 157 | ex.printStackTrace(); 158 | } 159 | } 160 | 161 | 162 | // This method dispatch userList to all user in the server. 163 | private void dispatchUserList() { 164 | this.sendToAll(userList.toString()); 165 | } 166 | 167 | 168 | // Used to get the output streams 169 | Enumeration getOutputStreams(){ 170 | return outputStreams.elements(); 171 | } 172 | 173 | 174 | // Used to send message to all clients 175 | void sendToAll(String message){ 176 | // Go through hashtable and send message to each output stream 177 | for (Enumeration e = getOutputStreams(); e.hasMoreElements();){ 178 | DataOutputStream dout = (DataOutputStream)e.nextElement(); 179 | try { 180 | // Write message 181 | dout.writeUTF(message); 182 | } 183 | catch (IOException ex) { 184 | ex.printStackTrace(); 185 | } 186 | } 187 | } 188 | 189 | 190 | // This method send onlineStatus to all the user excluding self. 191 | void sendOnlineStatus(Socket socket,String message){ 192 | for (Enumeration e = getOutputStreams(); e.hasMoreElements();){ 193 | DataOutputStream dataOutputStream = (DataOutputStream)e.nextElement(); 194 | try { 195 | //If it is same socket then don't send the message. 196 | if(!(outputStreams.get(socket) == dataOutputStream)){ 197 | // Write message 198 | dataOutputStream.writeUTF(message); 199 | } 200 | } catch (IOException ex) { 201 | ex.printStackTrace(); 202 | } 203 | } 204 | } 205 | 206 | 207 | /* 208 | Declaring a ServerThread class so that it can be 209 | used to create a multi-thread server serving 210 | a each socket in different thread. 211 | */ 212 | class ServerThread extends Thread { 213 | private ChatServer server; 214 | private Socket socket; 215 | String userName; // Default null; 216 | boolean userJoined; // Default false; 217 | 218 | /** Construct a thread */ 219 | public ServerThread(ChatServer server, Socket socket) { 220 | this.socket = socket; 221 | this.server = server; 222 | start(); 223 | } 224 | 225 | /** Run a thread */ 226 | public void run() { 227 | try { 228 | // Create data input and output streams 229 | DataInputStream dataInputStream = 230 | new DataInputStream(socket.getInputStream()); 231 | DataOutputStream dataOutputStream = 232 | new DataOutputStream(socket.getOutputStream()); 233 | 234 | // Continuously serve the client 235 | while (true) { 236 | /* 237 | When user connect to the server for first time, as it 238 | can only send userName, the userName is checked against 239 | the userList to make sure only one user with the same 240 | name exist, and approve message is send if approved. 241 | */ 242 | if(!userJoined){ 243 | userName = dataInputStream.readUTF(); 244 | if(userList.contains(userName)){ 245 | dataOutputStream.writeUTF(userName); 246 | System.out.println(userName + " already exist."); 247 | } 248 | else{ 249 | userList.add(userName); 250 | dataOutputStream.writeUTF("Accepted"); 251 | server.dispatchUserList(); 252 | System.out.println(userName +" joined the chat room"); 253 | userJoined = true; 254 | String userNotification = userName + " joined the chat room."; 255 | Platform.runLater(() -> 256 | logItems.add(userName + " joined the chat room.")); 257 | server.sendOnlineStatus(socket,userNotification); 258 | userItems.clear(); 259 | userItems.addAll(userList); 260 | } 261 | } 262 | /* 263 | Once it join it can receive the message from the other 264 | user in broadcast mode. 265 | */ 266 | else if(userJoined){ 267 | // User Message 268 | String string = dataInputStream.readUTF(); 269 | 270 | // Send text back to the clients 271 | server.sendToAll(string); 272 | server.dispatchUserList(); 273 | 274 | // Add chat to the server jta 275 | Platform.runLater(() ->logItems.add(string)); 276 | } 277 | } 278 | } 279 | 280 | 281 | /* 282 | When ever Exception is thrown due to closed socket, this is 283 | handled properly so that further error does not occurs due 284 | to non existence socket. The user is also removed from the 285 | userList if it was able to register successfully before changing 286 | the default value of null to userName. And relevant message is 287 | broadcast to other user letting them know that the user has 288 | left the chat due to closed socket. 289 | */ 290 | catch(IOException ex) { 291 | System.out.println("Connection Closed for " + userName); 292 | Platform.runLater(() -> 293 | logItems.add("Connection Closed for " + userName)); 294 | 295 | if(!userName.equals(null)){ 296 | userList.remove(userName); 297 | } 298 | outputStreams.remove(socket); 299 | server.dispatchUserList(); 300 | if (!userName.equals(null)){ 301 | server.sendToAll(userName + " has left the chat room."); 302 | } 303 | Platform.runLater(() ->{ 304 | userItems.clear(); 305 | userItems.addAll(userList); 306 | }); 307 | } 308 | } 309 | } 310 | } 311 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Chat Application 2 | 3 | Chat application called ‘Anonymous Chat Application’ has been created with graphic user interface (GUI) capable of exchanging text chat between two or multiple computers over the network using java socket programming and JavaFX has been created. This application will let the user connect to the chat server or chat room with unique user name and will let user see who is online at the same chat room or server. This application has separated server and client application and as socket programming require server to be present for client to connect, server application called ‘ChatServer’ need to be run first before running ‘ChatClient’. 4 | 5 | ## Logic 6 | The logic of the application is explained below in bullet point. 7 | 8 | - As server is required to relay the message between the clients, this application has a ‘ChatServer’ component which need to be executed first. 9 | - After ‘ChatServer’ is running, client application called ‘ChatClient’ can be executed. 10 | - As the client application is the only way the user can send and receive the messages, a user name needs to create before message can be send. 11 | - This is performed by sending the user name to the server to check whether the server contain any user with same name, if the user name is accepted, then the user is able to start receiving the message from the server which include the active user list and any message send by user there afterwards, if the user name was unaccepted, the user is asked to enter the user name again till it satisfy the criteria. 12 | - This is done to prevent two users with same name, which will confuse all the user participating in the chat room. 13 | - Once user compose and press send message, the server receives the message and broadcast to all the user to the chat room. 14 | - Multiline text input has been provided to user by using the text area. 15 | - A lot of error handling has been performed so that when user exit or close the application, the server receives the socket close notification, closing the user socket and removing it from the current user list so that the user name is available for future connection. 16 | - As the server side is always listening for the connection request in a loop and once socket is created, a thread is created to communicate with the given client, many clients can create a connection and exchange messages between them. 17 | 18 | ### Input: - 19 | 20 | The server must be running for the user input to be processed, once the server is running the user can user the text field, buttons and text area to provide input to the system. 21 | 22 | - The user can use text field labelled name to input the user name. 23 | - The user can then press join to send the user name to the server to be processed. 24 | - If the name is accepted by server, then the user can use text area labelled compose to compose the message to be send to all the people joining the chat room/server. 25 | - Once the chat is composed, the user can press send button to send the message to the server for it to be broadcasted to everyone joining in the chat server. 26 | - The user can press exit to terminate the connection and close the application. 27 | - Same task can be performed by pressing the cross button in the Windows UI. 28 | 29 | ### Processing: - 30 | 31 | As this application has two components: server and client, these components will process different data differently. 32 | #### Server: 33 | 34 | - The server will receive the connection request from the server and will assign a unique socket for the client to connect and create a thread to communicate with the client. 35 | - When the client side connect for the first time, it can send the server its user name. 36 | - Once the user name is received by the server, the server checks the internal user list to check whether there is a user with same user name. If the user exists, it will send username and if does not exist then will add the username to the user list and dispatch message to all the user letting them know that the new user has joined the chat and send client with accepted message and updated user list. 37 | - Once the user is accepted, it will also receive the list of users as a string, this string is reprocessed to add to the active user list view. 38 | - The user can then send the message to the server. 39 | - Once the server receives the message, it broadcast the message to everyone in the chat server. 40 | - If the client terminates the application, the server sends a notification to all user letting them know that the user has left the client with updated user list. 41 | 42 | ### Output: - 43 | 44 | #### Server: 45 | The server application will present the user with the information regarding the number of connections made and the user activity. 46 | 47 | - List view of log labelled log show all the activity that is happening in the server. 48 | - List view labelled active user shows the current active user connected to the server. 49 | 50 | #### Client: 51 | 52 | The client will present user with the active user list in the chat server as well as messages that been shared by users as well as notification send by server to let users know of new user joining or leaving the chat. 53 | 54 | - List view labelled messages shows all the user’s message as well as notification send by server regarding user leaving and joining the chat server. 55 | - List view labelled active users shows all the user connected to the server excluding itself. 56 | --------------------------------------------------------------------------------