diff --git a/bosh/src/main/java/org/jivesoftware/smack/BOSHConnection.java b/bosh/src/main/java/org/jivesoftware/smack/BOSHConnection.java index bbbe206e7..db3192316 100644 --- a/bosh/src/main/java/org/jivesoftware/smack/BOSHConnection.java +++ b/bosh/src/main/java/org/jivesoftware/smack/BOSHConnection.java @@ -102,12 +102,6 @@ public class BOSHConnection extends XMPPConnection { */ private String user = null; - /** - * The roster maybe also called buddy list holds the list of the users contacts. - */ - private Roster roster = null; - - /** * Create a HTTP Binding connection to a XMPP server. * @@ -202,6 +196,7 @@ public class BOSHConnection extends XMPPConnection { + getHost() + ":" + getPort() + "."; throw new SmackException(errorMessage); } + callConnectionConnectedListener(); } public String getConnectionID() { @@ -214,42 +209,6 @@ public class BOSHConnection extends XMPPConnection { } } - public Roster getRoster() throws XMPPException, SmackException { - if (roster == null) { - return null; - } - if (!config.isRosterLoadedAtLogin()) { - roster.reload(); - } - // If this is the first time the user has asked for the roster after calling - // login, we want to wait for the server to send back the user's roster. - // This behavior shields API users from having to worry about the fact that - // roster operations are asynchronous, although they'll still have to listen - // for changes to the roster. Note: because of this waiting logic, internal - // Smack code should be wary about calling the getRoster method, and may - // need to access the roster object directly. - if (!roster.rosterInitialized) { - try { - synchronized (roster) { - long waitTime = SmackConfiguration.getDefaultPacketReplyTimeout(); - long start = System.currentTimeMillis(); - while (!roster.rosterInitialized) { - if (waitTime <= 0) { - break; - } - roster.wait(waitTime); - long now = System.currentTimeMillis(); - waitTime -= now - start; - start = now; - } - } - } catch (InterruptedException ie) { - // Ignore. - } - } - return roster; - } - public String getUser() { return user; } @@ -311,14 +270,6 @@ public class BOSHConnection extends XMPPConnection { } } - // Create the roster if it is not a reconnection. - if (this.roster == null) { - this.roster = new Roster(this); - } - if (config.isRosterLoadedAtLogin()) { - this.roster.reload(); - } - // Set presence to online. if (config.isSendPresence()) { sendPacket(new Presence(Presence.Type.available)); @@ -337,6 +288,7 @@ public class BOSHConnection extends XMPPConnection { if (config.isDebuggerEnabled() && debugger != null) { debugger.userHasLogged(user); } + callConnectionAuthenticatedListener(); } public void loginAnonymously() throws XMPPException, SmackException, IOException { @@ -361,9 +313,6 @@ public class BOSHConnection extends XMPPConnection { // Update the serviceName with the one returned by the server config.setServiceName(StringUtils.parseServer(response)); - // Anonymous users can't have a roster. - roster = null; - // Set presence to online. if (config.isSendPresence()) { sendPacket(new Presence(Presence.Type.available)); @@ -380,6 +329,7 @@ public class BOSHConnection extends XMPPConnection { if (config.isDebuggerEnabled() && debugger != null) { debugger.userHasLogged(user); } + callConnectionAuthenticatedListener(); } public void sendPacket(Packet packet) { @@ -431,17 +381,7 @@ public class BOSHConnection extends XMPPConnection { wasAuthenticated = false; isFirstInitialization = true; - // Notify connection listeners of the connection closing if done hasn't already been set. - for (ConnectionListener listener : getConnectionListeners()) { - try { - listener.connectionClosed(); - } - catch (Exception e) { - // Catch and print any exception so we can recover - // from a faulty listener and finish the shutdown process - e.printStackTrace(); - } - } + callConnectionClosedListener(); } /** @@ -612,17 +552,7 @@ public class BOSHConnection extends XMPPConnection { shutdown(new Presence(Presence.Type.unavailable)); // Print the stack trace to help catch the problem e.printStackTrace(); - // Notify connection listeners of the error. - for (ConnectionListener listener : getConnectionListeners()) { - try { - listener.connectionClosedOnError(e); - } - catch (Exception e2) { - // Catch and print any exception so we can recover - // from a faulty listener - e2.printStackTrace(); - } - } + callConnectionClosedOnErrorListener(e); } diff --git a/core/src/main/java/org/jivesoftware/smack/AbstractConnectionListener.java b/core/src/main/java/org/jivesoftware/smack/AbstractConnectionListener.java index 3e8cee6c8..bc8b27b8e 100644 --- a/core/src/main/java/org/jivesoftware/smack/AbstractConnectionListener.java +++ b/core/src/main/java/org/jivesoftware/smack/AbstractConnectionListener.java @@ -25,25 +25,38 @@ package org.jivesoftware.smack; * @author Henning Staib */ public class AbstractConnectionListener implements ConnectionListener { + @Override + public void connected(XMPPConnection connection) { + // do nothing + } + @Override + public void authenticated(XMPPConnection connection) { + // do nothing + } + + @Override public void connectionClosed() { // do nothing } + @Override public void connectionClosedOnError(Exception e) { // do nothing } + @Override public void reconnectingIn(int seconds) { // do nothing } + @Override public void reconnectionFailed(Exception e) { // do nothing } + @Override public void reconnectionSuccessful() { // do nothing } - } diff --git a/core/src/main/java/org/jivesoftware/smack/ConnectionListener.java b/core/src/main/java/org/jivesoftware/smack/ConnectionListener.java index 1f5b7e71c..7df1827be 100644 --- a/core/src/main/java/org/jivesoftware/smack/ConnectionListener.java +++ b/core/src/main/java/org/jivesoftware/smack/ConnectionListener.java @@ -28,6 +28,18 @@ package org.jivesoftware.smack; */ public interface ConnectionListener { + /** + * TODO + * @param connection + */ + public void connected(XMPPConnection connection); + + /** + * TODO + * @param connection + */ + public void authenticated(XMPPConnection connection); + /** * Notification that the connection was closed normally or that the reconnection * process has been aborted. diff --git a/core/src/main/java/org/jivesoftware/smack/ReconnectionManager.java b/core/src/main/java/org/jivesoftware/smack/ReconnectionManager.java index a2ae412a4..f19a62ce4 100644 --- a/core/src/main/java/org/jivesoftware/smack/ReconnectionManager.java +++ b/core/src/main/java/org/jivesoftware/smack/ReconnectionManager.java @@ -35,7 +35,7 @@ import java.util.logging.Logger; * * @author Francisco Vives */ -public class ReconnectionManager implements ConnectionListener { +public class ReconnectionManager extends AbstractConnectionListener { private static final Logger LOGGER = Logger.getLogger(ReconnectionManager.class.getName()); // Holds the connection to the server @@ -187,10 +187,12 @@ public class ReconnectionManager implements ConnectionListener { } } + @Override public void connectionClosed() { done = true; } + @Override public void connectionClosedOnError(Exception e) { done = false; if (e instanceof StreamErrorException) { @@ -207,20 +209,4 @@ public class ReconnectionManager implements ConnectionListener { this.reconnect(); } } - - public void reconnectingIn(int seconds) { - // ignore - } - - public void reconnectionFailed(Exception e) { - // ignore - } - - /** - * The connection has successfull gotten connected. - */ - public void reconnectionSuccessful() { - // ignore - } - } diff --git a/core/src/main/java/org/jivesoftware/smack/Roster.java b/core/src/main/java/org/jivesoftware/smack/Roster.java index e7adb5599..b658f28c5 100644 --- a/core/src/main/java/org/jivesoftware/smack/Roster.java +++ b/core/src/main/java/org/jivesoftware/smack/Roster.java @@ -29,6 +29,8 @@ import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; +import java.util.logging.Level; +import java.util.logging.Logger; import org.jivesoftware.smack.SmackException.NoResponseException; import org.jivesoftware.smack.SmackException.NotLoggedInException; @@ -59,6 +61,7 @@ import org.jivesoftware.smack.util.StringUtils; */ public class Roster { + private static final Logger LOGGER = Logger.getLogger(Roster.class.getName()); /** * The default subscription processing mode to use when a Roster is created. By default * all subscription requests are automatically accepted. @@ -123,9 +126,9 @@ public class Roster { PacketFilter presenceFilter = new PacketTypeFilter(Presence.class); presencePacketListener = new PresencePacketListener(); connection.addPacketListener(presencePacketListener, presenceFilter); - + // Listen for connection events - final ConnectionListener connectionListener = new AbstractConnectionListener() { + connection.addConnectionListener(new AbstractConnectionListener() { public void connectionClosed() { // Changes the presence available contacts to unavailable @@ -137,22 +140,34 @@ public class Roster { setOfflinePresences(); } - }; - - // if not connected add listener after successful login - if(!this.connection.isConnected()) { - XMPPConnection.addConnectionCreationListener(new ConnectionCreationListener() { - - public void connectionCreated(XMPPConnection connection) { - if(connection.equals(Roster.this.connection)) { - Roster.this.connection.addConnectionListener(connectionListener); - } - - } - }); - } else { - connection.addConnectionListener(connectionListener); + }); + // If the connection is already established, call reload + if (connection.isAuthenticated()) { + try { + reload(); + } + catch (NotLoggedInException e) { + LOGGER.log(Level.SEVERE, "Could not reload Roster", e); + } } + connection.addConnectionListener(new AbstractConnectionListener() { + public void authenticated(XMPPConnection connection) { + // Anonymous users can't have a roster, but it iss possible that a Roster instance is + // retrieved if getRoster() is called *before* connect(). So we have to check here + // again if it's an anonymous connection. + if (connection.isAnonymous()) + return; + if (!connection.getConfiguration().isRosterLoadedAtLogin()) + return; + try { + Roster.this.reload(); + } + catch (NotLoggedInException e) { + LOGGER.log(Level.SEVERE, "Could not reload Roster", e); + return; + } + } + }); } /** @@ -189,11 +204,9 @@ public class Roster { * Reloads the entire roster from the server. This is an asynchronous operation, * which means the method will return immediately, and the roster will be * reloaded at a later point when the server responds to the reload request. - * - * @throws SmackException If not logged in. - * @throws IllegalStateException if logged in anonymously + * @throws NotLoggedInException If not logged in. */ - public void reload() throws XMPPException, SmackException { + public void reload() throws NotLoggedInException{ if (!connection.isAuthenticated()) { throw new NotLoggedInException(); } diff --git a/core/src/main/java/org/jivesoftware/smack/XMPPConnection.java b/core/src/main/java/org/jivesoftware/smack/XMPPConnection.java index 29701edaf..0e885cca1 100644 --- a/core/src/main/java/org/jivesoftware/smack/XMPPConnection.java +++ b/core/src/main/java/org/jivesoftware/smack/XMPPConnection.java @@ -224,6 +224,8 @@ public abstract class XMPPConnection { private final ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(2); + private Roster roster; + /** * Create an executor to deliver incoming packets to listeners. We'll use a single thread with an unbounded queue. */ @@ -482,11 +484,53 @@ public abstract class XMPPConnection { * {@link RosterListener}s will throw an IllegalStateException. * * @return the user's roster. - * @throws XMPPException if an error occurs on the XMPP protocol level. - * @throws SmackException if an error occurs somehwere else besides XMPP protocol level. + * @throws IllegalStateException if the connection is anonymous */ - public abstract Roster getRoster() throws XMPPException, SmackException; + public Roster getRoster() { + if (isAnonymous()) { + throw new IllegalStateException("Anonymous users can't have a roster"); + } + // synchronize against login() + synchronized(this) { + if (roster == null) { + roster = new Roster(this); + } + if (!isAuthenticated()) { + return roster; + } + } + // If this is the first time the user has asked for the roster after calling + // login, we want to wait for the server to send back the user's roster. This + // behavior shields API users from having to worry about the fact that roster + // operations are asynchronous, although they'll still have to listen for + // changes to the roster. Note: because of this waiting logic, internal + // Smack code should be wary about calling the getRoster method, and may need to + // access the roster object directly. + // Also only check for rosterInitalized is isRosterLoadedAtLogin is set, otherwise the user + // has to manually call Roster.reload() before he can expect a initialized roster. + if (!roster.rosterInitialized && config.isRosterLoadedAtLogin()) { + try { + synchronized (roster) { + long waitTime = SmackConfiguration.getDefaultPacketReplyTimeout(); + long start = System.currentTimeMillis(); + while (!roster.rosterInitialized) { + if (waitTime <= 0) { + break; + } + roster.wait(waitTime); + long now = System.currentTimeMillis(); + waitTime -= now - start; + start = now; + } + } + } + catch (InterruptedException ie) { + // Ignore. + } + } + return roster; + } /** * Returns the SASLAuthentication manager that is responsible for authenticating with * the server. @@ -944,6 +988,44 @@ public abstract class XMPPConnection { } } + void callConnectionConnectedListener() { + for (ConnectionListener listener : getConnectionListeners()) { + listener.connected(this); + } + } + + void callConnectionAuthenticatedListener() { + for (ConnectionListener listener : getConnectionListeners()) { + listener.connected(this); + } + } + + void callConnectionClosedListener() { + for (ConnectionListener listener : getConnectionListeners()) { + try { + listener.connectionClosed(); + } + catch (Exception e) { + // Catch and print any exception so we can recover + // from a faulty listener and finish the shutdown process + LOGGER.log(Level.SEVERE, "Error in listener while closing connection", e); + } + } + } + + void callConnectionClosedOnErrorListener(Exception e) { + for (ConnectionListener listener : getConnectionListeners()) { + try { + listener.connectionClosedOnError(e); + } + catch (Exception e2) { + // Catch and print any exception so we can recover + // from a faulty listener + LOGGER.log(Level.SEVERE, "Error in listener while closing connection", e2); + } + } + } + /** * A wrapper class to associate a packet filter with a listener. */ diff --git a/core/src/main/java/org/jivesoftware/smack/debugger/ConsoleDebugger.java b/core/src/main/java/org/jivesoftware/smack/debugger/ConsoleDebugger.java index e900d93f0..18200d93c 100644 --- a/core/src/main/java/org/jivesoftware/smack/debugger/ConsoleDebugger.java +++ b/core/src/main/java/org/jivesoftware/smack/debugger/ConsoleDebugger.java @@ -109,6 +109,14 @@ public class ConsoleDebugger implements SmackDebugger { }; connListener = new ConnectionListener() { + public void connected(XMPPConnection connection) { + System.out.println(dateFormatter.format(new Date()) + " XMPPConnection connected (" + + connection.hashCode() + ")"); + } + public void authenticated(XMPPConnection connection) { + System.out.println(dateFormatter.format(new Date()) + + " XMPPConnection authenticated (" + connection.hashCode() + ")"); + } public void connectionClosed() { System.out.println( dateFormatter.format(new Date()) + " XMPPConnection closed (" + diff --git a/debug/src/main/java/org/jivesoftware/smackx/debugger/EnhancedDebugger.java b/debug/src/main/java/org/jivesoftware/smackx/debugger/EnhancedDebugger.java index ec93ad470..11c0b5380 100644 --- a/debug/src/main/java/org/jivesoftware/smackx/debugger/EnhancedDebugger.java +++ b/debug/src/main/java/org/jivesoftware/smackx/debugger/EnhancedDebugger.java @@ -17,6 +17,7 @@ package org.jivesoftware.smackx.debugger; +import org.jivesoftware.smack.AbstractConnectionListener; import org.jivesoftware.smack.ConnectionListener; import org.jivesoftware.smack.PacketListener; import org.jivesoftware.smack.XMPPConnection; @@ -199,7 +200,7 @@ public class EnhancedDebugger implements SmackDebugger { }; // Create a thread that will listen for any connection closed event - connListener = new ConnectionListener() { + connListener = new AbstractConnectionListener() { public void connectionClosed() { SwingUtilities.invokeLater(new Runnable() { public void run() { diff --git a/extensions/src/main/java/org/jivesoftware/smackx/filetransfer/FileTransferNegotiator.java b/extensions/src/main/java/org/jivesoftware/smackx/filetransfer/FileTransferNegotiator.java index 561344d86..fbb6bc514 100644 --- a/extensions/src/main/java/org/jivesoftware/smackx/filetransfer/FileTransferNegotiator.java +++ b/extensions/src/main/java/org/jivesoftware/smackx/filetransfer/FileTransferNegotiator.java @@ -27,8 +27,8 @@ import java.util.Map; import java.util.Random; import java.util.concurrent.ConcurrentHashMap; +import org.jivesoftware.smack.AbstractConnectionListener; import org.jivesoftware.smack.XMPPConnection; -import org.jivesoftware.smack.ConnectionListener; import org.jivesoftware.smack.PacketCollector; import org.jivesoftware.smack.XMPPException.XMPPErrorException; import org.jivesoftware.smack.packet.IQ; @@ -215,26 +215,16 @@ public class FileTransferNegotiator { } private void configureConnection(final XMPPConnection connection) { - connection.addConnectionListener(new ConnectionListener() { + connection.addConnectionListener(new AbstractConnectionListener() { + @Override public void connectionClosed() { cleanup(connection); } + @Override public void connectionClosedOnError(Exception e) { cleanup(connection); } - - public void reconnectionFailed(Exception e) { - // ignore - } - - public void reconnectionSuccessful() { - // ignore - } - - public void reconnectingIn(int seconds) { - // ignore - } }); } diff --git a/extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChat.java b/extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChat.java index 1993453b0..04ee4dc9c 100644 --- a/extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChat.java +++ b/extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChat.java @@ -32,9 +32,9 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.logging.Level; import java.util.logging.Logger; +import org.jivesoftware.smack.AbstractConnectionListener; import org.jivesoftware.smack.Chat; import org.jivesoftware.smack.ConnectionCreationListener; -import org.jivesoftware.smack.ConnectionListener; import org.jivesoftware.smack.MessageListener; import org.jivesoftware.smack.PacketCollector; import org.jivesoftware.smack.PacketInterceptor; @@ -2338,7 +2338,7 @@ public class MultiUserChat { * * @author Gaston Dombiak */ - private static class InvitationsMonitor implements ConnectionListener { + private static class InvitationsMonitor extends AbstractConnectionListener { // We use a WeakHashMap so that the GC can collect the monitor when the // connection is no longer referenced by any object. // Note that when the InvitationsMonitor is used, i.e. when there are InvitationListeners, it will add a @@ -2447,26 +2447,11 @@ public class MultiUserChat { } } + @Override public void connectionClosed() { cancel(); } - public void connectionClosedOnError(Exception e) { - // ignore - } - - public void reconnectingIn(int seconds) { - // ignore - } - - public void reconnectionSuccessful() { - // ignore - } - - public void reconnectionFailed(Exception e) { - // ignore - } - /** * Initializes the listeners to detect received room invitations and to detect when the * connection gets closed. As soon as a room invitation is received the invitations diff --git a/extensions/src/main/java/org/jivesoftware/smackx/muc/RoomListenerMultiplexor.java b/extensions/src/main/java/org/jivesoftware/smackx/muc/RoomListenerMultiplexor.java index 1f5833347..aee730f9c 100644 --- a/extensions/src/main/java/org/jivesoftware/smackx/muc/RoomListenerMultiplexor.java +++ b/extensions/src/main/java/org/jivesoftware/smackx/muc/RoomListenerMultiplexor.java @@ -17,7 +17,7 @@ package org.jivesoftware.smackx.muc; -import org.jivesoftware.smack.ConnectionListener; +import org.jivesoftware.smack.AbstractConnectionListener; import org.jivesoftware.smack.PacketListener; import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smack.filter.PacketFilter; @@ -38,7 +38,7 @@ import java.util.concurrent.ConcurrentHashMap; * * @author Larry Kirschner */ -class RoomListenerMultiplexor implements ConnectionListener { +class RoomListenerMultiplexor extends AbstractConnectionListener { // We use a WeakHashMap so that the GC can collect the monitor when the // connection is no longer referenced by any object. @@ -98,26 +98,16 @@ class RoomListenerMultiplexor implements ConnectionListener { listener.addRoom(address, roomListener); } + @Override public void connectionClosed() { cancel(); } + @Override public void connectionClosedOnError(Exception e) { cancel(); } - public void reconnectingIn(int seconds) { - // ignore - } - - public void reconnectionSuccessful() { - // ignore - } - - public void reconnectionFailed(Exception e) { - // ignore - } - /** * Initializes the listeners to detect received room invitations and to detect when the * connection gets closed. As soon as a room invitation is received the invitations diff --git a/extensions/src/main/java/org/jivesoftware/smackx/ping/PingManager.java b/extensions/src/main/java/org/jivesoftware/smackx/ping/PingManager.java index 91e265863..8dc08ba21 100644 --- a/extensions/src/main/java/org/jivesoftware/smackx/ping/PingManager.java +++ b/extensions/src/main/java/org/jivesoftware/smackx/ping/PingManager.java @@ -26,11 +26,11 @@ import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; +import org.jivesoftware.smack.AbstractConnectionListener; import org.jivesoftware.smack.SmackException; import org.jivesoftware.smack.SmackException.NoResponseException; import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smack.ConnectionCreationListener; -import org.jivesoftware.smack.ConnectionListener; import org.jivesoftware.smack.Manager; import org.jivesoftware.smack.PacketListener; import org.jivesoftware.smack.XMPPException; @@ -134,7 +134,11 @@ public class PingManager extends Manager { connection().sendPacket(pong); } }, PING_PACKET_FILTER); - connection.addConnectionListener(new ConnectionListener() { + connection.addConnectionListener(new AbstractConnectionListener() { + @Override + public void authenticated(XMPPConnection connection) { + maybeSchedulePingServerTask(); + } @Override public void connectionClosed() { maybeStopPingServerTask(); @@ -143,14 +147,6 @@ public class PingManager extends Manager { public void connectionClosedOnError(Exception arg0) { maybeStopPingServerTask(); } - @Override - public void reconnectionSuccessful() { - maybeSchedulePingServerTask(); - } - @Override - public void reconnectingIn(int seconds) {} - @Override - public void reconnectionFailed(Exception e) {} }); maybeSchedulePingServerTask(); } diff --git a/jingle/src/main/java/org/jivesoftware/smackx/jingle/JingleSession.java b/jingle/src/main/java/org/jivesoftware/smackx/jingle/JingleSession.java index eedc44a88..cb7fa95af 100644 --- a/jingle/src/main/java/org/jivesoftware/smackx/jingle/JingleSession.java +++ b/jingle/src/main/java/org/jivesoftware/smackx/jingle/JingleSession.java @@ -23,6 +23,7 @@ import java.util.Map; import java.util.Random; import java.util.logging.Logger; +import org.jivesoftware.smack.AbstractConnectionListener; import org.jivesoftware.smack.ConnectionListener; import org.jivesoftware.smack.PacketListener; import org.jivesoftware.smack.SmackException; @@ -625,23 +626,16 @@ public class JingleSession extends JingleNegotiator implements MediaReceivedList */ private void installConnectionListeners(final XMPPConnection connection) { if (connection != null) { - connectionListener = new ConnectionListener() { + connectionListener = new AbstractConnectionListener() { + @Override public void connectionClosed() { unregisterInstanceFor(connection); } + @Override public void connectionClosedOnError(java.lang.Exception e) { unregisterInstanceFor(connection); } - - public void reconnectingIn(int i) { - } - - public void reconnectionSuccessful() { - } - - public void reconnectionFailed(Exception exception) { - } }; connection.addConnectionListener(connectionListener); } diff --git a/tcp/src/main/java/org/jivesoftware/smack/PacketReader.java b/tcp/src/main/java/org/jivesoftware/smack/PacketReader.java index bf5c392e7..17b737bd0 100644 --- a/tcp/src/main/java/org/jivesoftware/smack/PacketReader.java +++ b/tcp/src/main/java/org/jivesoftware/smack/PacketReader.java @@ -117,16 +117,7 @@ class PacketReader { public void shutdown() { // Notify connection listeners of the connection closing if done hasn't already been set. if (!done) { - for (ConnectionListener listener : connection.getConnectionListeners()) { - try { - listener.connectionClosed(); - } - catch (Exception e) { - // Catch and print any exception so we can recover - // from a faulty listener and finish the shutdown process - LOGGER.log(Level.SEVERE, "Error in listener while closing connection", e); - } - } + connection.callConnectionClosedListener(); } done = true; } diff --git a/tcp/src/main/java/org/jivesoftware/smack/TCPConnection.java b/tcp/src/main/java/org/jivesoftware/smack/TCPConnection.java index b17e26bce..46aff9ebe 100644 --- a/tcp/src/main/java/org/jivesoftware/smack/TCPConnection.java +++ b/tcp/src/main/java/org/jivesoftware/smack/TCPConnection.java @@ -93,8 +93,6 @@ public class TCPConnection extends XMPPConnection { PacketWriter packetWriter; PacketReader packetReader; - Roster roster = null; - /** * Collection of available stream compression methods offered by the server. */ @@ -266,14 +264,6 @@ public class TCPConnection extends XMPPConnection { authenticated = true; anonymous = false; - // Create the roster if it is not a reconnection or roster already created by getRoster() - if (this.roster == null) { - this.roster = new Roster(this); - } - if (config.isRosterLoadedAtLogin()) { - this.roster.reload(); - } - // Set presence to online. if (config.isSendPresence()) { packetWriter.sendPacket(new Presence(Presence.Type.available)); @@ -289,6 +279,7 @@ public class TCPConnection extends XMPPConnection { if (config.isDebuggerEnabled() && debugger != null) { debugger.userHasLogged(user); } + callConnectionAuthenticatedListener(); } @Override @@ -332,52 +323,7 @@ public class TCPConnection extends XMPPConnection { if (config.isDebuggerEnabled() && debugger != null) { debugger.userHasLogged(user); } - } - - public Roster getRoster() throws XMPPException, SmackException { - // synchronize against login() - synchronized(this) { - // if connection is authenticated the roster is already set by login() - // or a previous call to getRoster() - if (!isAuthenticated() || isAnonymous()) { - if (roster == null) { - roster = new Roster(this); - } - return roster; - } - } - - if (!config.isRosterLoadedAtLogin()) { - roster.reload(); - } - // If this is the first time the user has asked for the roster after calling - // login, we want to wait for the server to send back the user's roster. This - // behavior shields API users from having to worry about the fact that roster - // operations are asynchronous, although they'll still have to listen for - // changes to the roster. Note: because of this waiting logic, internal - // Smack code should be wary about calling the getRoster method, and may need to - // access the roster object directly. - if (!roster.rosterInitialized) { - try { - synchronized (roster) { - long waitTime = SmackConfiguration.getDefaultPacketReplyTimeout(); - long start = System.currentTimeMillis(); - while (!roster.rosterInitialized) { - if (waitTime <= 0) { - break; - } - roster.wait(waitTime); - long now = System.currentTimeMillis(); - waitTime -= now - start; - start = now; - } - } - } - catch (InterruptedException ie) { - // Ignore. - } - } - return roster; + callConnectionAuthenticatedListener(); } public boolean isConnected() { @@ -919,6 +865,11 @@ public class TCPConnection extends XMPPConnection { public void connect() throws SmackException, IOException, XMPPException { // Establishes the connection, readers and writers connectUsingConfiguration(config); + // TODO is there a case where connectUsing.. does not throw an exception but connected is + // still false? + if (connected) { + callConnectionConnectedListener(); + } // Automatically makes the login if the user was previously connected successfully // to the server and the connection was terminated abruptly if (connected && wasAuthenticated) { @@ -963,16 +914,7 @@ public class TCPConnection extends XMPPConnection { // Closes the connection temporary. A reconnection is possible shutdown(new Presence(Presence.Type.unavailable)); // Notify connection listeners of the error. - for (ConnectionListener listener : getConnectionListeners()) { - try { - listener.connectionClosedOnError(e); - } - catch (Exception e2) { - // Catch and print any exception so we can recover - // from a faulty listener - e2.printStackTrace(); - } - } + callConnectionClosedOnErrorListener(e); } /**