From ab599dd335194feb3b2e9b90f9834aba8f380911 Mon Sep 17 00:00:00 2001 From: BetaSteward Date: Wed, 11 May 2011 22:08:11 -0400 Subject: [PATCH] added client/server ping + remove inactive connections from server --- .../main/java/mage/client/remote/Session.java | 63 ++++++++++++++----- .../java/mage/client/table/TablesPanel.java | 5 +- Mage.Common/src/mage/interfaces/Server.java | 1 + .../main/java/mage/server/ChatManager.java | 2 +- .../src/main/java/mage/server/ServerImpl.java | 13 +++- .../src/main/java/mage/server/Session.java | 10 +++ .../main/java/mage/server/SessionManager.java | 31 ++++++++- 7 files changed, 105 insertions(+), 20 deletions(-) diff --git a/Mage.Client/src/main/java/mage/client/remote/Session.java b/Mage.Client/src/main/java/mage/client/remote/Session.java index 21fd2669b46..5d53fd94f99 100644 --- a/Mage.Client/src/main/java/mage/client/remote/Session.java +++ b/Mage.Client/src/main/java/mage/client/remote/Session.java @@ -37,6 +37,9 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.JOptionPane; @@ -69,6 +72,7 @@ import mage.view.TournamentView; public class Session { private final static Logger logger = Logging.getLogger(Session.class.getName()); + private static ScheduledExecutorService sessionExecutor = Executors.newScheduledThreadPool(1); private UUID sessionId; private Server server; @@ -112,6 +116,7 @@ public class Session { sessionId = server.registerClient(userName, client.getId(), frame.getVersion()); callbackDaemon = new CallbackClientDaemon(sessionId, client, server); serverState = server.getServerState(); + sessionExecutor.scheduleWithFixedDelay(new ServerPinger(), 15, 5, TimeUnit.SECONDS); logger.info("Connected to RMI server at " + serverName + ":" + port); frame.setStatusText("Connected to " + serverName + ":" + port + " "); frame.enableButtons(); @@ -134,7 +139,6 @@ public class Session { if (isConnected()) { try { - frame.hideTables(); for (UUID chatId: chats.keySet()) { server.leaveChat(chatId, sessionId); } @@ -145,18 +149,25 @@ public class Session { try { //TODO: stop daemon server.deregisterClient(sessionId); - server = null; - logger.info("Disconnected ... "); } catch (RemoteException ex) { logger.log(Level.SEVERE, "Error disconnecting ...", ex); } catch (MageException ex) { logger.log(Level.SEVERE, "Error disconnecting ...", ex); } - frame.setStatusText("Not connected "); - frame.disableButtons(); + removeServer(); } } + private void removeServer() { + sessionExecutor.shutdownNow(); + server = null; + frame.hideTables(); + frame.setStatusText("Not connected"); + frame.disableButtons(); + logger.info("Disconnected ... "); + JOptionPane.showMessageDialog(MageFrame.getDesktop(), "Disconnected.", "Disconnected", JOptionPane.INFORMATION_MESSAGE); + } + public void ack(String message) { try { server.ack(message, sessionId); @@ -167,6 +178,17 @@ public class Session { } } + public boolean ping() { + try { + return server.ping(sessionId); + } catch (RemoteException ex) { + handleRemoteException(ex); + } catch (MageException ex) { + handleMageException(ex); + } + return false; + } + public boolean isConnected() { return server != null; } @@ -706,14 +728,7 @@ public class Session { private void handleRemoteException(RemoteException ex) { logger.log(Level.SEVERE, "Communication error", ex); - if (ex instanceof java.rmi.ConnectException) { - server = null; - frame.setStatusText("Not connected"); - frame.disableButtons(); - JOptionPane.showMessageDialog(MageFrame.getDesktop(), "Communication error - disconnecting.", "Error", JOptionPane.ERROR_MESSAGE); - } - else - JOptionPane.showMessageDialog(MageFrame.getDesktop(), "Communication error.", "Error", JOptionPane.ERROR_MESSAGE); + removeServer(); } private void handleMageException(MageException ex) { @@ -741,4 +756,24 @@ public class Session { return server; } -} \ No newline at end of file + class ServerPinger implements Runnable { + + private int missed = 0; + + @Override + public void run() { + if (!ping()) { + missed++; + if (missed > 10) { + logger.info("Connection to server timed out"); + removeServer(); + } + } + else { + missed = 0; + } + } + + } + +} diff --git a/Mage.Client/src/main/java/mage/client/table/TablesPanel.java b/Mage.Client/src/main/java/mage/client/table/TablesPanel.java index 65881c4ec82..51e86af1472 100644 --- a/Mage.Client/src/main/java/mage/client/table/TablesPanel.java +++ b/Mage.Client/src/main/java/mage/client/table/TablesPanel.java @@ -190,10 +190,11 @@ public class TablesPanel extends javax.swing.JPanel { } public void hideTables() { - if (tableWaitingDialog.isVisible()) { + if (tableWaitingDialog != null && tableWaitingDialog.isVisible()) { tableWaitingDialog.closeDialog(); } - updateTask.cancel(true); + if (updateTask != null) + updateTask.cancel(true); this.chatPanel.disconnect(); Component c = this.getParent(); diff --git a/Mage.Common/src/mage/interfaces/Server.java b/Mage.Common/src/mage/interfaces/Server.java index 59a0f9792ea..920bf2fcab1 100644 --- a/Mage.Common/src/mage/interfaces/Server.java +++ b/Mage.Common/src/mage/interfaces/Server.java @@ -54,6 +54,7 @@ public interface Server extends Remote, CallbackServer { public void ack(String message, UUID sessionId) throws RemoteException, MageException; public ServerState getServerState() throws RemoteException, MageException; + public boolean ping(UUID sessionId) throws RemoteException, MageException; //table methods public TableView createTable(UUID sessionId, UUID roomId, MatchOptions matchOptions) throws RemoteException, MageException; diff --git a/Mage.Server/src/main/java/mage/server/ChatManager.java b/Mage.Server/src/main/java/mage/server/ChatManager.java index 55e2cc8fa50..a60755fefe0 100644 --- a/Mage.Server/src/main/java/mage/server/ChatManager.java +++ b/Mage.Server/src/main/java/mage/server/ChatManager.java @@ -70,7 +70,7 @@ public class ChatManager { chatSessions.get(chatId).broadcast(userName, message, color); } - void removeSession(UUID sessionId) { + public void removeSession(UUID sessionId) { for (ChatSession chat: chatSessions.values()) { chat.kill(sessionId); } diff --git a/Mage.Server/src/main/java/mage/server/ServerImpl.java b/Mage.Server/src/main/java/mage/server/ServerImpl.java index 630e78c919e..72170c0b2c1 100644 --- a/Mage.Server/src/main/java/mage/server/ServerImpl.java +++ b/Mage.Server/src/main/java/mage/server/ServerImpl.java @@ -45,6 +45,7 @@ import mage.game.tournament.TournamentOptions; import mage.interfaces.Server; import mage.interfaces.ServerState; import mage.interfaces.callback.ClientCallback; +import mage.server.Session; import mage.server.game.DeckValidatorFactory; import mage.server.draft.DraftManager; import mage.server.game.GameFactory; @@ -105,6 +106,16 @@ public class ServerImpl extends RemoteServer implements Server { SessionManager.getInstance().getSession(sessionId).ack(message); } + @Override + public boolean ping(UUID sessionId) { + Session session = SessionManager.getInstance().getSession(sessionId); + if (session != null) { + session.ping(); + return true; + } + return false; + } + @Override public UUID registerClient(String userName, UUID clientId, MageVersion version) throws MageException, RemoteException { @@ -241,8 +252,8 @@ public class ServerImpl extends RemoteServer implements Server { Session session = SessionManager.getInstance().getSession(sessionId); if (session != null) { session.kill(); + logger.info("Client deregistered ..."); } - logger.info("Client deregistered ..."); } } ); diff --git a/Mage.Server/src/main/java/mage/server/Session.java b/Mage.Server/src/main/java/mage/server/Session.java index 871d94ed4ae..5f403d3a41c 100644 --- a/Mage.Server/src/main/java/mage/server/Session.java +++ b/Mage.Server/src/main/java/mage/server/Session.java @@ -28,6 +28,7 @@ package mage.server; +import java.util.Date; import java.util.logging.Level; import java.util.UUID; import mage.cards.decks.Deck; @@ -50,6 +51,7 @@ public class Session { private String username; private int messageId = 0; private String ackMessage; + private long lastPing; private final CallbackServerSession callback = new CallbackServerSession(); public Session(String userName, UUID clientId) { @@ -137,4 +139,12 @@ public class Session { return username; } + public void ping() { + this.lastPing = System.currentTimeMillis(); + } + + public boolean stillAlive() { + return (System.currentTimeMillis() - lastPing) < 60000; + } + } diff --git a/Mage.Server/src/main/java/mage/server/SessionManager.java b/Mage.Server/src/main/java/mage/server/SessionManager.java index 839daf1dda1..a3f1f9730e5 100644 --- a/Mage.Server/src/main/java/mage/server/SessionManager.java +++ b/Mage.Server/src/main/java/mage/server/SessionManager.java @@ -30,6 +30,9 @@ package mage.server; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; import mage.interfaces.MageException; import org.apache.log4j.Logger; @@ -41,15 +44,20 @@ public class SessionManager { private final static Logger logger = Logger.getLogger(SessionManager.class); private final static SessionManager INSTANCE = new SessionManager(); + private static ScheduledExecutorService sessionExecutor; public static SessionManager getInstance() { return INSTANCE; } + protected SessionManager() { + sessionExecutor = Executors.newScheduledThreadPool(1); + sessionExecutor.scheduleWithFixedDelay(new SessionChecker(), 30, 10, TimeUnit.SECONDS); + } + private ConcurrentHashMap sessions = new ConcurrentHashMap(); public Session getSession(UUID sessionId) { - if (sessions == null || sessionId == null) return null; return sessions.get(sessionId); } @@ -74,5 +82,24 @@ public class SessionManager { public void removeSession(UUID sessionId) { sessions.remove(sessionId); } - + + public void checkSessions() { + for (Session session: sessions.values()) { + if (!session.stillAlive()) { + logger.info("Client for user " + session.getUsername() + " timed out - releasing resources"); + session.kill(); + sessions.remove(session.getId()); + } + } + } + + class SessionChecker implements Runnable { + + @Override + public void run() { + checkSessions(); + } + + } } +