diff --git a/smack-bosh/src/main/java/org/jivesoftware/smack/bosh/XMPPBOSHConnection.java b/smack-bosh/src/main/java/org/jivesoftware/smack/bosh/XMPPBOSHConnection.java index 59a1b4e0f..362de1d41 100644 --- a/smack-bosh/src/main/java/org/jivesoftware/smack/bosh/XMPPBOSHConnection.java +++ b/smack-bosh/src/main/java/org/jivesoftware/smack/bosh/XMPPBOSHConnection.java @@ -440,7 +440,6 @@ public class XMPPBOSHConnection extends AbstractXMPPConnection { throw new RuntimeException(e); } } - notifyReconnection(); } } else { diff --git a/smack-core/src/main/java/org/jivesoftware/smack/AbstractConnectionListener.java b/smack-core/src/main/java/org/jivesoftware/smack/AbstractConnectionListener.java index 074bbe573..85d027220 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/AbstractConnectionListener.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/AbstractConnectionListener.java @@ -45,16 +45,19 @@ public class AbstractConnectionListener implements ConnectionListener { // do nothing } + @Deprecated @Override public void reconnectingIn(int seconds) { // do nothing } + @Deprecated @Override public void reconnectionFailed(Exception e) { // do nothing } + @Deprecated @Override public void reconnectionSuccessful() { // do nothing diff --git a/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java b/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java index 8d0a69c6d..7e03c3abd 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java @@ -1311,6 +1311,8 @@ public abstract class AbstractXMPPConnection implements XMPPConnection { /** * Sends a notification indicating that the connection was reconnected successfully. */ + // TODO: Remove in Smack 4.3 + @Deprecated protected void notifyReconnection() { // Notify connection listeners of the reconnection. for (ConnectionListener listener : connectionListeners) { diff --git a/smack-core/src/main/java/org/jivesoftware/smack/ConnectionListener.java b/smack-core/src/main/java/org/jivesoftware/smack/ConnectionListener.java index 89fce66e4..5a677df31 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/ConnectionListener.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/ConnectionListener.java @@ -64,7 +64,10 @@ public interface ConnectionListener { /** * The connection has reconnected successfully to the server. Connections will * reconnect to the server when the previous socket connection was abruptly closed. + * @deprecated use {@link #connected(XMPPConnection)} or {@link #authenticated(XMPPConnection, boolean)} instead. */ + // TODO: Remove in Smack 4.3 + @Deprecated public void reconnectionSuccessful(); // The next two methods *must* only be invoked by ReconnectionManager @@ -78,6 +81,8 @@ public interface ConnectionListener { * * @param seconds remaining seconds before attempting a reconnection. */ + // TODO: Remove in Smack 4.3 + @Deprecated public void reconnectingIn(int seconds); /** @@ -90,5 +95,7 @@ public interface ConnectionListener { * * @param e the exception that caused the reconnection to fail. */ + // TODO: Remove in Smack 4.3 + @Deprecated public void reconnectionFailed(Exception e); } diff --git a/smack-core/src/main/java/org/jivesoftware/smack/ReconnectionListener.java b/smack-core/src/main/java/org/jivesoftware/smack/ReconnectionListener.java new file mode 100644 index 000000000..c404008ca --- /dev/null +++ b/smack-core/src/main/java/org/jivesoftware/smack/ReconnectionListener.java @@ -0,0 +1,50 @@ +/** + * + * Copyright 2017 Florian Schmaus. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jivesoftware.smack; + +/** + * A listener for the {@link ReconnectionManager}. Use + * {@link ReconnectionManager#addReconnectionListener(ReconnectionListener)} to add new listeners to the reconnection + * manager. + * + * @since 4.2.2 + */ +public interface ReconnectionListener { + + /** + * The connection will retry to reconnect in the specified number of seconds. + *

+ * Note: This method is only called if {@link ReconnectionManager#isAutomaticReconnectEnabled()} returns true, i.e. + * only when the reconnection manager is enabled for the connection. + *

+ * + * @param seconds remaining seconds before attempting a reconnection. + */ + public void reconnectingIn(int seconds); + + /** + * An attempt to connect to the server has failed. The connection will keep trying reconnecting to the server in a + * moment. + *

+ * Note: This method is only called if {@link ReconnectionManager#isAutomaticReconnectEnabled()} returns true, i.e. + * only when the reconnection manager is enabled for the connection. + *

+ * + * @param e the exception that caused the reconnection to fail. + */ + public void reconnectionFailed(Exception e); +} diff --git a/smack-core/src/main/java/org/jivesoftware/smack/ReconnectionManager.java b/smack-core/src/main/java/org/jivesoftware/smack/ReconnectionManager.java index 2cd0b7c8d..18cbcc1dc 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/ReconnectionManager.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/ReconnectionManager.java @@ -20,7 +20,9 @@ import java.io.IOException; import java.lang.ref.WeakReference; import java.util.Map; import java.util.Random; +import java.util.Set; import java.util.WeakHashMap; +import java.util.concurrent.CopyOnWriteArraySet; import java.util.logging.Level; import java.util.logging.Logger; @@ -103,6 +105,8 @@ public final class ReconnectionManager { return enabledPerDefault; } + private final Set reconnectionListeners = new CopyOnWriteArraySet<>(); + // Holds the connection to the server private final WeakReference weakRefConnection; private final int randomBase = new Random().nextInt(13) + 2; // between 2 and 15 seconds @@ -134,6 +138,27 @@ public final class ReconnectionManager { defaultReconnectionPolicy = reconnectionPolicy; } + /** + * Add a new reconnection listener. + * + * @param listener the listener to add + * @return true if the listener was not already added + * @since 4.2.2 + */ + public boolean addReconnectionListener(ReconnectionListener listener) { + return reconnectionListeners.add(listener); + } + + /** + * Remove a reconnection listener. + * @param listener the listener to remove + * @return true if the listener was active and got removed. + * @since 4.2.2 + */ + public boolean removeReconnectionListener(ReconnectionListener listener) { + return reconnectionListeners.remove(listener); + } + /** * Set the fixed delay in seconds between the reconnection attempts Also set the connection * policy to {@link ReconnectionPolicy#FIXED_DELAY}. @@ -208,6 +233,7 @@ public final class ReconnectionManager { /** * The process will try the reconnection until the connection succeed or the user cancel it */ + @SuppressWarnings("deprecation") @Override public void run() { final AbstractXMPPConnection connection = weakRefConnection.get(); @@ -233,6 +259,9 @@ public final class ReconnectionManager { try { Thread.sleep(1000); remainingSeconds--; + for (ReconnectionListener listener : reconnectionListeners) { + listener.reconnectingIn(remainingSeconds); + } for (ConnectionListener listener : connection.connectionListeners) { listener.reconnectingIn(remainingSeconds); } @@ -244,6 +273,9 @@ public final class ReconnectionManager { } } + for (ReconnectionListener listener : reconnectionListeners) { + listener.reconnectingIn(0); + } for (ConnectionListener listener : connection.connectionListeners) { listener.reconnectingIn(0); } @@ -269,6 +301,9 @@ public final class ReconnectionManager { } catch (SmackException | IOException | XMPPException e) { // Fires the failed reconnection notification + for (ReconnectionListener listener : reconnectionListeners) { + listener.reconnectionFailed(e); + } for (ConnectionListener listener : connection.connectionListeners) { listener.reconnectionFailed(e); } diff --git a/smack-core/src/main/java/org/jivesoftware/smack/debugger/AbstractDebugger.java b/smack-core/src/main/java/org/jivesoftware/smack/debugger/AbstractDebugger.java index 0bf5213bd..4ab7dfbd4 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/debugger/AbstractDebugger.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/debugger/AbstractDebugger.java @@ -18,8 +18,13 @@ package org.jivesoftware.smack.debugger; import java.io.Reader; import java.io.Writer; +import java.util.logging.Logger; +import org.jivesoftware.smack.AbstractConnectionListener; +import org.jivesoftware.smack.AbstractXMPPConnection; import org.jivesoftware.smack.ConnectionListener; +import org.jivesoftware.smack.ReconnectionListener; +import org.jivesoftware.smack.ReconnectionManager; import org.jivesoftware.smack.StanzaListener; import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smack.packet.Stanza; @@ -32,12 +37,15 @@ import org.jxmpp.jid.EntityFullJid; public abstract class AbstractDebugger implements SmackDebugger { + private static final Logger LOGGER = Logger.getLogger(AbstractDebugger.class.getName()); + public static boolean printInterpreted = false; private final XMPPConnection connection; private final StanzaListener listener; private final ConnectionListener connListener; + private final ReconnectionListener reconnectionListener; private final ReaderListener readerListener; private final WriterListener writerListener; @@ -79,7 +87,7 @@ public abstract class AbstractDebugger implements SmackDebugger { } }; - connListener = new ConnectionListener() { + connListener = new AbstractConnectionListener() { @Override public void connected(XMPPConnection connection) { log("XMPPConnection connected (" @@ -100,7 +108,6 @@ public abstract class AbstractDebugger implements SmackDebugger { connection + ")"); } - @Override public void connectionClosedOnError(Exception e) { log( @@ -108,6 +115,9 @@ public abstract class AbstractDebugger implements SmackDebugger { connection + ")", e); } + }; + + reconnectionListener = new ReconnectionListener() { @Override public void reconnectionFailed(Exception e) { log( @@ -116,13 +126,6 @@ public abstract class AbstractDebugger implements SmackDebugger { ")", e); } @Override - public void reconnectionSuccessful() { - log( - "XMPPConnection reconnected (" + - connection + - ")"); - } - @Override public void reconnectingIn(int seconds) { log( "XMPPConnection (" + @@ -130,6 +133,14 @@ public abstract class AbstractDebugger implements SmackDebugger { ") will reconnect in " + seconds); } }; + + if (connection instanceof AbstractXMPPConnection) { + AbstractXMPPConnection abstractXmppConnection = (AbstractXMPPConnection) connection; + ReconnectionManager.getInstanceFor(abstractXmppConnection).addReconnectionListener(reconnectionListener); + } else { + LOGGER.info("The connection instance " + connection + + " is not an instance of AbstractXMPPConnection, thus we can not install the ReconnectionListener"); + } } protected abstract void log(String logMessage); diff --git a/smack-core/src/test/java/org/jivesoftware/smack/DummyConnection.java b/smack-core/src/test/java/org/jivesoftware/smack/DummyConnection.java index b871b27cb..e5351835e 100644 --- a/smack-core/src/test/java/org/jivesoftware/smack/DummyConnection.java +++ b/smack-core/src/test/java/org/jivesoftware/smack/DummyConnection.java @@ -88,6 +88,7 @@ public class DummyConnection extends AbstractXMPPConnection { user = getUserJid(); } + @SuppressWarnings("deprecation") @Override protected void connectInternal() { connected = true; @@ -95,6 +96,7 @@ public class DummyConnection extends AbstractXMPPConnection { tlsHandled.reportSuccess(); streamId = "dummy-" + new Random(new Date().getTime()).nextInt(); + // TODO: Remove in Smack 4.3, and likely the suppression of the deprecation warning. if (reconnect) { notifyReconnection(); } diff --git a/smack-debug-slf4j/src/main/java/org/jivesoftware/smackx/debugger/slf4j/SLF4JLoggingConnectionListener.java b/smack-debug-slf4j/src/main/java/org/jivesoftware/smackx/debugger/slf4j/SLF4JLoggingConnectionListener.java index 61ea3a9d9..a6e0a41cb 100644 --- a/smack-debug-slf4j/src/main/java/org/jivesoftware/smackx/debugger/slf4j/SLF4JLoggingConnectionListener.java +++ b/smack-debug-slf4j/src/main/java/org/jivesoftware/smackx/debugger/slf4j/SLF4JLoggingConnectionListener.java @@ -17,12 +17,15 @@ package org.jivesoftware.smackx.debugger.slf4j; -import org.jivesoftware.smack.ConnectionListener; +import org.jivesoftware.smack.AbstractConnectionListener; +import org.jivesoftware.smack.ReconnectionListener; import org.jivesoftware.smack.XMPPConnection; import org.slf4j.Logger; -class SLF4JLoggingConnectionListener implements ConnectionListener { +// TODO: The suppression of deprecated API can be removed in Smack 4.3. +@SuppressWarnings("deprecation") +class SLF4JLoggingConnectionListener extends AbstractConnectionListener implements ReconnectionListener { private final XMPPConnection connection; private final Logger logger; @@ -56,11 +59,6 @@ class SLF4JLoggingConnectionListener implements ConnectionListener { logger.debug("({}) Reconnection failed due to an exception: {}", connection.hashCode(), e); } - @Override - public void reconnectionSuccessful() { - logger.debug("({}) Connection reconnected", connection.hashCode()); - } - @Override public void reconnectingIn(int seconds) { logger.debug("({}) Connection will reconnect in {}", connection.hashCode(), seconds); diff --git a/smack-debug-slf4j/src/main/java/org/jivesoftware/smackx/debugger/slf4j/SLF4JSmackDebugger.java b/smack-debug-slf4j/src/main/java/org/jivesoftware/smackx/debugger/slf4j/SLF4JSmackDebugger.java index c3b683c37..a6f97da57 100644 --- a/smack-debug-slf4j/src/main/java/org/jivesoftware/smackx/debugger/slf4j/SLF4JSmackDebugger.java +++ b/smack-debug-slf4j/src/main/java/org/jivesoftware/smackx/debugger/slf4j/SLF4JSmackDebugger.java @@ -21,6 +21,8 @@ import java.io.Reader; import java.io.Writer; import java.util.concurrent.atomic.AtomicBoolean; +import org.jivesoftware.smack.AbstractXMPPConnection; +import org.jivesoftware.smack.ReconnectionManager; import org.jivesoftware.smack.SmackConfiguration; import org.jivesoftware.smack.StanzaListener; import org.jivesoftware.smack.XMPPConnection; @@ -39,6 +41,9 @@ import org.slf4j.LoggerFactory; * See SLF4J manual for more details about bindings usage. */ public class SLF4JSmackDebugger implements SmackDebugger { + + private static final java.util.logging.Logger LOGGER = java.util.logging.Logger.getLogger(SLF4JSmackDebugger.class.getName()); + public static final String LOGGER_NAME = "SMACK"; private static final Logger logger = LoggerFactory.getLogger(LOGGER_NAME); public static final AtomicBoolean printInterpreted = new AtomicBoolean(true); @@ -74,7 +79,17 @@ public class SLF4JSmackDebugger implements SmackDebugger { this.writer.addWriterListener(slf4JRawXmlListener); this.reader = new ObservableReader(Validate.notNull(reader)); this.reader.addReaderListener(slf4JRawXmlListener); - this.connection.addConnectionListener(new SLF4JLoggingConnectionListener(connection, logger)); + + final SLF4JLoggingConnectionListener loggingConnectionListener = new SLF4JLoggingConnectionListener(connection, logger); + this.connection.addConnectionListener(loggingConnectionListener); + + if (connection instanceof AbstractXMPPConnection) { + AbstractXMPPConnection abstractXmppConnection = (AbstractXMPPConnection) connection; + ReconnectionManager.getInstanceFor(abstractXmppConnection).addReconnectionListener(loggingConnectionListener); + } else { + LOGGER.info("The connection instance " + connection + + " is not an instance of AbstractXMPPConnection, thus we can not install the ReconnectionListener"); + } } @Override diff --git a/smack-debug/src/main/java/org/jivesoftware/smackx/debugger/EnhancedDebugger.java b/smack-debug/src/main/java/org/jivesoftware/smackx/debugger/EnhancedDebugger.java index c9ad9909d..f288e8d63 100644 --- a/smack-debug/src/main/java/org/jivesoftware/smackx/debugger/EnhancedDebugger.java +++ b/smack-debug/src/main/java/org/jivesoftware/smackx/debugger/EnhancedDebugger.java @@ -70,7 +70,10 @@ import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; import org.jivesoftware.smack.AbstractConnectionListener; +import org.jivesoftware.smack.AbstractXMPPConnection; import org.jivesoftware.smack.ConnectionListener; +import org.jivesoftware.smack.ReconnectionListener; +import org.jivesoftware.smack.ReconnectionManager; import org.jivesoftware.smack.SmackException.NotConnectedException; import org.jivesoftware.smack.StanzaListener; import org.jivesoftware.smack.XMPPConnection; @@ -154,6 +157,7 @@ public class EnhancedDebugger implements SmackDebugger { private StanzaListener packetReaderListener = null; private StanzaListener packetWriterListener = null; private ConnectionListener connListener = null; + private final ReconnectionListener reconnectionListener; private Writer writer; private Reader reader; @@ -183,6 +187,36 @@ public class EnhancedDebugger implements SmackDebugger { this.reader = reader; createDebug(); EnhancedDebuggerWindow.addDebugger(this); + + reconnectionListener = new ReconnectionListener() { + @Override + public void reconnectingIn(final int seconds) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + statusField.setValue("Attempt to reconnect in " + seconds + " seconds"); + } + }); + } + + @Override + public void reconnectionFailed(Exception e) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + statusField.setValue("Reconnection failed"); + } + }); + } + }; + + if (connection instanceof AbstractXMPPConnection) { + AbstractXMPPConnection abstractXmppConnection = (AbstractXMPPConnection) connection; + ReconnectionManager.getInstanceFor(abstractXmppConnection).addReconnectionListener(reconnectionListener); + } else { + LOGGER.info("The connection instance " + connection + + " is not an instance of AbstractXMPPConnection, thus we can not install the ReconnectionListener"); + } } /** @@ -263,37 +297,8 @@ public class EnhancedDebugger implements SmackDebugger { }); } - @Override - public void reconnectingIn(final int seconds) { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - statusField.setValue("Attempt to reconnect in " + seconds + " seconds"); - } - }); - } - - @Override - public void reconnectionSuccessful() { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - statusField.setValue("Reconnection stablished"); - EnhancedDebuggerWindow.connectionEstablished(EnhancedDebugger.this); - } - }); - } - - @Override - public void reconnectionFailed(Exception e) { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - statusField.setValue("Reconnection failed"); - } - }); - } }; + } private void addBasicPanels() { diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/bytestreams/ibb/InBandBytestreamManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/bytestreams/ibb/InBandBytestreamManager.java index 5e7f99d45..f9bcf6969 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/bytestreams/ibb/InBandBytestreamManager.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/bytestreams/ibb/InBandBytestreamManager.java @@ -120,8 +120,7 @@ public final class InBandBytestreamManager extends Manager implements Bytestream } @Override - public void reconnectionSuccessful() { - // re-create the manager for this connection + public void connected(XMPPConnection connection) { InBandBytestreamManager.getByteStreamManager(connection); }