1
0
Fork 0
mirror of https://codeberg.org/Mercury-IM/Smack synced 2024-12-24 13:27:59 +01:00

SMACK-412 Added the pingMyServer back in, cleaned up unneeded synchronization and removed minimum ping interval.

git-svn-id: http://svn.igniterealtime.org/svn/repos/smack/branches/smack_3_3_0@13588 b35dd754-fafc-0310-a699-88a17e54d16e
This commit is contained in:
rcollier 2013-03-23 11:59:08 +00:00
parent 999c86ef4c
commit a14178990b
8 changed files with 174 additions and 42 deletions

View file

@ -162,7 +162,6 @@ class PacketWriter {
while (!done && (writerThread == thisThread)) { while (!done && (writerThread == thisThread)) {
Packet packet = nextPacket(); Packet packet = nextPacket();
if (packet != null) { if (packet != null) {
synchronized (writer) {
writer.write(packet.toXML()); writer.write(packet.toXML());
writer.flush(); writer.flush();
if (queue.isEmpty()) { if (queue.isEmpty()) {
@ -170,19 +169,16 @@ class PacketWriter {
} }
} }
} }
}
// Flush out the rest of the queue. If the queue is extremely large, it's possible // Flush out the rest of the queue. If the queue is extremely large, it's possible
// we won't have time to entirely flush it before the socket is forced closed // we won't have time to entirely flush it before the socket is forced closed
// by the shutdown process. // by the shutdown process.
try { try {
synchronized (writer) {
while (!queue.isEmpty()) { while (!queue.isEmpty()) {
Packet packet = queue.remove(); Packet packet = queue.remove();
writer.write(packet.toXML()); writer.write(packet.toXML());
} }
writer.flush(); writer.flush();
} }
}
catch (Exception e) { catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }

View file

@ -0,0 +1,24 @@
package org.jivesoftware.smack;
public enum SmackError {
NO_RESPONSE_FROM_SERVER("No response from server.");
private String message;
private SmackError(String errMessage) {
message = errMessage;
}
public String getErrorMessage() {
return message;
}
public static SmackError getErrorCode(String message) {
for (SmackError code : values()) {
if (code.message.equals(message)) {
return code;
}
}
return null;
}
}

View file

@ -41,10 +41,12 @@ import java.io.PrintWriter;
* @author Matt Tucker * @author Matt Tucker
*/ */
public class XMPPException extends Exception { public class XMPPException extends Exception {
private static final long serialVersionUID = 6881651633890968625L;
private StreamError streamError = null; private StreamError streamError = null;
private XMPPError error = null; private XMPPError error = null;
private Throwable wrappedThrowable = null; private Throwable wrappedThrowable = null;
private SmackError smackError = null;
/** /**
* Creates a new XMPPException. * Creates a new XMPPException.
@ -62,6 +64,16 @@ public class XMPPException extends Exception {
super(message); super(message);
} }
/**
* Creates a new XMPPException with a Smack specific error code.
*
* @param code the root cause of the exception.
*/
public XMPPException(SmackError code) {
super(code.getErrorMessage());
smackError = code;
}
/** /**
* Creates a new XMPPException with the Throwable that was the root cause of the * Creates a new XMPPException with the Throwable that was the root cause of the
* exception. * exception.
@ -74,7 +86,7 @@ public class XMPPException extends Exception {
} }
/** /**
* Cretaes a new XMPPException with the stream error that was the root case of the * Creates a new XMPPException with the stream error that was the root case of the
* exception. When a stream error is received from the server then the underlying * exception. When a stream error is received from the server then the underlying
* TCP connection will be closed by the server. * TCP connection will be closed by the server.
* *
@ -144,6 +156,16 @@ public class XMPPException extends Exception {
return error; return error;
} }
/**
* Returns the SmackError asscociated with this exception, or <tt>null</tt> if there
* isn't one.
*
* @return the SmackError asscociated with this exception.
*/
public SmackError getSmackError() {
return smackError;
}
/** /**
* Returns the StreamError asscociated with this exception, or <tt>null</tt> if there * Returns the StreamError asscociated with this exception, or <tt>null</tt> if there
* isn't one. The underlying TCP connection is closed by the server after sending the * isn't one. The underlying TCP connection is closed by the server after sending the

View file

@ -57,8 +57,6 @@ import org.jivesoftware.smackx.ServiceDiscoveryManager;
* @author Florian Schmaus * @author Florian Schmaus
*/ */
public class ServerPingManager { public class ServerPingManager {
public static final long PING_MINIMUM = 10000;
private static Map<Connection, ServerPingManager> instances = Collections private static Map<Connection, ServerPingManager> instances = Collections
.synchronizedMap(new WeakHashMap<Connection, ServerPingManager>()); .synchronizedMap(new WeakHashMap<Connection, ServerPingManager>());
private static long defaultPingInterval = SmackConfiguration.getKeepAliveInterval(); private static long defaultPingInterval = SmackConfiguration.getKeepAliveInterval();
@ -173,14 +171,17 @@ public class ServerPingManager {
* The new ping time interval in milliseconds. * The new ping time interval in milliseconds.
*/ */
public void setPingInterval(long newPingInterval) { public void setPingInterval(long newPingInterval) {
if (newPingInterval < PING_MINIMUM)
newPingInterval = PING_MINIMUM;
if (pingInterval != newPingInterval) { if (pingInterval != newPingInterval) {
pingInterval = newPingInterval; pingInterval = newPingInterval;
if (pingInterval < 0) {
stopPinging();
}
else {
schedulePingServerTask(); schedulePingServerTask();
} }
} }
}
/** /**
* Stops pinging the server. This cannot stop a ping that has already started, but will prevent another from being triggered. * Stops pinging the server. This cannot stop a ping that has already started, but will prevent another from being triggered.

View file

@ -16,6 +16,7 @@ package org.jivesoftware.smack.util;
import org.jivesoftware.smack.PacketCollector; import org.jivesoftware.smack.PacketCollector;
import org.jivesoftware.smack.SmackConfiguration; import org.jivesoftware.smack.SmackConfiguration;
import org.jivesoftware.smack.Connection; import org.jivesoftware.smack.Connection;
import org.jivesoftware.smack.SmackError;
import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.filter.PacketFilter; import org.jivesoftware.smack.filter.PacketFilter;
import org.jivesoftware.smack.filter.PacketIDFilter; import org.jivesoftware.smack.filter.PacketIDFilter;
@ -47,7 +48,7 @@ final public class SyncPacketSend
response.cancel(); response.cancel();
if (result == null) { if (result == null) {
throw new XMPPException("No response from " + packet.getTo()); throw new XMPPException(SmackError.NO_RESPONSE_FROM_SERVER);
} }
else if (result.getError() != null) { else if (result.getError() != null) {
throw new XMPPException(result.getError()); throw new XMPPException(result.getError());

View file

@ -18,6 +18,7 @@ package org.jivesoftware.smackx.ping;
import org.jivesoftware.smack.Connection; import org.jivesoftware.smack.Connection;
import org.jivesoftware.smack.SmackConfiguration; import org.jivesoftware.smack.SmackConfiguration;
import org.jivesoftware.smack.SmackError;
import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.ping.ServerPingManager; import org.jivesoftware.smack.ping.ServerPingManager;
import org.jivesoftware.smack.ping.packet.Ping; import org.jivesoftware.smack.ping.packet.Ping;
@ -49,7 +50,9 @@ public class PingManager {
} }
/** /**
* Pings the given jid. This method will return false if an error occurs. * Pings the given jid. This method will return false if an error occurs. The exception
* to this, is a server ping, which will always return true if the server is reachable,
* event if there is an error on the ping itself (i.e. ping not supported).
* <p> * <p>
* Use {@link #isPingSupported(String)} to determine if XMPP Ping is supported * Use {@link #isPingSupported(String)} to determine if XMPP Ping is supported
* by the entity. * by the entity.
@ -65,7 +68,8 @@ public class PingManager {
SyncPacketSend.getReply(connection, ping); SyncPacketSend.getReply(connection, ping);
} }
catch (XMPPException exc) { catch (XMPPException exc) {
return false;
return (jid.equals(connection.getServiceName()) && (exc.getSmackError() != SmackError.NO_RESPONSE_FROM_SERVER));
} }
return true; return true;
} }
@ -92,4 +96,17 @@ public class PingManager {
DiscoverInfo result = ServiceDiscoveryManager.getInstanceFor(connection).discoverInfo(jid); DiscoverInfo result = ServiceDiscoveryManager.getInstanceFor(connection).discoverInfo(jid);
return result.containsFeature(Ping.NAMESPACE); return result.containsFeature(Ping.NAMESPACE);
} }
/**
* Pings the server. This method will return true if the server is reachable. It
* is the equivalent of calling <code>ping</code> with the XMPP domain.
* <p>
* Unlike the {@link #ping(String)} case, this method will return true even if
* {@link #isPingSupported(String)} is false.
*
* @return true if a reply was received from the server, false otherwise.
*/
public boolean pingMyServer() {
return ping(connection.getServiceName());
}
} }

View file

@ -21,9 +21,12 @@ import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.Packet; import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.ping.packet.Ping; import org.jivesoftware.smack.ping.packet.Ping;
import org.jivesoftware.smack.util.PacketParserUtils; import org.jivesoftware.smack.util.PacketParserUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Test; import org.junit.Test;
public class ServerPingTest { public class KeepaliveTest {
private static final long PING_MINIMUM = 1000;
private static String TO = "juliet@capulet.lit/balcony"; private static String TO = "juliet@capulet.lit/balcony";
private static String ID = "s2c1"; private static String ID = "s2c1";
@ -32,6 +35,20 @@ public class ServerPingTest {
outputProperties.put(javax.xml.transform.OutputKeys.OMIT_XML_DECLARATION, "yes"); outputProperties.put(javax.xml.transform.OutputKeys.OMIT_XML_DECLARATION, "yes");
} }
private int originalTimeout;
@Before
public void resetProperties()
{
originalTimeout = SmackConfiguration.getPacketReplyTimeout();
SmackConfiguration.setPacketReplyTimeout(1000);
}
@After
public void restoreProperties()
{
SmackConfiguration.setPacketReplyTimeout(originalTimeout);
}
/* /*
* Stanza copied from spec * Stanza copied from spec
*/ */
@ -133,7 +150,7 @@ public class ServerPingTest {
private DummyConnection getConnection() { private DummyConnection getConnection() {
DummyConnection con = new DummyConnection(); DummyConnection con = new DummyConnection();
ServerPingManager mgr = ServerPingManager.getInstanceFor(con); ServerPingManager mgr = ServerPingManager.getInstanceFor(con);
mgr.setPingInterval(ServerPingManager.PING_MINIMUM); mgr.setPingInterval(PING_MINIMUM);
return con; return con;
} }
@ -141,7 +158,7 @@ public class ServerPingTest {
private ThreadedDummyConnection getThreadedConnection() { private ThreadedDummyConnection getThreadedConnection() {
ThreadedDummyConnection con = new ThreadedDummyConnection(); ThreadedDummyConnection con = new ThreadedDummyConnection();
ServerPingManager mgr = ServerPingManager.getInstanceFor(con); ServerPingManager mgr = ServerPingManager.getInstanceFor(con);
mgr.setPingInterval(ServerPingManager.PING_MINIMUM); mgr.setPingInterval(PING_MINIMUM);
return con; return con;
} }
@ -157,6 +174,6 @@ public class ServerPingTest {
} }
private long getWaitTime() { private long getWaitTime() {
return ServerPingManager.PING_MINIMUM + SmackConfiguration.getPacketReplyTimeout() + 3000; return PING_MINIMUM + SmackConfiguration.getPacketReplyTimeout() + 3000;
} }
} }

View file

@ -23,19 +23,28 @@ import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.ping.packet.Ping; import org.jivesoftware.smack.ping.packet.Ping;
import org.jivesoftware.smack.util.PacketParserUtils; import org.jivesoftware.smack.util.PacketParserUtils;
import org.jivesoftware.smackx.packet.DiscoverInfo; import org.jivesoftware.smackx.packet.DiscoverInfo;
import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import static org.junit.Assert.*; import static org.junit.Assert.*;
public class PingPongTest { public class PingTest {
private DummyConnection dummyCon;
private ThreadedDummyConnection threadedCon;
@Before
public void setup() {
dummyCon = new DummyConnection();
threadedCon = new ThreadedDummyConnection();
}
@Test @Test
public void checkSendingPing() throws Exception { public void checkSendingPing() throws Exception {
DummyConnection con = new DummyConnection(); dummyCon = new DummyConnection();
PingManager pinger = new PingManager(con); PingManager pinger = new PingManager(dummyCon);
pinger.ping("test@myserver.com"); pinger.ping("test@myserver.com");
Packet sentPacket = con.getSentPacket(); Packet sentPacket = dummyCon.getSentPacket();
assertTrue(sentPacket instanceof Ping); assertTrue(sentPacket instanceof Ping);
@ -43,9 +52,9 @@ public class PingPongTest {
@Test @Test
public void checkSuccessfulPing() throws Exception { public void checkSuccessfulPing() throws Exception {
ThreadedDummyConnection con = new ThreadedDummyConnection(); threadedCon = new ThreadedDummyConnection();
PingManager pinger = new PingManager(con); PingManager pinger = new PingManager(threadedCon);
boolean pingSuccess = pinger.ping("test@myserver.com"); boolean pingSuccess = pinger.ping("test@myserver.com");
@ -59,8 +68,8 @@ public class PingPongTest {
*/ */
@Test @Test
public void checkFailedPingOnTimeout() throws Exception { public void checkFailedPingOnTimeout() throws Exception {
DummyConnection con = new DummyConnection(); dummyCon = new DummyConnection();
PingManager pinger = new PingManager(con); PingManager pinger = new PingManager(dummyCon);
boolean pingSuccess = pinger.ping("test@myserver.com"); boolean pingSuccess = pinger.ping("test@myserver.com");
@ -69,12 +78,12 @@ public class PingPongTest {
} }
/** /**
* DummyConnection will not reply so it will timeout. * Server returns an exception for entity.
* @throws Exception * @throws Exception
*/ */
@Test @Test
public void checkFailedPingError() throws Exception { public void checkFailedPingToEntityError() throws Exception {
ThreadedDummyConnection con = new ThreadedDummyConnection(); threadedCon = new ThreadedDummyConnection();
//@formatter:off //@formatter:off
String reply = String reply =
"<iq type='error' id='qrzSp-16' to='test@myserver.com'>" + "<iq type='error' id='qrzSp-16' to='test@myserver.com'>" +
@ -84,15 +93,60 @@ public class PingPongTest {
"</error>" + "</error>" +
"</iq>"; "</iq>";
//@formatter:on //@formatter:on
IQ serviceUnavailable = PacketParserUtils.parseIQ(TestUtils.getIQParser(reply), threadedCon);
threadedCon.addIQReply(serviceUnavailable);
PingManager pinger = new PingManager(threadedCon);
boolean pingSuccess = pinger.ping("test@myserver.com");
assertFalse(pingSuccess);
}
@Test
public void checkPingToServerSuccess() throws Exception {
ThreadedDummyConnection con = new ThreadedDummyConnection();
PingManager pinger = new PingManager(con);
boolean pingSuccess = pinger.pingMyServer();
assertTrue(pingSuccess);
}
/**
* Server returns an exception.
* @throws Exception
*/
@Test
public void checkPingToServerError() throws Exception {
ThreadedDummyConnection con = new ThreadedDummyConnection();
//@formatter:off
String reply =
"<iq type='error' id='qrzSp-16' to='test@myserver.com' from='" + con.getServiceName() + "'>" +
"<ping xmlns='urn:xmpp:ping'/>" +
"<error type='cancel'>" +
"<service-unavailable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>" +
"</error>" +
"</iq>";
//@formatter:on
IQ serviceUnavailable = PacketParserUtils.parseIQ(TestUtils.getIQParser(reply), con); IQ serviceUnavailable = PacketParserUtils.parseIQ(TestUtils.getIQParser(reply), con);
con.addIQReply(serviceUnavailable); con.addIQReply(serviceUnavailable);
PingManager pinger = new PingManager(con); PingManager pinger = new PingManager(con);
boolean pingSuccess = pinger.ping("test@myserver.com"); boolean pingSuccess = pinger.pingMyServer();
assertTrue(pingSuccess);
}
@Test
public void checkPingToServerTimeout() throws Exception {
DummyConnection con = new DummyConnection();
PingManager pinger = new PingManager(con);
boolean pingSuccess = pinger.pingMyServer();
assertFalse(pingSuccess); assertFalse(pingSuccess);
} }
@Test @Test