package vooga.rts.networking.server; import java.util.HashMap; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; import util.logger.HandlerMail; import util.logger.HandlerMemory; import util.logger.IVoogaHandler; import util.logger.LoggerManager; import vooga.rts.networking.NetworkBundle; import vooga.rts.networking.communications.ExpandedLobbyInfo; import vooga.rts.networking.communications.IMessage; import vooga.rts.networking.communications.LobbyInfo; import vooga.rts.networking.communications.Message; import vooga.rts.networking.communications.clientmessages.ClientInfoMessage; import vooga.rts.networking.communications.servermessages.AlertClientMessage; /** * Class that provides default behavior for IThreadContainer and provides other behaviors * for thread containers. This is the superclass for MatchmakerServer, GameContainer, Room, Lobby, * and GameServer. This provides default (empty) behavior for IThreadContainer and default * (non-empty) behavior for IMessageReceiver. * * @author David Winegar * */ public abstract class AbstractThreadContainer implements IThreadContainer, IMessageReceiver { /** * The email handler that sends the email information contained in the configuration files. */ public static final IVoogaHandler EMAIL_HANDLER = new HandlerMemory(new HandlerMail(NetworkBundle.getConfigurationItem("emailFrom"), new String[] { NetworkBundle .getConfigurationItem("emailTo") }, NetworkBundle.getConfigurationItem("emailServer"), NetworkBundle.getString("emailSubject"), NetworkBundle.getString("emailMessage")), 1, Level.SEVERE); private Map<Integer, ConnectionThread> myConnectionThreads = new HashMap<Integer, ConnectionThread>(); private Logger myLogger; /** * Default empty constructor, initializes state and logger. */ public AbstractThreadContainer () { LoggerManager log = new LoggerManager(); log.addHandler(EMAIL_HANDLER); myLogger = log.getLogger(); } /** * Initializes state and uses the passed in logger. * * @param logger to use */ public AbstractThreadContainer (Logger logger) { myLogger = logger; } /** * Constructor that copies all current threads from the AbstractThreadContainer passed in and * uses the logger passed in. * * @param container AbstractThreadContainer * @param logger to use */ public AbstractThreadContainer (AbstractThreadContainer container, Logger logger) { this(logger); myConnectionThreads = new HashMap<Integer, ConnectionThread>(container.myConnectionThreads); for (ConnectionThread thread : myConnectionThreads.values()) { thread.switchMessageServer(this); } } /** * This method returns the logger for the class. * * @return logger */ protected Logger getLogger () { return myLogger; } @Override public void joinGameContainer (ConnectionThread thread, String gameName) { sendErrorMessage(thread); } @Override public void joinLobby (ConnectionThread thread, int lobbyNumber) { sendErrorMessage(thread); } @Override public void leaveLobby (ConnectionThread thread, ExpandedLobbyInfo lobbyInfo) { sendErrorMessage(thread); } @Override public void requestGameStart (ConnectionThread thread) { sendErrorMessage(thread); } @Override public void requestLobbies (ConnectionThread thread) { sendErrorMessage(thread); } @Override public void startLobby (ConnectionThread thread, LobbyInfo lobbyInfo) { sendErrorMessage(thread); } @Override public void updateLobbyInfo (ConnectionThread thread, ExpandedLobbyInfo myLobbyInfo) { sendErrorMessage(thread); } @Override public void clientIsReadyToStart (ConnectionThread thread) { sendErrorMessage(thread); } /** * Sends an error message to the client with the method that calls this one. * * @param thread to send to */ private void sendErrorMessage (ConnectionThread thread) { StackTraceElement[] element = Thread.currentThread().getStackTrace(); thread.sendMessage(new AlertClientMessage(NetworkBundle.getString("InvalidOperation"), element[1].getMethodName())); getLogger().log(Level.SEVERE, NetworkBundle.getString("InvalidOperation") + ": " + element[1].getMethodName()); } @Override public void removeConnection (ConnectionThread thread) { myConnectionThreads.remove(thread.getID()); } /** * Receives a message and then executes default behavior, stamping it and if it is a * systemMessage, executing it. * * @param message message received * @param thread thread received from */ @Override public void receiveMessageFromClient (Message message, ConnectionThread thread) { getLogger().log(Level.FINEST, NetworkBundle.getString("MessageReceived") + thread.getID() + " " + message.getClass().getSimpleName()); stampMessage(message); if (message instanceof ClientInfoMessage) { ClientInfoMessage systemMessage = (ClientInfoMessage) message; systemMessage.affectServer(thread, this); } } /** * Overridable method for stamping this message called by receiveMessageFromClient. * */ protected void stampMessage (Message message) { message.stampTime(); } /** * Adds a connection. */ protected void addConnection (ConnectionThread thread) { myConnectionThreads.put(thread.getID(), thread); thread.switchMessageServer(this); } /** * Send a message to all connection threads. */ protected void sendMessageToAllConnections (IMessage message) { for (ConnectionThread thread : myConnectionThreads.values()) { thread.sendMessage(message); } } /** * Send a message to a specific connection thread. */ protected void sendMessageToClient (ConnectionThread thread, IMessage message) { thread.sendMessage(message); } /** * Returns whether the AbstractThreadContainer has any connection threads or not. */ protected boolean haveNoConnections () { return myConnectionThreads.isEmpty(); } /** * Removes all connection threads. */ protected void removeAllConnections () { myConnectionThreads.clear(); } /** * Returns the curent number of connections. */ protected int getNumberOfConnections () { return myConnectionThreads.size(); } }