From 975ce7ba21957643461958d63db6882ac6a38fdd Mon Sep 17 00:00:00 2001 From: BetaSteward Date: Fri, 20 May 2011 23:29:12 -0400 Subject: [PATCH] added reconnect dialog - not quite finished --- .../src/main/java/mage/client/MageFrame.java | 4 +- .../mage/client/dialog/ReconnectDialog.form | 56 ++++++ .../mage/client/dialog/ReconnectDialog.java | 167 ++++++++++++++++++ .../main/java/mage/client/remote/Client.java | 2 +- .../main/java/mage/client/remote/Session.java | 106 ++++++----- 5 files changed, 291 insertions(+), 44 deletions(-) create mode 100644 Mage.Client/src/main/java/mage/client/dialog/ReconnectDialog.form create mode 100644 Mage.Client/src/main/java/mage/client/dialog/ReconnectDialog.java diff --git a/Mage.Client/src/main/java/mage/client/MageFrame.java b/Mage.Client/src/main/java/mage/client/MageFrame.java index 6bac7c971ef..75bde3d85ec 100644 --- a/Mage.Client/src/main/java/mage/client/MageFrame.java +++ b/Mage.Client/src/main/java/mage/client/MageFrame.java @@ -712,7 +712,7 @@ public class MageFrame extends javax.swing.JFrame { private void btnConnectActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnConnectActionPerformed if (session.isConnected()) { if (JOptionPane.showConfirmDialog(this, "Are you sure you want to disconnect?", "Confirm disconnect", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) { - session.disconnect(); + session.disconnect(true); } } else { connectDialog.showDialog(); @@ -726,7 +726,7 @@ public class MageFrame extends javax.swing.JFrame { }//GEN-LAST:event_btnAboutActionPerformed public void exitApp() { - session.disconnect(); + session.disconnect(true); Plugins.getInstance().shutdown(); dispose(); System.exit(0); diff --git a/Mage.Client/src/main/java/mage/client/dialog/ReconnectDialog.form b/Mage.Client/src/main/java/mage/client/dialog/ReconnectDialog.form new file mode 100644 index 00000000000..22a1c40aacb --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/dialog/ReconnectDialog.form @@ -0,0 +1,56 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/Mage.Client/src/main/java/mage/client/dialog/ReconnectDialog.java b/Mage.Client/src/main/java/mage/client/dialog/ReconnectDialog.java new file mode 100644 index 00000000000..efa5915d062 --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/dialog/ReconnectDialog.java @@ -0,0 +1,167 @@ +/* +* Copyright 2011 BetaSteward_at_googlemail.com. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without modification, are +* permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this list of +* conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright notice, this list +* of conditions and the following disclaimer in the documentation and/or other materials +* provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR +* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +* The views and conclusions contained in the software and documentation are those of the +* authors and should not be interpreted as representing official policies, either expressed +* or implied, of BetaSteward_at_googlemail.com. +*/ + +/* + * ReconnectDialog.java + * + * Created on 20-May-2011, 2:39:21 PM + */ +package mage.client.dialog; + +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.swing.SwingWorker; +import mage.client.remote.Session; + +/** + * + * @author BetaSteward_at_googlemail.com + */ +public class ReconnectDialog extends MageDialog { + + private static final int MAX_ATTEMPTS = 3; + private boolean result = false; + private boolean cancel = false; + private ReconnectTask reconnectTask; + + /** Creates new form ReconnectDialog */ + public ReconnectDialog() { + initComponents(); + } + + public void showDialog(Session session) { + result = false; + cancel = false; + reconnectTask = new ReconnectTask(session, this); + reconnectTask.execute(); + this.setModal(true); + this.setLocation(100, 100); + this.setVisible(true); + } + + public void closeDialog() { + if (reconnectTask != null) reconnectTask.cancel(true); + this.setVisible(false); + } + + public void update(String message) { + this.jLabel1.setText(message); + } + + public boolean getResult() { + return result; + } + + /** This method is called from within the constructor to + * initialize the form. + * WARNING: Do NOT modify this code. The content of this method is + * always regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + jLabel1 = new javax.swing.JLabel(); + btnCancel = new javax.swing.JButton(); + + btnCancel.setText("Cancel"); + btnCancel.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnCancelActionPerformed(evt); + } + }); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); + getContentPane().setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 309, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(btnCancel, javax.swing.GroupLayout.Alignment.TRAILING)) + .addContainerGap()) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addComponent(jLabel1, javax.swing.GroupLayout.DEFAULT_SIZE, 14, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnCancel) + .addContainerGap()) + ); + + pack(); + }// //GEN-END:initComponents + + private void btnCancelActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnCancelActionPerformed + this.cancel = true; + closeDialog(); + }//GEN-LAST:event_btnCancelActionPerformed + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton btnCancel; + private javax.swing.JLabel jLabel1; + // End of variables declaration//GEN-END:variables + + class ReconnectTask extends SwingWorker { + + private Session session; + private ReconnectDialog dialog; + + ReconnectTask(Session session, ReconnectDialog dialog) { + this.session = session; + this.dialog = dialog; + } + + @Override + protected Void doInBackground() throws Exception { + int numAttempts = 0; + while (numAttempts < MAX_ATTEMPTS && !cancel) { + numAttempts++; + this.publish("Attempting to reconnect: attempt " + numAttempts + "of " + MAX_ATTEMPTS); + Thread.sleep(2000); + if (session.connect()) { + result = true; + closeDialog(); + break; + } + } + return null; + } + + @Override + protected void process(List view) { + dialog.update(view.get(0)); + } + + } +} + diff --git a/Mage.Client/src/main/java/mage/client/remote/Client.java b/Mage.Client/src/main/java/mage/client/remote/Client.java index ed5d894c884..b62f5d7f240 100644 --- a/Mage.Client/src/main/java/mage/client/remote/Client.java +++ b/Mage.Client/src/main/java/mage/client/remote/Client.java @@ -316,7 +316,7 @@ public class Client implements CallbackClient { private void handleException(Exception ex) { logger.fatal("Client error\n", ex); JOptionPane.showMessageDialog(MageFrame.getDesktop(), "Unrecoverable client error. Disconnecting", "Error", JOptionPane.ERROR_MESSAGE); - session.disconnect(); + session.disconnect(false); frame.disableButtons(); } 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 f8538142f42..acbb0bebde8 100644 --- a/Mage.Client/src/main/java/mage/client/remote/Session.java +++ b/Mage.Client/src/main/java/mage/client/remote/Session.java @@ -43,11 +43,13 @@ import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; +import javax.swing.JLayeredPane; import javax.swing.JOptionPane; import mage.cards.decks.DeckCardLists; import mage.client.MageFrame; import mage.client.chat.ChatPanel; import mage.client.components.MageUI; +import mage.client.dialog.ReconnectDialog; import mage.client.draft.DraftPanel; import mage.client.game.GamePanel; import mage.client.tournament.TournamentPanel; @@ -89,15 +91,24 @@ public class Session { private CallbackClientDaemon callbackDaemon; private ScheduledFuture future; private MageUI ui = new MageUI(); + private Connection connection; + private boolean reconnecting = false; + private boolean connecting = false; public Session(MageFrame frame) { this.frame = frame; } - public boolean connect(Connection connection) { + public synchronized boolean connect(Connection connection) { + this.connecting = true; if (isConnected()) { - disconnect(); + disconnect(true); } + this.connection = connection; + return connect(); + } + + public boolean connect() { try { System.setSecurityManager(null); System.setProperty("http.nonProxyHosts", "code.google.com"); @@ -132,55 +143,70 @@ public class Session { logger.info("Connected to RMI server at " + connection.getHost() + ":" + connection.getPort()); frame.setStatusText("Connected to " + connection.getHost() + ":" + connection.getPort() + " "); frame.enableButtons(); + reconnecting = false; + connecting = false; return true; } catch (MageException ex) { logger.fatal("", ex); - disconnect(); - JOptionPane.showMessageDialog(frame, "Unable to connect to server. " + ex.getMessage()); + if (!reconnecting) { + disconnect(false); + JOptionPane.showMessageDialog(frame, "Unable to connect to server. " + ex.getMessage()); + } } catch (RemoteException ex) { logger.fatal("Unable to connect to server - ", ex); - disconnect(); - JOptionPane.showMessageDialog(frame, "Unable to connect to server. " + ex.getMessage()); + if (!reconnecting) { + disconnect(false); + JOptionPane.showMessageDialog(frame, "Unable to connect to server. " + ex.getMessage()); + } } catch (NotBoundException ex) { logger.fatal("Unable to connect to server - ", ex); } return false; } - - public void disconnect() { - - if (isConnected()) { - try { - for (UUID chatId: chats.keySet()) { - server.leaveChat(chatId, sessionId); - } - } - catch (Exception ex) { - //swallow all exceptions at this point - } - try { - //TODO: stop daemon - if (server != null) - server.deregisterClient(sessionId); - } catch (RemoteException ex) { - logger.fatal("Error disconnecting ...", ex); - } catch (MageException ex) { - logger.fatal("Error disconnecting ...", ex); - } - removeServer(); - } - } - - private void removeServer() { + + public synchronized void disconnect(boolean voluntary) { + if (reconnecting) + return; if (future != null && !future.isDone()) future.cancel(true); - server = null; - frame.hideGames(); - frame.hideTables(); frame.setStatusText("Not connected"); frame.disableButtons(); + server = null; + if (!voluntary && !connecting) { + if (attemptReconnect()) + return; + } + try { + for (UUID chatId: chats.keySet()) { + server.leaveChat(chatId, sessionId); + } + } + catch (Exception ex) { + //swallow all exceptions at this point + } + try { + //TODO: stop daemon + if (server != null) + server.deregisterClient(sessionId); + } catch (RemoteException ex) { + logger.fatal("Error disconnecting ...", ex); + } catch (MageException ex) { + logger.fatal("Error disconnecting ...", ex); + } + frame.hideGames(); + frame.hideTables(); logger.info("Disconnected ... "); - JOptionPane.showMessageDialog(MageFrame.getDesktop(), "Disconnected.", "Disconnected", JOptionPane.INFORMATION_MESSAGE); + if (!voluntary && !connecting) + JOptionPane.showMessageDialog(MageFrame.getDesktop(), "Server error. You have been disconnected", "Error", JOptionPane.ERROR_MESSAGE); + } + + private boolean attemptReconnect() { + reconnecting = true; + ReconnectDialog rcd = new ReconnectDialog(); + MageFrame.getDesktop().add(rcd, JLayeredPane.MODAL_LAYER); + rcd.showDialog(this); + reconnecting = false; + return rcd.getResult(); } public void ack(String message) { @@ -755,14 +781,12 @@ public class Session { private void handleRemoteException(RemoteException ex) { logger.fatal("Communication error", ex); - JOptionPane.showMessageDialog(MageFrame.getDesktop(), "Critical server error. Disconnecting", "Error", JOptionPane.ERROR_MESSAGE); - disconnect(); + disconnect(false); } private void handleMageException(MageException ex) { logger.fatal("Server error", ex); - JOptionPane.showMessageDialog(MageFrame.getDesktop(), "Critical server error. Disconnecting", "Error", JOptionPane.ERROR_MESSAGE); - disconnect(); + disconnect(false); } private void handleGameException(GameException ex) { @@ -793,7 +817,7 @@ public class Session { missed++; if (missed > 10) { logger.info("Connection to server timed out"); - removeServer(); + disconnect(false); } } else {