The issue is that the requirements aren't really that clear what message they want. I will note that I have done something a little bit different in how I approached this; I've nested try/catch statements in order to be able to differentiate whether the exception comes from the Connection constructor or the serverHandshake method.
package com.codegym.task.task30.task3008;
import java.io.Console;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class Server
{
private static Map<String, Connection> connectionMap = new ConcurrentHashMap<>();
public static void main(String[] args)
{
int serverPort = ConsoleHelper.readInt();
try(ServerSocket serverSocket = new ServerSocket(serverPort))
{
ConsoleHelper.writeMessage("The server is running.");
Socket socket;
while(true)
{
socket = serverSocket.accept();
new Handler(socket).start();
}
}
catch(IOException e)
{
e.printStackTrace();
}
}
private static class Handler extends Thread
{
Socket socket;
String userName;
public void run()
{
ConsoleHelper.writeMessage("Connection established with " + socket.getRemoteSocketAddress());
try(Connection connection = new Connection(socket))
{
try
{
userName = serverHandshake(connection);
sendBroadcastMessage(new Message(MessageType.USER_ADDED, userName));
notifyUsers(connection, userName);
serverMainLoop(connection, userName);
connectionMap.remove(userName);
sendBroadcastMessage(new Message(MessageType.USER_REMOVED, userName));
}
catch(Exception e)
{
ConsoleHelper.writeMessage("Failed to get username from connection");
connection.close();
}
}
catch(IOException e)
{
ConsoleHelper.writeMessage("Failed to create new Connection using socket.");
}
sendBroadcastMessage(new Message(MessageType.TEXT, "The connection with the remote address is closed."));
}
public Handler(Socket socket)
{
this.socket = socket;
}
private String serverHandshake(Connection connection) throws IOException, ClassNotFoundException
{
while(true)
{
connection.send(new Message(MessageType.NAME_REQUEST));
Message response = connection.receive();
if(response.getType() == MessageType.USER_NAME)
{
if(response.getData() != "" && !connectionMap.containsKey(response.getData()))
{
connectionMap.put(response.getData(), connection);
connection.send(new Message(MessageType.NAME_ACCEPTED));
return response.getData();
}
}
}
}
private void notifyUsers(Connection connection, String userName) throws IOException
{
for(Map.Entry<String, Connection> entry : connectionMap.entrySet())
{
if(userName != entry.getKey())
{
connection.send(new Message(MessageType.USER_ADDED, entry.getKey()));
}
}
}
private void serverMainLoop(Connection connection, String userName) throws IOException, ClassNotFoundException
{
Message message;
while(true)
{
message = connection.receive();
if(message.getType() == MessageType.TEXT)
{
sendBroadcastMessage(new Message(MessageType.TEXT, userName + ": " + message.getData()));
}
else
{
ConsoleHelper.writeMessage("Error: MessageType not equal to TEXT");
}
}
}
}
public static void sendBroadcastMessage(Message message)
{
for(Map.Entry<String, Connection> entry : connectionMap.entrySet())
{
try
{
entry.getValue().send(message);
}
catch(IOException e)
{
System.out.println("The message could not be sent to " + entry.getKey());
}
}
}
}