diff --git a/build/resources/META-INF/smack-config.xml b/build/resources/META-INF/smack-config.xml
index 42874aa98..9d6654de9 100644
--- a/build/resources/META-INF/smack-config.xml
+++ b/build/resources/META-INF/smack-config.xml
@@ -10,6 +10,7 @@
org.jivesoftware.smackx.muc.MultiUserChat
org.jivesoftware.smackx.filetransfer.FileTransferManager
org.jivesoftware.smackx.LastActivityManager
+ org.jivesoftware.smack.ReconnectionManager
diff --git a/source/org/jivesoftware/smack/ConnectionConfiguration.java b/source/org/jivesoftware/smack/ConnectionConfiguration.java
index bdb3e617a..a613604e8 100644
--- a/source/org/jivesoftware/smack/ConnectionConfiguration.java
+++ b/source/org/jivesoftware/smack/ConnectionConfiguration.java
@@ -20,6 +20,7 @@
package org.jivesoftware.smack;
+import javax.net.SocketFactory;
import java.io.File;
/**
@@ -54,6 +55,16 @@ public class ConnectionConfiguration implements Cloneable {
private boolean debuggerEnabled = XMPPConnection.DEBUG_ENABLED;
+ // Flag that indicates if a reconnection should be attempted when abruptly disconnected
+ private boolean reconnectionAllowed = true;
+
+ // Holds the socket factory that is used to generate the socket in the connection
+ private SocketFactory socketFactory;
+
+ // Holds the authentication information for future reconnections
+ private String username;
+ private String password;
+
public ConnectionConfiguration(String host, int port, String serviceName) {
this.host = host;
this.port = port;
@@ -354,4 +365,61 @@ public class ConnectionConfiguration implements Cloneable {
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
+
+ /**
+ * Sets if the reconnection mechanism is allowed to be used. By default
+ * reconnection is allowed.
+ *
+ * @param isAllowed if the reconnection mechanism is allowed to use.
+ */
+ public void setReconnectionAllowed(boolean isAllowed) {
+ this.reconnectionAllowed = isAllowed;
+ }
+ /**
+ * Returns if the reconnection mechanism is allowed to be used. By default
+ * reconnection is allowed.
+ *
+ * @return if the reconnection mechanism is allowed to be used.
+ */
+ public boolean isReconnectionAllowed() {
+ return this.reconnectionAllowed;
+ }
+
+ /**
+ * Sets the socket factory used to create new xmppConnection sockets.
+ * This is mainly used when reconnection is necessary.
+ *
+ * @param socketFactory used to create new sockets.
+ */
+ public void setSocketFactory(SocketFactory socketFactory) {
+ this.socketFactory = socketFactory;
+ }
+
+
+ /**
+ * Returns the socket factory used to create new xmppConnection sockets.
+ * This is mainly used when reconnection is necessary.
+ *
+ * @return socketFactory used to create new sockets.
+ */
+ public SocketFactory getSocketFactory() {
+ return this.socketFactory;
+ }
+
+ protected void setUsernameAndPassword(String username, String password) {
+ this.username = username;
+ this.password = password;
+ }
+ /**
+ * Returns the username used to login
+ */
+ protected String getUsername() {
+ return this.username;
+ }
+ /**
+ * Returns the password used to login
+ */
+ protected String getPassword() {
+ return this.password;
+ }
}
diff --git a/source/org/jivesoftware/smack/ConnectionListener.java b/source/org/jivesoftware/smack/ConnectionListener.java
index 69bc854f3..4f62df183 100644
--- a/source/org/jivesoftware/smack/ConnectionListener.java
+++ b/source/org/jivesoftware/smack/ConnectionListener.java
@@ -22,7 +22,7 @@ package org.jivesoftware.smack;
/**
* Interface that allows for implementing classes to listen for connection closing
- * events. Listeners are registered with XMPPConnection objects.
+ * and reconnection events. Listeners are registered with XMPPConnection objects.
*
* @see XMPPConnection#addConnectionListener
* @see XMPPConnection#removeConnectionListener
@@ -32,14 +32,36 @@ package org.jivesoftware.smack;
public interface ConnectionListener {
/**
- * Notification that the connection was closed normally.
+ * Notification that the connection was closed normally or that the reconnection
+ * process has been aborted.
*/
public void connectionClosed();
/**
- * Notification that the connection was closed due to an exception.
+ * Notification that the connection was closed due to an exception. When
+ * abruptly disconnected it is possible for the connection to try reconnecting
+ * to the server.
*
* @param e the exception.
*/
public void connectionClosedOnError(Exception e);
+
+ /**
+ * The connection will retry to reconnect in the specified number of seconds.
+ *
+ * @param seconds remaining seconds before attempting a reconnection.
+ */
+ public void reconnectingIn(int seconds);
+
+ /**
+ * The connection has reconnected successfully to the server. Connections will
+ * reconnect to the server when the previous socket connection was abruptly closed.
+ */
+ public void reconectionSuccessful();
+
+ /**
+ * An attempt to connect to the server has failed. The connection will keep trying
+ * reconnecting to the server in a moment.
+ */
+ public void reconnectionFailed(Exception e);
}
\ No newline at end of file
diff --git a/source/org/jivesoftware/smack/PacketReader.java b/source/org/jivesoftware/smack/PacketReader.java
index 91075495d..26e5c4db2 100644
--- a/source/org/jivesoftware/smack/PacketReader.java
+++ b/source/org/jivesoftware/smack/PacketReader.java
@@ -44,12 +44,12 @@ import java.util.concurrent.TimeUnit;
*/
class PacketReader {
- private final Thread readerThread;
- private final Thread listenerThread;
+ private Thread readerThread;
+ private Thread listenerThread;
private XMPPConnection connection;
private XmlPullParser parser;
- private boolean done = false;
+ private boolean done;
private final VolatileMemberCollection collectors =
new VolatileMemberCollection(50);
protected final VolatileMemberCollection listeners = new VolatileMemberCollection(50);
@@ -61,10 +61,20 @@ class PacketReader {
protected PacketReader(XMPPConnection connection) {
this.connection = connection;
+ this.init();
+ }
+
+ /**
+ * Initializes the reader in order to be used. The reader is initialized during the
+ * first connection and when reconnecting due to an abruptly disconnection.
+ */
+ protected void init() {
+ done = false;
+ connectionID = null;
readerThread = new Thread() {
public void run() {
- parsePackets();
+ parsePackets(this);
}
};
readerThread.setName("Smack Packet Reader");
@@ -73,7 +83,7 @@ class PacketReader {
listenerThread = new Thread() {
public void run() {
try {
- processListeners();
+ processListeners(this);
}
catch (Exception e) {
e.printStackTrace();
@@ -195,7 +205,8 @@ class PacketReader {
*/
void notifyConnectionError(Exception e) {
done = true;
- connection.close();
+ // Closes the connection temporary. A reconnection is possible
+ connection.shutdown();
// Print the stack trace to help catch the problem
e.printStackTrace();
// Notify connection listeners of the error.
@@ -214,6 +225,26 @@ class PacketReader {
}
}
+ /**
+ * Sends a notification indicating that the connection was reconnected successfully.
+ */
+ protected void notifyReconnection() {
+ // Notify connection listeners of the reconnection.
+ List listenersCopy;
+ synchronized (connectionListeners) {
+ // Make a copy since it's possible that a listener will be removed from the list
+ listenersCopy = new ArrayList(connectionListeners);
+ for (ConnectionListener listener : listenersCopy) {
+ listener.reconectionSuccessful();
+ }
+ }
+
+ // Make sure that the listenerThread is awake to shutdown properly
+ synchronized (listenerThread) {
+ listenerThread.notify();
+ }
+ }
+
/**
* Resets the parser using the latest connection's reader. Reseting the parser is necessary
* when the plain connection has been secured or when a new opening stream element is going
@@ -232,9 +263,11 @@ class PacketReader {
/**
* Process listeners.
+ *
+ * @param thread the thread that is being used by the reader to process incoming packets.
*/
- private void processListeners() {
- while (!done) {
+ private void processListeners(Thread thread) {
+ while (!done && thread == listenerThread) {
boolean processedPacket = false;
Iterator it = listeners.getIterator();
while (it.hasNext()) {
@@ -257,8 +290,10 @@ class PacketReader {
/**
* Parse top-level packets in order to process them further.
+ *
+ * @param thread the thread that is being used by the reader to parse incoming packets.
*/
- private void parsePackets() {
+ private void parsePackets(Thread thread) {
try {
int eventType = parser.getEventType();
do {
@@ -356,12 +391,12 @@ class PacketReader {
}
else if (eventType == XmlPullParser.END_TAG) {
if (parser.getName().equals("stream")) {
- // Close the connection.
- connection.close();
+ // Disconnect the connection
+ connection.disconnect();
}
}
eventType = parser.next();
- } while (!done && eventType != XmlPullParser.END_DOCUMENT);
+ } while (!done && eventType != XmlPullParser.END_DOCUMENT && thread == readerThread);
}
catch (Exception e) {
if (!done) {
@@ -470,7 +505,7 @@ class PacketReader {
}
}
}
- // Release the lock after TLS has been negotiated or we are not insterested in TLS
+ // Release the lock after TLS has been negotiated or we are not insterested in TLS
if (!startTLSReceived || !connection.getConfiguration().isTLSEnabled()) {
releaseConnectionIDLock();
}
@@ -873,7 +908,7 @@ class PacketReader {
/**
* A wrapper class to associate a packet collector with a listener.
*/
- private static class ListenerWrapper {
+ protected static class ListenerWrapper {
private PacketListener packetListener;
private PacketCollector packetCollector;
diff --git a/source/org/jivesoftware/smack/PacketWriter.java b/source/org/jivesoftware/smack/PacketWriter.java
index 164c551c8..b516cfaf9 100644
--- a/source/org/jivesoftware/smack/PacketWriter.java
+++ b/source/org/jivesoftware/smack/PacketWriter.java
@@ -39,13 +39,14 @@ import java.util.List;
class PacketWriter {
private Thread writerThread;
+ private Thread keepAliveThread;
private Writer writer;
private XMPPConnection connection;
final private LinkedList queue;
- private boolean done = false;
+ private boolean done;
- final private List listeners = new ArrayList();
- private boolean listenersDeleted = false;
+ final protected List listeners = new ArrayList();
+ private boolean listenersDeleted;
/**
* Timestamp when the last stanza was sent to the server. This information is used
@@ -70,13 +71,24 @@ class PacketWriter {
* @param connection the connection.
*/
protected PacketWriter(XMPPConnection connection) {
- this.connection = connection;
- this.writer = connection.writer;
this.queue = new LinkedList();
+ this.connection = connection;
+ init();
+ }
+
+ /**
+ * Initializes the writer in order to be used. It is called at the first connection and also
+ * is invoked if the connection is disconnected by an error.
+ */
+ protected void init() {
+ this.writer = connection.writer;
+ listenersDeleted = false;
+ interceptorDeleted = false;
+ done = false;
writerThread = new Thread() {
public void run() {
- writePackets();
+ writePackets(this);
}
};
writerThread.setName("Smack Packet Writer");
@@ -205,8 +217,11 @@ class PacketWriter {
// out a space character each time it runs to keep the TCP/IP connection open.
int keepAliveInterval = SmackConfiguration.getKeepAliveInterval();
if (keepAliveInterval > 0) {
- Thread keepAliveThread = new Thread(new KeepAliveTask(keepAliveInterval));
+ KeepAliveTask target = new KeepAliveTask(keepAliveInterval);
+ keepAliveThread = new Thread(target);
+ target.setThread(keepAliveThread);
keepAliveThread.setDaemon(true);
+ keepAliveThread.setName("Smack Keep Alive");
keepAliveThread.start();
}
}
@@ -247,12 +262,12 @@ class PacketWriter {
}
}
- private void writePackets() {
+ private void writePackets(Thread thisThread) {
try {
// Open the stream.
openStream();
// Write out packets from the queue.
- while (!done) {
+ while (!done && (writerThread == thisThread)) {
Packet packet = nextPacket();
if (packet != null) {
synchronized (writer) {
@@ -370,7 +385,7 @@ class PacketWriter {
/**
* A wrapper class to associate a packet filter with a listener.
*/
- private static class ListenerWrapper {
+ protected static class ListenerWrapper {
private PacketListener packetListener;
private PacketFilter packetFilter;
@@ -444,11 +459,16 @@ class PacketWriter {
private class KeepAliveTask implements Runnable {
private int delay;
+ private Thread thread;
public KeepAliveTask(int delay) {
this.delay = delay;
}
+ protected void setThread(Thread thread) {
+ this.thread = thread;
+ }
+
public void run() {
try {
// Sleep 15 seconds before sending first heartbeat. This will give time to
@@ -458,7 +478,7 @@ class PacketWriter {
catch (InterruptedException ie) {
// Do nothing
}
- while (!done) {
+ while (!done && keepAliveThread == thread) {
synchronized (writer) {
// Send heartbeat if no packet has been sent to the server for a given time
if (System.currentTimeMillis() - lastActive >= delay) {
diff --git a/source/org/jivesoftware/smack/PrivacyListManager.java b/source/org/jivesoftware/smack/PrivacyListManager.java
index ce79d6e4e..93febcbd5 100644
--- a/source/org/jivesoftware/smack/PrivacyListManager.java
+++ b/source/org/jivesoftware/smack/PrivacyListManager.java
@@ -71,24 +71,27 @@ public class PrivacyListManager {
// the connection is closed
connection.addConnectionListener(new ConnectionListener() {
public void connectionClosed() {
- // Unregister this instance since the connection has been closed
+ // Unregister this instance since the connection has been closed
instances.remove(connection);
}
public void connectionClosedOnError(Exception e) {
// ignore
}
+
public void reconnectionFailed(Exception e) {
// ignore
}
- public void attemptToReconnectIn(int seconds) {
+
+ public void reconnectingIn(int seconds) {
// ignore
}
- public void conectionReestablished() {
+
+ public void reconectionSuccessful() {
// ignore
}
});
-
+
connection.addPacketListener(new PacketListener() {
public void processPacket(Packet packet) {
diff --git a/source/org/jivesoftware/smack/SASLAuthentication.java b/source/org/jivesoftware/smack/SASLAuthentication.java
index f8f531418..9904f04fe 100644
--- a/source/org/jivesoftware/smack/SASLAuthentication.java
+++ b/source/org/jivesoftware/smack/SASLAuthentication.java
@@ -68,14 +68,14 @@ public class SASLAuthentication implements UserAuthentication {
/**
* Boolean indicating if SASL negotiation has finished and was successful.
*/
- private boolean saslNegotiated = false;
+ private boolean saslNegotiated;
/**
* Boolean indication if SASL authentication has failed. When failed the server may end
* the connection.
*/
- private boolean saslFailed = false;
- private boolean resourceBinded = false;
- private boolean sessionSupported = false;
+ private boolean saslFailed;
+ private boolean resourceBinded;
+ private boolean sessionSupported;
static {
// Register SASL mechanisms supported by Smack
@@ -126,6 +126,7 @@ public class SASLAuthentication implements UserAuthentication {
SASLAuthentication(XMPPConnection connection) {
super();
this.connection = connection;
+ this.init();
}
/**
@@ -413,4 +414,16 @@ public class SASLAuthentication implements UserAuthentication {
void sessionsSupported() {
sessionSupported = true;
}
+
+ /**
+ * Initializes the internal state in order to be able to be reused. The authentication
+ * is used by the connection at the first login and then reused after the connection
+ * is disconnected and then reconnected.
+ */
+ protected void init() {
+ saslNegotiated = false;
+ saslFailed = false;
+ resourceBinded = false;
+ sessionSupported = false;
+ }
}
diff --git a/source/org/jivesoftware/smack/debugger/ConsoleDebugger.java b/source/org/jivesoftware/smack/debugger/ConsoleDebugger.java
index a3757cb2a..e4db9fe78 100644
--- a/source/org/jivesoftware/smack/debugger/ConsoleDebugger.java
+++ b/source/org/jivesoftware/smack/debugger/ConsoleDebugger.java
@@ -108,6 +108,26 @@ public class ConsoleDebugger implements SmackDebugger {
")");
e.printStackTrace();
}
+ public void reconnectionFailed(Exception e) {
+ System.out.println(
+ dateFormatter.format(new Date()) +
+ " Reconnection failed due to an exception (" +
+ connection.hashCode() +
+ ")");
+ e.printStackTrace();
+ }
+ public void reconectionSuccessful() {
+ System.out.println(
+ dateFormatter.format(new Date()) + " Connection reconnected (" +
+ connection.hashCode() +
+ ")");
+ }
+ public void reconnectingIn(int seconds) {
+ System.out.println(
+ dateFormatter.format(new Date()) + " Connection (" +
+ connection.hashCode() +
+ ") will reconnect in " + seconds);
+ }
};
}
diff --git a/source/org/jivesoftware/smack/packet/XMPPError.java b/source/org/jivesoftware/smack/packet/XMPPError.java
index 89aef8723..8b1b0566a 100644
--- a/source/org/jivesoftware/smack/packet/XMPPError.java
+++ b/source/org/jivesoftware/smack/packet/XMPPError.java
@@ -20,10 +20,7 @@
package org.jivesoftware.smack.packet;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
+import java.util.*;
/**
* Represents a XMPP error sub-packet. Typically, a server responds to a request that has
@@ -79,8 +76,8 @@ public class XMPPError {
* @param condition the error condition.
*/
public XMPPError(Condition condition) {
- this.init(condition);
- this.message = null;
+ this.init(condition);
+ this.message = null;
}
/**
@@ -97,7 +94,7 @@ public class XMPPError {
this.init(condition);
this.message = messageText;
}
-
+
/**
* Creates a new error with the specified code and no message.
*
@@ -108,7 +105,7 @@ public class XMPPError {
this.code = code;
this.message = null;
}
-
+
/**
* Creates a new error with the specified code and message.
* deprecated
@@ -121,8 +118,7 @@ public class XMPPError {
this.code = code;
this.message = message;
}
-
-
+
/**
* Creates a new error with the specified code, type, condition and message.
* This constructor is used when the condition is not recognized automatically by XMPPError
@@ -156,7 +152,7 @@ public class XMPPError {
// If there is a default error specification for the received condition,
// it get configured with the infered type and code.
this.type = defaultErrorSpecification.getType();
- this.code = defaultErrorSpecification.getCode();
+ this.code = defaultErrorSpecification.getCode();
}
}
/**
@@ -167,7 +163,7 @@ public class XMPPError {
public String getCondition() {
return condition;
}
-
+
/**
* Returns the error type.
*
@@ -176,7 +172,7 @@ public class XMPPError {
public Type getType() {
return type;
}
-
+
/**
* Returns the error code.
*
@@ -210,17 +206,17 @@ public class XMPPError {
}
buf.append(">");
if (condition != null) {
- buf.append("<").append(condition);
- buf.append(" xmlns=\"urn:ietf:params:xml:ns:xmpp-stanzas\"/>");
+ buf.append("<").append(condition);
+ buf.append(" xmlns=\"urn:ietf:params:xml:ns:xmpp-stanzas\"/>");
}
if (message != null) {
- buf.append("");
- buf.append(message);
- buf.append("");
+ buf.append("");
+ buf.append(message);
+ buf.append("");
}
for (PacketExtension element : this.getExtensions()) {
- buf.append(element.toXML());
- }
+ buf.append(element.toXML());
+ }
buf.append("");
return buf.toString();
}
@@ -270,7 +266,7 @@ public class XMPPError {
}
return null;
}
-
+
/**
* Adds a packet extension to the error.
*
@@ -278,7 +274,7 @@ public class XMPPError {
*/
public synchronized void addExtension(PacketExtension extension) {
if (applicationExtensions == null) {
- applicationExtensions = new ArrayList();
+ applicationExtensions = new ArrayList();
}
applicationExtensions.add(extension);
}
@@ -289,10 +285,9 @@ public class XMPPError {
* @param extension a packet extension.
*/
public synchronized void setExtension(List extension) {
- applicationExtensions = extension;
+ applicationExtensions = extension;
}
-
-
+
/**
* A class to represent the type of the Error. The types are:
*
@@ -311,7 +306,7 @@ public class XMPPError {
AUTH,
CONTINUE
}
-
+
/**
* A class to represent predefined error conditions.
*/
@@ -341,7 +336,7 @@ public class XMPPError {
public static final Condition undefined_condition = new Condition("undefined-condition");
public static final Condition unexpected_condition = new Condition("unexpected-condition");
public static final Condition request_timeout = new Condition("request-timeout");
-
+
private String value;
public Condition(String value) {
@@ -353,80 +348,80 @@ public class XMPPError {
}
}
-
+
/**
* A class to represent the error specification used to infer common usage.
*/
private static class ErrorSpecification {
- private int code;
+ private int code;
private Type type;
private Condition condition;
- private static HashMap instances = errorSpecifications();
+ private static Map instances = errorSpecifications();
private ErrorSpecification(Condition condition, Type type, int code) {
- this.code = code;
- this.type = type;
- this.condition = condition;
+ this.code = code;
+ this.type = type;
+ this.condition = condition;
}
-
- private static HashMap errorSpecifications() {
- HashMap instances = new HashMap(22);
- instances.put(Condition.interna_server_error, new ErrorSpecification(
- Condition.interna_server_error, Type.WAIT, 500));
- instances.put(Condition.forbidden, new ErrorSpecification(Condition.forbidden,
- Type.AUTH, 403));
- instances.put(Condition.bad_request, new XMPPError.ErrorSpecification(
- Condition.bad_request, Type.MODIFY, 400));
- instances.put(Condition.item_not_found, new XMPPError.ErrorSpecification(
- Condition.item_not_found, Type.CANCEL, 404));
- instances.put(Condition.conflict, new XMPPError.ErrorSpecification(
- Condition.conflict, Type.CANCEL, 409));
- instances.put(Condition.feature_not_implemented, new XMPPError.ErrorSpecification(
- Condition.feature_not_implemented, Type.CANCEL, 501));
- instances.put(Condition.gone, new XMPPError.ErrorSpecification(
- Condition.gone, Type.MODIFY, 302));
- instances.put(Condition.jid_malformed, new XMPPError.ErrorSpecification(
- Condition.jid_malformed, Type.MODIFY, 400));
- instances.put(Condition.no_acceptable, new XMPPError.ErrorSpecification(
- Condition.no_acceptable, Type.MODIFY, 406));
- instances.put(Condition.not_allowed, new XMPPError.ErrorSpecification(
- Condition.not_allowed, Type.CANCEL, 405));
- instances.put(Condition.not_authorized, new XMPPError.ErrorSpecification(
- Condition.not_authorized, Type.AUTH, 401));
- instances.put(Condition.payment_required, new XMPPError.ErrorSpecification(
- Condition.payment_required, Type.AUTH, 402));
- instances.put(Condition.recipient_unavailable, new XMPPError.ErrorSpecification(
- Condition.recipient_unavailable, Type.WAIT, 404));
- instances.put(Condition.redirect, new XMPPError.ErrorSpecification(
- Condition.redirect, Type.MODIFY, 302));
- instances.put(Condition.registration_required, new XMPPError.ErrorSpecification(
- Condition.registration_required, Type.AUTH, 407));
- instances.put(Condition.remote_server_not_found, new XMPPError.ErrorSpecification(
- Condition.remote_server_not_found, Type.CANCEL, 404));
- instances.put(Condition.remote_server_timeout, new XMPPError.ErrorSpecification(
- Condition.remote_server_timeout, Type.WAIT, 504));
- instances.put(Condition.remote_server_error, new XMPPError.ErrorSpecification(
- Condition.remote_server_error, Type.CANCEL, 502));
- instances.put(Condition.resource_constraint, new XMPPError.ErrorSpecification(
- Condition.resource_constraint, Type.WAIT, 500));
- instances.put(Condition.service_unavailable, new XMPPError.ErrorSpecification(
- Condition.service_unavailable, Type.CANCEL, 503));
- instances.put(Condition.subscription_required, new XMPPError.ErrorSpecification(
- Condition.subscription_required, Type.AUTH, 407));
- instances.put(Condition.undefined_condition, new XMPPError.ErrorSpecification(
- Condition.undefined_condition, Type.WAIT, 500));
- instances.put(Condition.unexpected_condition, new XMPPError.ErrorSpecification(
- Condition.unexpected_condition, Type.WAIT, 400));
+
+ private static Map errorSpecifications() {
+ Map instances = new HashMap(22);
+ instances.put(Condition.interna_server_error, new ErrorSpecification(
+ Condition.interna_server_error, Type.WAIT, 500));
+ instances.put(Condition.forbidden, new ErrorSpecification(Condition.forbidden,
+ Type.AUTH, 403));
+ instances.put(Condition.bad_request, new XMPPError.ErrorSpecification(
+ Condition.bad_request, Type.MODIFY, 400));
+ instances.put(Condition.item_not_found, new XMPPError.ErrorSpecification(
+ Condition.item_not_found, Type.CANCEL, 404));
+ instances.put(Condition.conflict, new XMPPError.ErrorSpecification(
+ Condition.conflict, Type.CANCEL, 409));
+ instances.put(Condition.feature_not_implemented, new XMPPError.ErrorSpecification(
+ Condition.feature_not_implemented, Type.CANCEL, 501));
+ instances.put(Condition.gone, new XMPPError.ErrorSpecification(
+ Condition.gone, Type.MODIFY, 302));
+ instances.put(Condition.jid_malformed, new XMPPError.ErrorSpecification(
+ Condition.jid_malformed, Type.MODIFY, 400));
+ instances.put(Condition.no_acceptable, new XMPPError.ErrorSpecification(
+ Condition.no_acceptable, Type.MODIFY, 406));
+ instances.put(Condition.not_allowed, new XMPPError.ErrorSpecification(
+ Condition.not_allowed, Type.CANCEL, 405));
+ instances.put(Condition.not_authorized, new XMPPError.ErrorSpecification(
+ Condition.not_authorized, Type.AUTH, 401));
+ instances.put(Condition.payment_required, new XMPPError.ErrorSpecification(
+ Condition.payment_required, Type.AUTH, 402));
+ instances.put(Condition.recipient_unavailable, new XMPPError.ErrorSpecification(
+ Condition.recipient_unavailable, Type.WAIT, 404));
+ instances.put(Condition.redirect, new XMPPError.ErrorSpecification(
+ Condition.redirect, Type.MODIFY, 302));
+ instances.put(Condition.registration_required, new XMPPError.ErrorSpecification(
+ Condition.registration_required, Type.AUTH, 407));
+ instances.put(Condition.remote_server_not_found, new XMPPError.ErrorSpecification(
+ Condition.remote_server_not_found, Type.CANCEL, 404));
+ instances.put(Condition.remote_server_timeout, new XMPPError.ErrorSpecification(
+ Condition.remote_server_timeout, Type.WAIT, 504));
+ instances.put(Condition.remote_server_error, new XMPPError.ErrorSpecification(
+ Condition.remote_server_error, Type.CANCEL, 502));
+ instances.put(Condition.resource_constraint, new XMPPError.ErrorSpecification(
+ Condition.resource_constraint, Type.WAIT, 500));
+ instances.put(Condition.service_unavailable, new XMPPError.ErrorSpecification(
+ Condition.service_unavailable, Type.CANCEL, 503));
+ instances.put(Condition.subscription_required, new XMPPError.ErrorSpecification(
+ Condition.subscription_required, Type.AUTH, 407));
+ instances.put(Condition.undefined_condition, new XMPPError.ErrorSpecification(
+ Condition.undefined_condition, Type.WAIT, 500));
+ instances.put(Condition.unexpected_condition, new XMPPError.ErrorSpecification(
+ Condition.unexpected_condition, Type.WAIT, 400));
instances.put(Condition.request_timeout, new XMPPError.ErrorSpecification(
Condition.request_timeout, Type.CANCEL, 408));
-
- return instances;
- }
+
+ return instances;
+ }
protected static ErrorSpecification specFor(Condition condition) {
- return instances.get(condition);
+ return instances.get(condition);
}
-
+
/**
* Returns the error condition.
*
@@ -435,7 +430,7 @@ public class XMPPError {
protected Condition getCondition() {
return condition;
}
-
+
/**
* Returns the error type.
*
@@ -444,7 +439,7 @@ public class XMPPError {
protected Type getType() {
return type;
}
-
+
/**
* Returns the error code.
*
diff --git a/source/org/jivesoftware/smackx/ServiceDiscoveryManager.java b/source/org/jivesoftware/smackx/ServiceDiscoveryManager.java
index f83588b45..5c1fefe22 100644
--- a/source/org/jivesoftware/smackx/ServiceDiscoveryManager.java
+++ b/source/org/jivesoftware/smackx/ServiceDiscoveryManager.java
@@ -150,8 +150,19 @@ public class ServiceDiscoveryManager {
}
public void connectionClosedOnError(Exception e) {
- // Unregister this instance since the connection has been closed
- instances.remove(connection);
+ // ignore
+ }
+
+ public void reconnectionFailed(Exception e) {
+ // ignore
+ }
+
+ public void reconnectingIn(int seconds) {
+ // ignore
+ }
+
+ public void reconectionSuccessful() {
+ // ignore
}
});
diff --git a/source/org/jivesoftware/smackx/debugger/EnhancedDebugger.java b/source/org/jivesoftware/smackx/debugger/EnhancedDebugger.java
index 3e1a078cd..3f02a6761 100644
--- a/source/org/jivesoftware/smackx/debugger/EnhancedDebugger.java
+++ b/source/org/jivesoftware/smackx/debugger/EnhancedDebugger.java
@@ -218,6 +218,30 @@ public class EnhancedDebugger implements SmackDebugger {
});
}
+ public void reconnectingIn(final int seconds){
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ statusField.setValue("Attempt to reconnect in " + seconds + " seconds");
+ }
+ });
+ }
+
+ public void reconectionSuccessful() {
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ statusField.setValue("Reconnection stablished");
+ EnhancedDebuggerWindow.connectionEstablished(EnhancedDebugger.this);
+ }
+ });
+ }
+
+ public void reconnectionFailed(Exception e) {
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ statusField.setValue("Reconnection failed");
+ }
+ });
+ }
};
}
@@ -551,7 +575,7 @@ public class EnhancedDebugger implements SmackDebugger {
connPanel.add(
label,
new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0, 21, 0, new Insets(0, 0, 0, 0), 0, 0));
- field = new JFormattedTextField(new Integer(connection.getPort()));
+ field = new JFormattedTextField(connection.getPort());
field.setMinimumSize(new java.awt.Dimension(150, 20));
field.setMaximumSize(new java.awt.Dimension(150, 20));
field.setEditable(false);
@@ -618,16 +642,9 @@ public class EnhancedDebugger implements SmackDebugger {
packetsPanel.setBorder(BorderFactory.createTitledBorder("Transmitted Packets"));
statisticsTable =
- new DefaultTableModel(new Object[][]{{"IQ", new Integer(0), new Integer(0)}, {
- "Message", new Integer(0), new Integer(0)
- }, {
- "Presence", new Integer(0), new Integer(0)
- }, {
- "Other", new Integer(0), new Integer(0)
- }, {
- "Total", new Integer(0), new Integer(0)
- }
- }, new Object[]{"Type", "Received", "Sent"}) {
+ new DefaultTableModel(new Object[][]{{"IQ", 0, 0}, {"Message", 0, 0},
+ {"Presence", 0, 0}, {"Other", 0, 0}, {"Total", 0, 0}},
+ new Object[]{"Type", "Received", "Sent"}) {
public boolean isCellEditable(int rowIndex, int mColIndex) {
return false;
}
@@ -719,7 +736,7 @@ public class EnhancedDebugger implements SmackDebugger {
private void addReadPacketToTable(final SimpleDateFormat dateFormatter, final Packet packet) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
- String messageType = null;
+ String messageType;
String from = packet.getFrom();
String type = "";
Icon packetTypeIcon;
@@ -780,7 +797,7 @@ public class EnhancedDebugger implements SmackDebugger {
private void addSentPacketToTable(final SimpleDateFormat dateFormatter, final Packet packet) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
- String messageType = null;
+ String messageType;
String to = packet.getTo();
String type = "";
Icon packetTypeIcon;
@@ -840,9 +857,10 @@ public class EnhancedDebugger implements SmackDebugger {
// Surround this setting in a try/catch for compatibility with Java 1.4. This setting is required
// for Java 1.5
try {
- tFactory.setAttribute("indent-number", new Integer(2));
+ tFactory.setAttribute("indent-number", 2);
}
catch (IllegalArgumentException e) {
+ // Ignore
}
Transformer transformer = tFactory.newTransformer();
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
diff --git a/source/org/jivesoftware/smackx/debugger/EnhancedDebuggerWindow.java b/source/org/jivesoftware/smackx/debugger/EnhancedDebuggerWindow.java
index 741783ab5..75eb952cb 100644
--- a/source/org/jivesoftware/smackx/debugger/EnhancedDebuggerWindow.java
+++ b/source/org/jivesoftware/smackx/debugger/EnhancedDebuggerWindow.java
@@ -29,7 +29,6 @@ import java.awt.event.*;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
-import java.util.Iterator;
import java.util.Vector;
/**
@@ -90,7 +89,7 @@ public class EnhancedDebuggerWindow {
private JFrame frame = null;
private JTabbedPane tabbedPane = null;
- private java.util.List debuggers = new ArrayList();
+ private java.util.List debuggers = new ArrayList();
private EnhancedDebuggerWindow() {
}
@@ -178,6 +177,12 @@ public class EnhancedDebuggerWindow {
connectionClosedOnErrorIcon);
}
+ synchronized static void connectionEstablished(EnhancedDebugger debugger) {
+ getInstance().tabbedPane.setIconAt(
+ getInstance().tabbedPane.indexOfComponent(debugger.tabbedPane),
+ connectionActiveIcon);
+ }
+
/**
* Creates the main debug window that provides information about Smack and also shows
* a tab panel for each connection that is being debugged.
@@ -264,7 +269,7 @@ public class EnhancedDebuggerWindow {
if (tabbedPane.getSelectedIndex() < tabbedPane.getComponentCount() - 1) {
int index = tabbedPane.getSelectedIndex();
// Notify to the debugger to stop debugging
- EnhancedDebugger debugger = (EnhancedDebugger) debuggers.get(index);
+ EnhancedDebugger debugger = debuggers.get(index);
debugger.cancel();
// Remove the debugger from the root window
tabbedPane.remove(debugger.tabbedPane);
@@ -281,18 +286,17 @@ public class EnhancedDebuggerWindow {
menuItem = new JMenuItem("Close All Not Active");
menuItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
- ArrayList debuggersToRemove = new ArrayList();
+ ArrayList debuggersToRemove = new ArrayList();
// Remove all the debuggers of which their connections are no longer valid
for (int index = 0; index < tabbedPane.getComponentCount() - 1; index++) {
- EnhancedDebugger debugger = (EnhancedDebugger) debuggers.get(index);
+ EnhancedDebugger debugger = debuggers.get(index);
if (!debugger.isConnectionActive()) {
// Notify to the debugger to stop debugging
debugger.cancel();
debuggersToRemove.add(debugger);
}
}
- for (Iterator it = debuggersToRemove.iterator(); it.hasNext();) {
- EnhancedDebugger debugger = (EnhancedDebugger) it.next();
+ for (EnhancedDebugger debugger : debuggersToRemove) {
// Remove the debugger from the root window
tabbedPane.remove(debugger.tabbedPane);
debuggers.remove(debugger);
@@ -324,8 +328,7 @@ public class EnhancedDebuggerWindow {
*/
public void rootWindowClosing(WindowEvent evt) {
// Notify to all the debuggers to stop debugging
- for (Iterator it = debuggers.iterator(); it.hasNext();) {
- EnhancedDebugger debugger = (EnhancedDebugger) it.next();
+ for (EnhancedDebugger debugger : debuggers) {
debugger.cancel();
}
// Release any reference to the debuggers
diff --git a/source/org/jivesoftware/smackx/filetransfer/FileTransferNegotiator.java b/source/org/jivesoftware/smackx/filetransfer/FileTransferNegotiator.java
index c6febc2de..de426b9d4 100644
--- a/source/org/jivesoftware/smackx/filetransfer/FileTransferNegotiator.java
+++ b/source/org/jivesoftware/smackx/filetransfer/FileTransferNegotiator.java
@@ -35,6 +35,7 @@ import org.jivesoftware.smackx.packet.StreamInitiation;
import java.net.URLConnection;
import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
/**
* Manages the negotiation of file transfers according to JEP-0096. If a file is
@@ -64,7 +65,8 @@ public class FileTransferNegotiator {
private static final String[] PROTOCOLS = {BYTE_STREAM, INBAND_BYTE_STREAM};
- private static final Map transferObject = new HashMap();
+ private static final Map transferObject =
+ new ConcurrentHashMap();
private static final String STREAM_INIT_PREFIX = "jsi_";
@@ -92,7 +94,7 @@ public class FileTransferNegotiator {
}
if (transferObject.containsKey(connection)) {
- return (FileTransferNegotiator) transferObject.get(connection);
+ return transferObject.get(connection);
}
else {
FileTransferNegotiator transfer = new FileTransferNegotiator(
@@ -114,12 +116,12 @@ public class FileTransferNegotiator {
final boolean isEnabled) {
ServiceDiscoveryManager manager = ServiceDiscoveryManager
.getInstanceFor(connection);
- for (int i = 0; i < NAMESPACE.length; i++) {
+ for (String ns : NAMESPACE) {
if (isEnabled) {
- manager.addFeature(NAMESPACE[i]);
+ manager.addFeature(ns);
}
else {
- manager.removeFeature(NAMESPACE[i]);
+ manager.removeFeature(ns);
}
}
}
@@ -132,9 +134,8 @@ public class FileTransferNegotiator {
* @return True if all related services are enabled, false if they are not.
*/
public static boolean isServiceEnabled(final XMPPConnection connection) {
- for (int i = 0; i < NAMESPACE.length; i++) {
- if (!ServiceDiscoveryManager.getInstanceFor(connection)
- .includesFeature(NAMESPACE[i]))
+ for (String ns : NAMESPACE) {
+ if (!ServiceDiscoveryManager.getInstanceFor(connection).includesFeature(ns))
return false;
}
return true;
@@ -198,14 +199,26 @@ public class FileTransferNegotiator {
public void connectionClosedOnError(Exception e) {
cleanup(connection);
}
+
+ public void reconnectionFailed(Exception e) {
+ // ignore
+ }
+
+ public void reconectionSuccessful() {
+ // ignore
+ }
+
+ public void reconnectingIn(int seconds) {
+ // ignore
+ }
});
}
private void cleanup(final XMPPConnection connection) {
- transferObject.remove(connection);
-
- byteStreamTransferManager.cleanup();
- inbandTransferManager.cleanup();
+ if (transferObject.remove(connection) != null) {
+ byteStreamTransferManager.cleanup();
+ inbandTransferManager.cleanup();
+ }
}
/**
diff --git a/source/org/jivesoftware/smackx/muc/MultiUserChat.java b/source/org/jivesoftware/smackx/muc/MultiUserChat.java
index 1096ddb0e..36cb781e8 100644
--- a/source/org/jivesoftware/smackx/muc/MultiUserChat.java
+++ b/source/org/jivesoftware/smackx/muc/MultiUserChat.java
@@ -2614,6 +2614,18 @@ public class MultiUserChat {
cancel();
}
+ public void reconnectingIn(int seconds) {
+ // ignore
+ }
+
+ public void reconectionSuccessful() {
+ // 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/source/org/jivesoftware/smackx/muc/RoomListenerMultiplexor.java b/source/org/jivesoftware/smackx/muc/RoomListenerMultiplexor.java
index e756f92f5..bfe38d095 100644
--- a/source/org/jivesoftware/smackx/muc/RoomListenerMultiplexor.java
+++ b/source/org/jivesoftware/smackx/muc/RoomListenerMultiplexor.java
@@ -109,6 +109,18 @@ class RoomListenerMultiplexor implements ConnectionListener {
cancel();
}
+ public void reconnectingIn(int seconds) {
+ // ignore
+ }
+
+ public void reconectionSuccessful() {
+ // 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/test/org/jivesoftware/smack/LoginTest.java b/test/org/jivesoftware/smack/LoginTest.java
index 68e5c66fb..9b114c1d7 100644
--- a/test/org/jivesoftware/smack/LoginTest.java
+++ b/test/org/jivesoftware/smack/LoginTest.java
@@ -32,10 +32,11 @@ public class LoginTest extends SmackTestCase {
public void testInvalidLogin() {
try {
XMPPConnection connection = new XMPPConnection(getHost(), getPort());
+ connection.connect();
try {
// Login with an invalid user
connection.login("invaliduser" , "invalidpass");
- connection.close();
+ connection.disconnect();
fail("Invalid user was able to log into the server");
}
catch (XMPPException e) {
@@ -60,6 +61,8 @@ public class LoginTest extends SmackTestCase {
try {
XMPPConnection conn1 = new XMPPConnection(getHost(), getPort());
XMPPConnection conn2 = new XMPPConnection(getHost(), getPort());
+ conn1.connect();
+ conn2.connect();
try {
// Try to login anonymously
conn1.loginAnonymously();
@@ -76,8 +79,8 @@ public class LoginTest extends SmackTestCase {
fail(e.getMessage());
}
// Close the connection
- conn1.close();
- conn2.close();
+ conn1.disconnect();
+ conn2.disconnect();
}
catch (Exception e) {
e.printStackTrace();
@@ -93,10 +96,13 @@ public class LoginTest extends SmackTestCase {
ConnectionConfiguration config = new ConnectionConfiguration(getHost(), getPort());
config.setSASLAuthenticationEnabled(false);
XMPPConnection conn1 = new XMPPConnection(config);
+ conn1.connect();
config = new ConnectionConfiguration(getHost(), getPort());
config.setSASLAuthenticationEnabled(false);
XMPPConnection conn2 = new XMPPConnection(config);
+ conn2.connect();
+
try {
// Try to login anonymously
conn1.loginAnonymously();
@@ -113,8 +119,8 @@ public class LoginTest extends SmackTestCase {
fail(e.getMessage());
}
// Close the connection
- conn1.close();
- conn2.close();
+ conn1.disconnect();
+ conn2.disconnect();
}
catch (Exception e) {
e.printStackTrace();
@@ -128,6 +134,7 @@ public class LoginTest extends SmackTestCase {
public void testLoginWithNoResource() {
try {
XMPPConnection conn = new XMPPConnection(getHost(), getPort());
+ conn.connect();
try {
conn.getAccountManager().createAccount("user_1", "user_1");
} catch (XMPPException e) {
@@ -142,7 +149,7 @@ public class LoginTest extends SmackTestCase {
assertNotNull("JID assigned by server is missing", conn.getUser());
assertNotNull("JID assigned by server does not have a resource",
StringUtils.parseResource(conn.getUser()));
- conn.close();
+ conn.disconnect();
}
else {
fail("User with no resource was able to log into the server");
diff --git a/test/org/jivesoftware/smack/MessengerLoginTest.java b/test/org/jivesoftware/smack/MessengerLoginTest.java
index 884a97142..33648d428 100644
--- a/test/org/jivesoftware/smack/MessengerLoginTest.java
+++ b/test/org/jivesoftware/smack/MessengerLoginTest.java
@@ -86,6 +86,7 @@ public class MessengerLoginTest extends TestCase {
try {
XMPPConnection con = new XMPPConnection(host, port);
+ con.connect();
con.login(username, password, resource);
}
catch (XMPPException e) {
diff --git a/test/org/jivesoftware/smack/PresenceTest.java b/test/org/jivesoftware/smack/PresenceTest.java
index 3ebb36f63..48a8620b6 100644
--- a/test/org/jivesoftware/smack/PresenceTest.java
+++ b/test/org/jivesoftware/smack/PresenceTest.java
@@ -37,6 +37,7 @@ public class PresenceTest extends SmackTestCase {
try {
// User_1 will log in again using another resource
conn = new XMPPConnection(getHost(), getPort());
+ conn.connect();
conn.login(getUsername(1), getUsername(1), "OtherPlace");
// Change the presence priorities of User_1
getConnection(1).sendPacket(new Presence(Presence.Type.available, null, 1,
@@ -71,8 +72,7 @@ public class PresenceTest extends SmackTestCase {
chat2.nextMessage(1000));
// User_1 closes his connection
- chat2 = null;
- conn.close();
+ conn.disconnect();
Thread.sleep(150);
// Test delivery of message to the unique presence of the user_1
@@ -85,6 +85,7 @@ public class PresenceTest extends SmackTestCase {
// User_1 will log in again using another resource
conn = new XMPPConnection(getHost(), getPort());
+ conn.connect();
conn.login(getUsername(1), getUsername(1), "OtherPlace");
conn.sendPacket(new Presence(Presence.Type.available, null, 1,
Presence.Mode.available));
@@ -119,7 +120,7 @@ public class PresenceTest extends SmackTestCase {
}
finally {
if (conn != null) {
- conn.close();
+ conn.disconnect();
}
}
}
@@ -128,6 +129,7 @@ public class PresenceTest extends SmackTestCase {
* User1 logs from 2 resources but only one is available. User0 sends a message
* to the full JID of the unavailable resource. User1 in the not available resource
* should receive the message.
+ * TODO Fix this in Wildfire but before check if XMPP spec requests this feature
*/
public void testNotAvailablePresence() throws XMPPException {
// Change the presence to unavailable of User_1
@@ -135,6 +137,7 @@ public class PresenceTest extends SmackTestCase {
// User_1 will log in again using another resource (that is going to be available)
XMPPConnection conn = new XMPPConnection(getHost(), getPort());
+ conn.connect();
conn.login(getUsername(1), getUsername(1), "OtherPlace");
// Create chats between participants
@@ -158,6 +161,7 @@ public class PresenceTest extends SmackTestCase {
public void testMultipleResources() throws Exception {
// Create another connection for the same user of connection 1
XMPPConnection conn4 = new XMPPConnection(getServiceName());
+ conn4.connect();
conn4.login(getUsername(1), getUsername(1), "Home");
// Add a new roster entry
@@ -188,7 +192,7 @@ public class PresenceTest extends SmackTestCase {
assertTrue("Only one presence was found for user1", presences.hasNext());
// User1 logs out from one resource
- conn4.close();
+ conn4.disconnect();
// Wait up to 1 second
Thread.sleep(700);
diff --git a/test/org/jivesoftware/smack/RosterTest.java b/test/org/jivesoftware/smack/RosterTest.java
index 91cd34ffd..f14d1b77f 100644
--- a/test/org/jivesoftware/smack/RosterTest.java
+++ b/test/org/jivesoftware/smack/RosterTest.java
@@ -367,6 +367,7 @@ public class RosterTest extends SmackTestCase {
// Log in from another resource so we can test the roster
XMPPConnection con2 = new XMPPConnection(getHost(), getPort());
+ con2.connect();
con2.login(getUsername(0), getUsername(0), "MyNewResource");
Roster roster2 = con2.getRoster();
@@ -386,7 +387,7 @@ public class RosterTest extends SmackTestCase {
assertTrue("NewGroup group was not found", groupNames.contains("NewGroup"));
// Close the new connection
- con2.close();
+ con2.disconnect();
Thread.sleep(500);
cleanUpRoster();
@@ -480,6 +481,7 @@ public class RosterTest extends SmackTestCase {
// Create another connection for the same user of connection 1
XMPPConnection conn4 = new XMPPConnection(getServiceName());
+ conn4.connect();
conn4.login(getUsername(1), getUsername(1), "Home");
// Add a new roster entry
@@ -506,6 +508,7 @@ public class RosterTest extends SmackTestCase {
// Check that the right presence is returned for a user+resource
presence = roster.getPresenceResource(getFullJID(1));
+ assertNotNull("Presence not found for user " + getFullJID(1), presence);
assertEquals(
"Returned the wrong Presence",
StringUtils.parseResource(presence.getFrom()),
@@ -525,7 +528,7 @@ public class RosterTest extends SmackTestCase {
assertEquals("Wrong number of returned presences", count, 2);
// Close the connection so one presence must go
- conn4.close();
+ conn4.disconnect();
// Check that the returned presences are correct
presences = roster.getPresences(getBareJID(1));
@@ -548,6 +551,7 @@ public class RosterTest extends SmackTestCase {
public void testMultipleResources() throws Exception {
// Create another connection for the same user of connection 1
XMPPConnection conn4 = new XMPPConnection(getServiceName());
+ conn4.connect();
conn4.login(getUsername(1), getUsername(1), "Home");
// Add a new roster entry
@@ -605,6 +609,7 @@ public class RosterTest extends SmackTestCase {
// Create another connection for the same user of connection 0
XMPPConnection conn2 = new XMPPConnection(getServiceName());
+ conn2.connect();
conn2.login(getUsername(0), getUsername(0), "Home");
// Retrieve roster and verify that new contact is there and nickname is correct
@@ -677,6 +682,46 @@ public class RosterTest extends SmackTestCase {
getConnection(2).getRoster().getGroupCount());
}
+ /**
+ * Tests the creation of a roster and then simulates abrupt termination. Cached presences
+ * must go offline. At reconnection, presences must go back to online.
+ *
+ * - Create some entries
+ *
- Breack the connection
+ *
- Check offline presences
+ *
- Whait for automatic reconnection
+ *
- Check online presences
+ *
+ */
+ public void testOfflinePresencesAfterDisconnection() throws Exception {
+ // Add a new roster entry
+ Roster roster = getConnection(0).getRoster();
+ roster.createEntry(getBareJID(1), "gato11", null);
+ roster.createEntry(getBareJID(2), "gato12", null);
+
+ // Wait up to 2 seconds to let the server process presence subscriptions
+ long initial = System.currentTimeMillis();
+ while (System.currentTimeMillis() - initial < 2000 && (
+ roster.getPresence(getBareJID(1)) == null ||
+ roster.getPresence(getBareJID(2)) == null)) {
+ Thread.sleep(100);
+ }
+
+ Thread.sleep(200);
+
+ // Brakes the connection
+ getConnection(0).packetReader.notifyConnectionError(new Exception("Simulated Error"));
+
+ Presence presence = roster.getPresence(getBareJID(1));
+ assertNull("Presence should be offline after a connection termination", presence);
+ // Reconnection should occur in 10 seconds
+ Thread.sleep(12200);
+ presence = roster.getPresence(getBareJID(1));
+ assertNotNull("Presence not found for user", presence);
+ assertEquals("Presence should be online after a connection reconnection",
+ Presence.Type.available, presence.getType());
+ }
+
protected int getMaxConnections() {
return 3;
}
diff --git a/test/org/jivesoftware/smack/test/SmackTestCase.java b/test/org/jivesoftware/smack/test/SmackTestCase.java
index c560e5de0..22040b22b 100644
--- a/test/org/jivesoftware/smack/test/SmackTestCase.java
+++ b/test/org/jivesoftware/smack/test/SmackTestCase.java
@@ -1,7 +1,7 @@
/**
* $RCSfile$
* $Revision$
- * $Date: $
+ * $Date$
*
* Copyright 2003-2005 Jive Software.
*
@@ -19,20 +19,18 @@
*/
package org.jivesoftware.smack.test;
+import junit.framework.TestCase;
+import org.jivesoftware.smack.ConnectionConfiguration;
+import org.jivesoftware.smack.XMPPConnection;
+import org.jivesoftware.smack.XMPPException;
+import org.xmlpull.mxp1.MXParser;
+import org.xmlpull.v1.XmlPullParser;
+
+import javax.net.SocketFactory;
import java.io.InputStream;
import java.net.URL;
import java.util.Enumeration;
-import javax.net.SocketFactory;
-
-import org.jivesoftware.smack.XMPPConnection;
-import org.jivesoftware.smack.XMPPException;
-import org.jivesoftware.smack.ConnectionConfiguration;
-import org.xmlpull.v1.*;
-import org.xmlpull.mxp1.MXParser;
-
-import junit.framework.TestCase;
-
/**
* Base class for all the test cases which provides a pre-configured execution context. This
* means that any test case that subclassifies this base class will have access to a pool of
@@ -196,6 +194,7 @@ public abstract class SmackTestCase extends TestCase {
else {
connections[i] = new XMPPConnection(config, getSocketFactory());
}
+ connections[i].connect();
}
// Use the host name that the server reports. This is a good idea in most
// cases, but could fail if the user set a hostname in their XMPP server
@@ -232,11 +231,12 @@ public abstract class SmackTestCase extends TestCase {
super.tearDown();
for (int i = 0; i < getMaxConnections(); i++) {
+ if (getConnection(i).isConnected()) {
// Delete the created account for the test
getConnection(i).getAccountManager().deleteAccount();
// Close the connection
- getConnection(i).close();
-
+ getConnection(i).disconnect();
+ }
}
}
diff --git a/test/org/jivesoftware/smackx/CompressionTest.java b/test/org/jivesoftware/smackx/CompressionTest.java
index 06ebc8a05..af1da8202 100644
--- a/test/org/jivesoftware/smackx/CompressionTest.java
+++ b/test/org/jivesoftware/smackx/CompressionTest.java
@@ -20,11 +20,10 @@
package org.jivesoftware.smackx;
-import org.jivesoftware.smack.test.SmackTestCase;
+import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
-import org.jivesoftware.smack.ConnectionConfiguration;
-import org.jivesoftware.smack.SmackConfiguration;
+import org.jivesoftware.smack.test.SmackTestCase;
/**
* Ensure that stream compression (JEP-138) is correctly supported by Smack.
@@ -50,6 +49,7 @@ public class CompressionTest extends SmackTestCase {
config.setSASLAuthenticationEnabled(true);
XMPPConnection connection = new XMPPConnection(config);
+ connection.connect();
// Login with the test account
connection.login("user0", "user0");
@@ -57,7 +57,7 @@ public class CompressionTest extends SmackTestCase {
assertTrue("Connection is not using stream compression", connection.isUsingCompression());
// Close connection
- connection.close();
+ connection.disconnect();
}
protected int getMaxConnections() {
@@ -70,6 +70,7 @@ public class CompressionTest extends SmackTestCase {
protected void setUp() throws Exception {
super.setUp();
XMPPConnection setupConnection = new XMPPConnection(getHost(), getPort());
+ setupConnection.connect();
if (!setupConnection.getAccountManager().supportsAccountCreation())
fail("Server does not support account creation");
@@ -90,11 +91,12 @@ public class CompressionTest extends SmackTestCase {
protected void tearDown() throws Exception {
super.tearDown();
XMPPConnection setupConnection = new XMPPConnection(getHost(), getPort());
+ setupConnection.connect();
setupConnection.login("user0", "user0");
// Delete the created account for the test
setupConnection.getAccountManager().deleteAccount();
// Close the setupConnection
- setupConnection.close();
+ setupConnection.disconnect();
}
}
diff --git a/test/org/jivesoftware/smackx/muc/MultiUserChatTest.java b/test/org/jivesoftware/smackx/muc/MultiUserChatTest.java
index 4377c5f42..4893127c3 100644
--- a/test/org/jivesoftware/smackx/muc/MultiUserChatTest.java
+++ b/test/org/jivesoftware/smackx/muc/MultiUserChatTest.java
@@ -250,6 +250,7 @@ public class MultiUserChatTest extends SmackTestCase {
try {
// Anonymous user joins the new room
XMPPConnection anonConnection = new XMPPConnection(getHost(), getPort());
+ anonConnection.connect();
anonConnection.loginAnonymously();
MultiUserChat muc2 = new MultiUserChat(anonConnection, room);
muc2.join("testbot2");
@@ -265,7 +266,7 @@ public class MultiUserChatTest extends SmackTestCase {
// Anonymous user leaves the room
muc2.leave();
- anonConnection.close();
+ anonConnection.disconnect();
Thread.sleep(250);
// User1 checks the presence of Anonymous user in the room
presence = muc.getOccupantPresence(room + "/testbot2");
@@ -1766,6 +1767,7 @@ public class MultiUserChatTest extends SmackTestCase {
XMPPConnection[] conns = new XMPPConnection[20];
for (int i = 0; i < conns.length; i++) {
conns[i] = new XMPPConnection(getServiceName());
+ conns[i].connect();
conns[i].login(getUsername(1), getUsername(1), "resource-" + i);
}
@@ -1788,7 +1790,7 @@ public class MultiUserChatTest extends SmackTestCase {
// Each connection leaves the room and closes the connection
for (int i = 0; i < mucs.length; i++) {
mucs[i].leave();
- conns[i].close();
+ conns[i].disconnect();
}
} catch (Exception e) {