From d7dba26b7f8d28e32026ec78e804b49802efc8b5 Mon Sep 17 00:00:00 2001 From: Fateme Azizi Date: Mon, 22 Jun 2026 02:40:43 +0330 Subject: [PATCH 1/5] implement ClientSession.java --- .../university/chat/Server/ClientSession.java | 58 ++++++++++++++++++- 1 file changed, 56 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/university/chat/Server/ClientSession.java b/src/main/java/com/university/chat/Server/ClientSession.java index f09d64a..3276957 100644 --- a/src/main/java/com/university/chat/Server/ClientSession.java +++ b/src/main/java/com/university/chat/Server/ClientSession.java @@ -2,18 +2,28 @@ package com.university.chat.Server; import com.university.chat.Common.ChatMessage; import com.university.chat.Common.FileMessage; +import com.university.chat.Common.MessageType; -import java.io.IOException; +import java.io.*; import java.net.Socket; import java.nio.file.Files; public class ClientSession implements Runnable { private String username; + UserManager userManager = null; + Socket socket = null; + ObjectOutputStream outputStream = null; + ObjectInputStream inputStream = null; - public ClientSession(Socket socket, UserManager userManager) { + public ClientSession(Socket socket, UserManager userManager) throws IOException { // TODO : Create an ObjectOutputStream from socket.getOutputStream() // and an ObjectInputStream from socket.getInputStream(). + this.userManager = userManager; + this.socket = socket; + outputStream = new ObjectOutputStream(socket.getOutputStream()); + outputStream.flush(); + inputStream = new ObjectInputStream(socket.getInputStream()); } @Override @@ -29,17 +39,49 @@ public class ClientSession implements Runnable { // 6. Otherwise, create the user's folders with FileManager.createUserFolders(...) // and send back LOGIN_SUCCESS. + System.out.println("Welcome"); + Object object = inputStream.readObject(); + + if(object instanceof ChatMessage) { + ChatMessage chatMessage = (ChatMessage) object; + + if(chatMessage.getType().equals(MessageType.LOGIN)) { + username = chatMessage.getSender(); + + if (userManager.addUser(username, this)) { + FileManager.createUserFolders(username); + outputStream.writeObject(MessageType.LOGIN_SUCCESS); + outputStream.flush(); + } + else { + outputStream.writeObject(MessageType.LOGIN_FAILED); + outputStream.flush(); + socket.close(); + } + } + } + // TODO: Main message loop // In a loop, call in.readObject(), you can separate messages by their type: // - if it's a ChatMessage -> call handleChatMessage(msg) // - if it's a FileMessage -> call handleFileMessage(fileMsg) // Keep looping until the connection is closed (an exception will be thrown). + while (!socket.isClosed()) { + object = inputStream.readObject(); + + if(object instanceof ChatMessage) + handleChatMessage((ChatMessage) object); + else if(object instanceof FileMessage) + handleFileMessage((FileMessage) object); + } + } catch (Exception e) { System.out.println("Disconnected: " + username); } finally { // TODO: Remove the user from UserManager so they no longer // receive broadcasts or appear in users list + userManager.removeUser(username); } } @@ -48,12 +90,21 @@ public class ClientSession implements Runnable { switch (msg.getType()) { case PUBLIC_MESSAGE -> { // TODO: Broadcast this message to every connected client. + for (ClientSession clientSession : userManager.getAllSessions()) { + clientSession.outputStream.writeObject(msg); + clientSession.outputStream.flush(); + } } case PRIVATE_MESSAGE -> { // TODO: Forward this message to the receiver user. + userManager.getUser(msg.getReceiver()).outputStream.writeObject(msg); + userManager.getUser(msg.getReceiver()).outputStream.flush(); } case USER_LIST -> { // TODO: Reply to the requester with the list of online users. + ChatMessage chatMessage = new ChatMessage(MessageType.USER_LIST, "UserManager", username, userManager.listUsers()); + outputStream.writeObject(chatMessage); + outputStream.flush(); } } } @@ -67,5 +118,8 @@ public class ClientSession implements Runnable { Files.write(recvPath, fileMsg.getData()); // TODO: Forward the received file-message to the destination user. + ClientSession recieverSession = userManager.getUser(fileMsg.getReceiver()); + recieverSession.outputStream.writeObject(fileMsg); + recieverSession.outputStream.flush(); } } \ No newline at end of file -- 2.54.0 From 9a5bddd86219ddb2d570a00e9d6fc37813224d6c Mon Sep 17 00:00:00 2001 From: Fateme Azizi Date: Mon, 22 Jun 2026 02:41:43 +0330 Subject: [PATCH 2/5] implement ChatServer.java --- .../com/university/chat/Server/ChatServer.java | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/university/chat/Server/ChatServer.java b/src/main/java/com/university/chat/Server/ChatServer.java index b2a35ae..e0a0754 100644 --- a/src/main/java/com/university/chat/Server/ChatServer.java +++ b/src/main/java/com/university/chat/Server/ChatServer.java @@ -1,15 +1,27 @@ package com.university.chat.Server; +import java.io.IOException; +import java.net.*; + public class ChatServer { // TODO: declare a single shared UserManager instance (static final) // This MUST be shared by all ClientSession threads so that // broadcasting and private messaging work correctly. - public static void main(String[] args) { + static final UserManager userManager = new UserManager(); + + public static void main(String[] args) throws IOException { // TODO: Create a ServerSocket + ServerSocket serverSocket = new ServerSocket(5000); // TODO: In an infinite loop: // accept an incoming client connection // make a new thread running ClientSession for each user. + while (true) { + Socket socket = serverSocket.accept(); + ClientSession clientSession = new ClientSession(socket, userManager); + Thread thread = new Thread(clientSession); + thread.start(); + } } } -- 2.54.0 From f407f841ebe77adcae1dd2e6df82234320bf86f0 Mon Sep 17 00:00:00 2001 From: Fateme Azizi Date: Mon, 22 Jun 2026 02:42:34 +0330 Subject: [PATCH 3/5] implement chatClient.java --- .../university/chat/Client/chatClient.java | 61 ++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/university/chat/Client/chatClient.java b/src/main/java/com/university/chat/Client/chatClient.java index dae0bad..fcb3c31 100644 --- a/src/main/java/com/university/chat/Client/chatClient.java +++ b/src/main/java/com/university/chat/Client/chatClient.java @@ -1,7 +1,18 @@ package com.university.chat.Client; +import com.university.chat.Common.ChatMessage; +import com.university.chat.Common.FileMessage; +import com.university.chat.Common.MessageType; + +import java.io.*; +import java.net.*; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Scanner; + public class chatClient { - public static void main() { + public static void main() throws IOException { // TODO: Connecting to the server // 1. Create a socket and connect to the server // 2. Create an ObjectOutputStream (out) and ObjectInputStream (in) @@ -10,6 +21,22 @@ public class chatClient { // 3. Start a new Thread running a ServerListener(in) so incoming // messages are handled concurrently. + Socket socket = new Socket("127.0.0.1", 5000); + ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream()); + ObjectInputStream in = new ObjectInputStream(socket.getInputStream()); + + Scanner input = new Scanner(System.in); + System.out.println("Enter your username: "); + String username = input.nextLine(); + + ChatMessage chatMessage = new ChatMessage(MessageType.LOGIN, username, null, ""); + out.writeObject(chatMessage); + out.flush(); + + Thread thread = new Thread(new ServerListener(in)); + thread.start(); + + while (true){ try { // TODO: Program loop — read a line from the console and act on it: @@ -21,6 +48,38 @@ public class chatClient { // and send it as a FileMessage // - anything else -> send a PUBLIC_MESSAGE // Remember to flush() the output stream after writeObject(). + + String line = input.nextLine(); + if(line.equals("/users")) { + chatMessage = new ChatMessage(MessageType.USER_LIST, username, null, null); + out.writeObject(chatMessage); + out.flush(); + } + else if(line.startsWith("/msg")) { + String[] parts = line.split(" ", 3); + chatMessage = new ChatMessage(MessageType.PRIVATE_MESSAGE, + username, parts[1], parts[2]); + out.writeObject(chatMessage); + out.flush(); + } + else if(line.startsWith("/sendfile")) { + String[] parts = line.split(" ", 3); + String receiver = parts[1]; + String path = parts[2]; + + Path filePath = Paths.get(path); + byte[] data = Files.readAllBytes(filePath); + FileMessage fileMessage = new FileMessage(username, receiver, filePath.getFileName().toString(), data); + + out.writeObject(fileMessage); + out.flush(); + } + else { + chatMessage = new ChatMessage(MessageType.PUBLIC_MESSAGE, username, null, line); + out.writeObject(chatMessage); + out.flush(); + } + } catch (Exception e){ System.out.println("command failed: " + e.getMessage()); } -- 2.54.0 From 8b01d7881996f6b25923a8883fec04c9f4997f71 Mon Sep 17 00:00:00 2001 From: Fateme Azizi Date: Mon, 22 Jun 2026 02:43:02 +0330 Subject: [PATCH 4/5] implement ServerListener.java --- .../chat/Client/ServerListener.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/main/java/com/university/chat/Client/ServerListener.java b/src/main/java/com/university/chat/Client/ServerListener.java index b609d74..e38e58f 100644 --- a/src/main/java/com/university/chat/Client/ServerListener.java +++ b/src/main/java/com/university/chat/Client/ServerListener.java @@ -1,9 +1,19 @@ package com.university.chat.Client; +import com.university.chat.Common.ChatMessage; +import com.university.chat.Common.FileMessage; + +import java.io.ObjectInputStream; + public class ServerListener implements Runnable{ // TODO: store the ObjectInputStream from the user socket // (this should be the same input stream the // chatClient created when connecting) + private ObjectInputStream inputStream; + + public ServerListener(ObjectInputStream inputStream) { + this.inputStream = inputStream; + } @Override public void run() { @@ -13,6 +23,16 @@ public class ServerListener implements Runnable{ // - if it's a FileMessage -> print that a file was received // (filename + sender), it's already // saved to disk by the server. + while (true) { + Object object = inputStream.readObject(); + + if(object instanceof ChatMessage) { + System.out.println(((ChatMessage) object).getSender() + ": " + ((ChatMessage) object).getContent()); + } + else if(object instanceof FileMessage) { + System.out.println("File received: " + ((FileMessage) object).getFilename() + " from " + ((FileMessage) object).getSender()); + } + } } catch (Exception e){ System.out.println("Disconnected from server"); } -- 2.54.0 From 64373ef02f4e6b96e18dc9999c66904e745d80b3 Mon Sep 17 00:00:00 2001 From: Fateme Azizi Date: Mon, 22 Jun 2026 17:36:54 +0330 Subject: [PATCH 5/5] final edit --- .../chat/Client/ServerListener.java | 4 +-- .../university/chat/Client/chatClient.java | 4 +-- .../university/chat/Server/ChatServer.java | 7 +++--- .../university/chat/Server/ClientSession.java | 25 ++++++++++--------- 4 files changed, 21 insertions(+), 19 deletions(-) diff --git a/src/main/java/com/university/chat/Client/ServerListener.java b/src/main/java/com/university/chat/Client/ServerListener.java index e38e58f..dab64d8 100644 --- a/src/main/java/com/university/chat/Client/ServerListener.java +++ b/src/main/java/com/university/chat/Client/ServerListener.java @@ -18,7 +18,7 @@ public class ServerListener implements Runnable{ @Override public void run() { try { - // TODO: In an infinite loop read objects from the server + // In an infinite loop read objects from the server // - if it's a ChatMessage -> print ": " // - if it's a FileMessage -> print that a file was received // (filename + sender), it's already @@ -34,7 +34,7 @@ public class ServerListener implements Runnable{ } } } catch (Exception e){ - System.out.println("Disconnected from server"); + System.out.println("Disconnected from server" ); } } } diff --git a/src/main/java/com/university/chat/Client/chatClient.java b/src/main/java/com/university/chat/Client/chatClient.java index fcb3c31..f0f80f4 100644 --- a/src/main/java/com/university/chat/Client/chatClient.java +++ b/src/main/java/com/university/chat/Client/chatClient.java @@ -13,7 +13,7 @@ import java.util.Scanner; public class chatClient { public static void main() throws IOException { - // TODO: Connecting to the server + // Connecting to the server // 1. Create a socket and connect to the server // 2. Create an ObjectOutputStream (out) and ObjectInputStream (in) // from the socket's streams — output FIRST, then input. @@ -39,7 +39,7 @@ public class chatClient { while (true){ try { - // TODO: Program loop — read a line from the console and act on it: + //Program loop — read a line from the console and act on it: // - "/msg " -> build & send a PRIVATE_MESSAGE // - "/users" -> build & send a USER_LIST request // - "/sendfile " -> read the file into a byte[] diff --git a/src/main/java/com/university/chat/Server/ChatServer.java b/src/main/java/com/university/chat/Server/ChatServer.java index e0a0754..8a23644 100644 --- a/src/main/java/com/university/chat/Server/ChatServer.java +++ b/src/main/java/com/university/chat/Server/ChatServer.java @@ -4,21 +4,22 @@ import java.io.IOException; import java.net.*; public class ChatServer { - // TODO: declare a single shared UserManager instance (static final) + // declare a single shared UserManager instance (static final) // This MUST be shared by all ClientSession threads so that // broadcasting and private messaging work correctly. static final UserManager userManager = new UserManager(); public static void main(String[] args) throws IOException { - // TODO: Create a ServerSocket + // Create a ServerSocket ServerSocket serverSocket = new ServerSocket(5000); - // TODO: In an infinite loop: + // In an infinite loop: // accept an incoming client connection // make a new thread running ClientSession for each user. while (true) { Socket socket = serverSocket.accept(); + System.out.println("New client accepted"); ClientSession clientSession = new ClientSession(socket, userManager); Thread thread = new Thread(clientSession); thread.start(); diff --git a/src/main/java/com/university/chat/Server/ClientSession.java b/src/main/java/com/university/chat/Server/ClientSession.java index 3276957..3f38a47 100644 --- a/src/main/java/com/university/chat/Server/ClientSession.java +++ b/src/main/java/com/university/chat/Server/ClientSession.java @@ -17,7 +17,7 @@ public class ClientSession implements Runnable { ObjectInputStream inputStream = null; public ClientSession(Socket socket, UserManager userManager) throws IOException { - // TODO : Create an ObjectOutputStream from socket.getOutputStream() + // Create an ObjectOutputStream from socket.getOutputStream() // and an ObjectInputStream from socket.getInputStream(). this.userManager = userManager; this.socket = socket; @@ -30,7 +30,7 @@ public class ClientSession implements Runnable { public void run() { try { - // TODO: Welcome the user (login step) + // Welcome the user (login step) // 1. Read the first object sent by the client. // 2. Check it's a ChatMessage with type LOGIN. // 3. Extract the username. @@ -39,7 +39,6 @@ public class ClientSession implements Runnable { // 6. Otherwise, create the user's folders with FileManager.createUserFolders(...) // and send back LOGIN_SUCCESS. - System.out.println("Welcome"); Object object = inputStream.readObject(); if(object instanceof ChatMessage) { @@ -50,18 +49,20 @@ public class ClientSession implements Runnable { if (userManager.addUser(username, this)) { FileManager.createUserFolders(username); - outputStream.writeObject(MessageType.LOGIN_SUCCESS); + ChatMessage response = new ChatMessage(MessageType.LOGIN_SUCCESS, "Server", username, "Login successfully"); + outputStream.writeObject(response); outputStream.flush(); } else { - outputStream.writeObject(MessageType.LOGIN_FAILED); + ChatMessage response = new ChatMessage(MessageType.LOGIN_FAILED, "Server", username, "Username already exists"); + outputStream.writeObject(response); outputStream.flush(); socket.close(); } } } - // TODO: Main message loop + // Main message loop // In a loop, call in.readObject(), you can separate messages by their type: // - if it's a ChatMessage -> call handleChatMessage(msg) // - if it's a FileMessage -> call handleFileMessage(fileMsg) @@ -79,9 +80,9 @@ public class ClientSession implements Runnable { } catch (Exception e) { System.out.println("Disconnected: " + username); } finally { - // TODO: Remove the user from UserManager so they no longer + // Remove the user from UserManager so they no longer // receive broadcasts or appear in users list - userManager.removeUser(username); + if(!socket.isClosed()) userManager.removeUser(username); } } @@ -89,19 +90,19 @@ public class ClientSession implements Runnable { private void handleChatMessage(ChatMessage msg) throws IOException { switch (msg.getType()) { case PUBLIC_MESSAGE -> { - // TODO: Broadcast this message to every connected client. + // Broadcast this message to every connected client. for (ClientSession clientSession : userManager.getAllSessions()) { clientSession.outputStream.writeObject(msg); clientSession.outputStream.flush(); } } case PRIVATE_MESSAGE -> { - // TODO: Forward this message to the receiver user. + // Forward this message to the receiver user. userManager.getUser(msg.getReceiver()).outputStream.writeObject(msg); userManager.getUser(msg.getReceiver()).outputStream.flush(); } case USER_LIST -> { - // TODO: Reply to the requester with the list of online users. + // Reply to the requester with the list of online users. ChatMessage chatMessage = new ChatMessage(MessageType.USER_LIST, "UserManager", username, userManager.listUsers()); outputStream.writeObject(chatMessage); outputStream.flush(); @@ -117,7 +118,7 @@ public class ClientSession implements Runnable { Files.write(sentPath, fileMsg.getData()); Files.write(recvPath, fileMsg.getData()); - // TODO: Forward the received file-message to the destination user. + // Forward the received file-message to the destination user. ClientSession recieverSession = userManager.getUser(fileMsg.getReceiver()); recieverSession.outputStream.writeObject(fileMsg); recieverSession.outputStream.flush(); -- 2.54.0