I've checked with the solution (I almost always do that before coming here). I can't find any functional difference between my solution and CodeGym's solution, except:
- my code validates that the message string has a colon in it (just in case something buggy happens), CG solution does not check this.
- I start building the output message text earlier in the code, while CG solution waits until the end to do any of that.
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))
{
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(IOException | ClassNotFoundException e)
{
ConsoleHelper.writeMessage(e.getMessage());
}
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());
}
}
}
}