diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..cd4d8a5
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,17 @@
+
+
+ 4.0.0
+
+ org.example
+ chat-app
+ 1.0-SNAPSHOT
+
+
+ 21
+ 21
+ UTF-8
+
+
+
diff --git a/src/main/java/chat/ChatClient.java b/src/main/java/chat/ChatClient.java
new file mode 100644
index 0000000..eb20460
--- /dev/null
+++ b/src/main/java/chat/ChatClient.java
@@ -0,0 +1,72 @@
+package chat;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.net.Socket;
+
+public class ChatClient {
+
+ private final String host;
+ private final int port;
+ private Socket socket;
+ private PrintWriter out;
+ private BufferedReader in;
+ private BufferedReader consoleReader;
+
+ public ChatClient(String host, int port) {
+ this.host = host;
+ this.port = port;
+ this.consoleReader = new BufferedReader(new InputStreamReader(System.in));
+ }
+
+ public void start() {
+ try {
+ connectToServer();
+ MessageListener messageListener = new MessageListener(in);
+ Thread listenerThread = new Thread(messageListener);
+ listenerThread.setDaemon(true);
+ listenerThread.start();
+ readUserInputAndSend();
+ } catch (IOException e) {
+ System.err.println("Client error: " + e.getMessage());
+ } finally {
+ cleanup();
+ }
+ }
+
+ private void connectToServer() throws IOException {
+ // TODO: create socket connection to host:port
+ // TODO: initialize output stream (PrintWriter)
+ // TODO: initialize input stream (BufferedReader)
+ }
+
+ private void readUserInputAndSend() throws IOException {
+ // TODO: read continuously from console
+ // TODO: send each input line to server
+ }
+
+ private void cleanup() {
+ // TODO: close socket safely
+ // TODO: release resources
+ }
+
+ public static void main(String[] args) {
+ String host = "127.0.0.1";
+ int port = 12345;
+
+ if (args.length > 0) {
+ host = args[0];
+ }
+ if (args.length > 1) {
+ try {
+ port = Integer.parseInt(args[1]);
+ } catch (NumberFormatException e) {
+ System.err.println("Invalid port. Using default: " + port);
+ }
+ }
+
+ new ChatClient(host, port).start();
+ }
+}
diff --git a/src/main/java/chat/ChatServer.java b/src/main/java/chat/ChatServer.java
new file mode 100644
index 0000000..218dbcd
--- /dev/null
+++ b/src/main/java/chat/ChatServer.java
@@ -0,0 +1,69 @@
+package chat;
+
+import java.io.IOException;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+public class ChatServer {
+
+ private final int port;
+ private final Set connectedClients;
+ private final ExecutorService threadPool;
+
+ public ChatServer(int port) {
+ this.port = port;
+ this.connectedClients = Collections.synchronizedSet(new HashSet<>());
+ this.threadPool = Executors.newCachedThreadPool();
+ }
+
+ public void start() {
+ try (ServerSocket serverSocket = new ServerSocket(port)) {
+ System.out.println("Chat server started on port " + port);
+
+ while (true) {
+ Socket clientSocket = serverSocket.accept();
+ ClientHandler clientHandler = new ClientHandler(clientSocket, this);
+ connectedClients.add(clientHandler);
+ threadPool.execute(clientHandler);
+ }
+ } catch (IOException e) {
+ System.err.println("Server error: " + e.getMessage());
+ } finally {
+ threadPool.shutdown();
+ }
+ }
+
+ public void broadcast(String message, ClientHandler sender) {
+ // step 1: iterate through connectedClients safely
+ // step 2: skip the sender client
+ // step 3: send message to remaining clients using sendMessage
+ }
+
+ public void broadcastSystemMessage(String message) {
+ // step 1: iterate through all connected clients
+ // step 2: send system message to each client
+ }
+
+ public void removeClient(ClientHandler clientHandler) {
+ // step 1: remove client from connectedClients set
+ // step 2: retrieve username from clientHandler
+ // step 3: broadcast system message about user leaving
+ }
+
+ public static void main(String[] args) {
+ int port = 12345;
+ if (args.length > 0) {
+ try {
+ port = Integer.parseInt(args[0]);
+ } catch (NumberFormatException e) {
+ System.err.println("Invalid port. Using default: " + port);
+ }
+ }
+ new ChatServer(port).start();
+ }
+}
diff --git a/src/main/java/chat/ClientHandler.java b/src/main/java/chat/ClientHandler.java
new file mode 100644
index 0000000..04484ba
--- /dev/null
+++ b/src/main/java/chat/ClientHandler.java
@@ -0,0 +1,78 @@
+package chat;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.net.Socket;
+
+public class ClientHandler implements Runnable {
+
+ private final Socket clientSocket;
+ private final ChatServer chatServer;
+ private PrintWriter out;
+ private BufferedReader in;
+ private String username;
+
+ public ClientHandler(Socket clientSocket, ChatServer chatServer) {
+ this.clientSocket = clientSocket;
+ this.chatServer = chatServer;
+ }
+
+ @Override
+ public void run() {
+ try {
+ setupStreams();
+ requestUsername();
+ announceJoin();
+ listenForMessages();
+ } catch (IOException e) {
+ System.err.println("Client handler error: " + e.getMessage());
+ } finally {
+ cleanup();
+ }
+ }
+
+ private void setupStreams() throws IOException {
+ out = new PrintWriter(clientSocket.getOutputStream(), true);
+ in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
+ }
+
+ private void requestUsername() throws IOException {
+ out.println("Enter your username:");
+ username = in.readLine();
+ if (username == null || username.trim().isEmpty()) {
+ username = "Anonymous";
+ }
+ }
+
+ private void announceJoin() {
+ chatServer.broadcastSystemMessage("[System] " + username + " joined the chat.");
+ }
+
+ private void listenForMessages() throws IOException {
+ String message;
+ while ((message = in.readLine()) != null) {
+ chatServer.broadcast(username + ": " + message, this);
+ }
+ }
+
+ private void cleanup() {
+ chatServer.removeClient(this);
+ try {
+ if (clientSocket != null && !clientSocket.isClosed()) {
+ clientSocket.close();
+ }
+ } catch (IOException e) {
+ System.err.println("Error closing socket: " + e.getMessage());
+ }
+ }
+
+ public void sendMessage(String message) {
+ out.println(message);
+ }
+
+ public String getUsername() {
+ return username;
+ }
+}
diff --git a/src/main/java/chat/MessageListener.java b/src/main/java/chat/MessageListener.java
new file mode 100644
index 0000000..246256b
--- /dev/null
+++ b/src/main/java/chat/MessageListener.java
@@ -0,0 +1,19 @@
+package chat;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+
+public class MessageListener implements Runnable {
+
+ private final BufferedReader inputReader;
+
+ public MessageListener(BufferedReader inputReader) {
+ this.inputReader = inputReader;
+ }
+
+ @Override
+ public void run() {
+ // TODO: continuously read messages from server
+ // TODO: print received messages immediately
+ }
+}