Rework incoming packet listeners and Roster

Differentiate between asynchronous and synchronous ones. Asynchronous
are the ones where the invocation order may not be the same as the order
in which the stanzas arrived.

Since it's no longer guaranteed that when a unit test calls

processPacket(stanza)

the stanza will be completely processed when the call returns, it was
necessary to extend the unit tests (mostly Roster and ChatManager) with
a packet listener that waits for his invocation. Since we now also use
LinkedHashMaps as Map for the packet listeners (SMACK-531, SMACK-424),
adding a packet listeners as last also means that it will be called as
last. We exploit this behavior change now in the unit tests.

Rename 'recvListeners' to 'syncRecvListeners' in AbstractXMPPConnection.

Rename 'rosterInitialized' to 'loaded' in Roster.

Add Roster.isLoaded().

Reset 'loaded' to false in
Roster.setOfflinePresencesAndResetLoaded() (was setOfflinePresences()).

Fixes SMACK-583, SMACK-532, SMACK-424
This commit is contained in:
Florian Schmaus 2015-01-05 21:42:35 +01:00
parent e5c6c9bdf8
commit 717090d272
39 changed files with 443 additions and 306 deletions

View File

@ -169,7 +169,7 @@ public class XMPPBOSHConnection extends AbstractXMPPConnection {
initDebugger();
if (isFirstInitialization) {
if (debugger.getReaderListener() != null) {
addPacketListener(debugger.getReaderListener(), null);
addAsyncPacketListener(debugger.getReaderListener(), null);
}
if (debugger.getWriterListener() != null) {
addPacketSendingListener(debugger.getWriterListener(), null);

View File

@ -107,7 +107,7 @@ public class PacketReaderTest extends SmackTestCase {
// Keep number of current listeners
int listenersSize = getConnection(0).getPacketListeners().size();
// Add a new listener
getConnection(0).addPacketListener(listener, new MockPacketFilter(true));
getConnection(0).addAsyncPacketListener(listener, new MockPacketFilter(true));
// Check that the listener was added
assertEquals("Listener was not added", listenersSize + 1,
getConnection(0).getPacketListeners().size());
@ -117,7 +117,7 @@ public class PacketReaderTest extends SmackTestCase {
getConnection(1).sendPacket(msg);
// Remove the listener
getConnection(0).removePacketListener(listener);
getConnection(0).removeAsyncPacketListener(listener);
// Check that the number of listeners is correct (i.e. the listener was removed)
assertEquals("Listener was not removed", listenersSize,
getConnection(0).getPacketListeners().size());
@ -134,7 +134,7 @@ public class PacketReaderTest extends SmackTestCase {
packet.setBody("aloha");
// User1 will always reply to user0 when a message is received
getConnection(1).addPacketListener(new PacketListener() {
getConnection(1).addAsyncPacketListener(new PacketListener() {
public void processPacket(Packet packet) {
System.out.println(new Date() + " " + packet);
@ -203,8 +203,8 @@ public class PacketReaderTest extends SmackTestCase {
}
};
getConnection(0).addPacketListener(listener0, pf0);
getConnection(1).addPacketListener(listener1, pf1);
getConnection(0).addAsyncPacketListener(listener0, pf0);
getConnection(1).addAsyncPacketListener(listener1, pf1);
// Check that the listener was added
@ -225,8 +225,8 @@ public class PacketReaderTest extends SmackTestCase {
}
// Remove the listener
getConnection(0).removePacketListener(listener0);
getConnection(1).removePacketListener(listener1);
getConnection(0).removeAsyncPacketListener(listener0);
getConnection(1).removeAsyncPacketListener(listener1);
try {
Thread.sleep(300);

View File

@ -22,6 +22,7 @@ import java.io.Writer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
@ -126,12 +127,14 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
private final Collection<PacketCollector> collectors = new ConcurrentLinkedQueue<PacketCollector>();
/**
* List of PacketListeners that will be notified when a new packet was received.
* List of PacketListeners that will be notified synchronously when a new packet was received.
*/
private final Map<PacketListener, ListenerWrapper> recvListeners =
new HashMap<PacketListener, ListenerWrapper>();
private final Map<PacketListener, ListenerWrapper> syncRecvListeners = new LinkedHashMap<>();
private final Map<PacketListener, ListenerWrapper> asyncRecvListeners = new HashMap<>();
/**
* List of PacketListeners that will be notified asynchronously when a new packet was received.
*/
private final Map<PacketListener, ListenerWrapper> asyncRecvListeners = new LinkedHashMap<>();
/**
* List of PacketListeners that will be notified when a new packet was sent.
@ -245,6 +248,14 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
// @formatter:on
);
/**
* A executor service used to invoke the callbacks of synchronous packet listeners. We use a executor service to
* decouple incoming stanza processing from callback invocation. It is important that order of callback invocation
* is the same as the order of the incoming stanzas. Therefore we use a <i>single</i> threaded executor service.
*/
private final ExecutorService singleThreadedExecutorService = Executors.newSingleThreadExecutor(new SmackExecutorThreadFactory(
getConnectionCounter(), "Sync PacketListener Callback"));
private Roster roster;
/**
@ -593,27 +604,10 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
// 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
// Also only check for rosterIsLoaded 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 = getPacketReplyTimeout();
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.
}
if (!roster.isLoaded() && config.isRosterLoadedAtLogin()) {
roster.waitUntilLoaded();
}
return roster;
}
@ -727,19 +721,29 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
@Override
public void addPacketListener(PacketListener packetListener, PacketFilter packetFilter) {
if (packetListener == null) {
throw new NullPointerException("Packet listener is null.");
}
ListenerWrapper wrapper = new ListenerWrapper(packetListener, packetFilter);
synchronized (recvListeners) {
recvListeners.put(packetListener, wrapper);
}
addAsyncPacketListener(packetListener, packetFilter);
}
@Override
public boolean removePacketListener(PacketListener packetListener) {
synchronized (recvListeners) {
return recvListeners.remove(packetListener) != null;
return removeAsyncPacketListener(packetListener);
}
@Override
public void addSyncPacketListener(PacketListener packetListener, PacketFilter packetFilter) {
if (packetListener == null) {
throw new NullPointerException("Packet listener is null.");
}
ListenerWrapper wrapper = new ListenerWrapper(packetListener, packetFilter);
synchronized (syncRecvListeners) {
syncRecvListeners.put(packetListener, wrapper);
}
}
@Override
public boolean removeSyncPacketListener(PacketListener packetListener) {
synchronized (syncRecvListeners) {
return syncRecvListeners.remove(packetListener) != null;
}
}
@ -961,7 +965,7 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
// First handle the async recv listeners. Note that this code is very similar to what follows a few lines below,
// the only difference is that asyncRecvListeners is used here and that the packet listeners are started in
// their own thread.
Collection<PacketListener> listenersToNotify = new LinkedList<PacketListener>();
final Collection<PacketListener> listenersToNotify = new LinkedList<PacketListener>();
synchronized (asyncRecvListeners) {
for (ListenerWrapper listenerWrapper : asyncRecvListeners.values()) {
if (listenerWrapper.filterMatches(packet)) {
@ -989,25 +993,33 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
}
// Notify the receive listeners interested in the packet
listenersToNotify = new LinkedList<PacketListener>();
synchronized (recvListeners) {
for (ListenerWrapper listenerWrapper : recvListeners.values()) {
listenersToNotify.clear();
synchronized (syncRecvListeners) {
for (ListenerWrapper listenerWrapper : syncRecvListeners.values()) {
if (listenerWrapper.filterMatches(packet)) {
listenersToNotify.add(listenerWrapper.getListener());
}
}
}
for (PacketListener listener : listenersToNotify) {
try {
listener.processPacket(packet);
} catch(NotConnectedException e) {
LOGGER.log(Level.WARNING, "Got not connected exception, aborting", e);
break;
} catch (Exception e) {
LOGGER.log(Level.SEVERE, "Exception in packet listener", e);
// Decouple incoming stanza processing from listener invocation. Unlike async listeners, this uses a single
// threaded executor service and therefore keeps the order.
singleThreadedExecutorService.execute(new Runnable() {
@Override
public void run() {
for (PacketListener listener : listenersToNotify) {
try {
listener.processPacket(packet);
} catch(NotConnectedException e) {
LOGGER.log(Level.WARNING, "Got not connected exception, aborting", e);
break;
} catch (Exception e) {
LOGGER.log(Level.SEVERE, "Exception in packet listener", e);
}
}
}
}
});
}
/**
@ -1145,6 +1157,7 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
executorService.shutdownNow();
cachedExecutorService.shutdown();
removeCallbacksService.shutdownNow();
singleThreadedExecutorService.shutdownNow();
} catch (Throwable t) {
LOGGER.log(Level.WARNING, "finalize() threw trhowable", t);
}
@ -1302,14 +1315,14 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
}
}
finally {
removePacketListener(this);
removeAsyncPacketListener(this);
}
}
};
removeCallbacksService.schedule(new Runnable() {
@Override
public void run() {
boolean removed = removePacketListener(packetListener);
boolean removed = removeAsyncPacketListener(packetListener);
// If the packetListener got removed, then it was never run and
// we never received a response, inform the exception callback
if (removed && exceptionCallback != null) {
@ -1317,7 +1330,7 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
}
}
}, timeout, TimeUnit.MILLISECONDS);
addPacketListener(packetListener, replyFilter);
addAsyncPacketListener(packetListener, replyFilter);
sendPacket(stanza);
}

View File

@ -137,7 +137,7 @@ public class ChatManager extends Manager{
// Add a listener for all message packets so that we can deliver
// messages to the best Chat instance available.
connection.addPacketListener(new PacketListener() {
connection.addSyncPacketListener(new PacketListener() {
public void processPacket(Packet packet) {
Message message = (Message) packet;
Chat chat;

View File

@ -33,7 +33,7 @@ import org.jivesoftware.smack.packet.Packet;
* org.jivesoftware.smack.filter.PacketFilter)}
* </p>
*
* @see XMPPConnection#addPacketListener(PacketListener, org.jivesoftware.smack.filter.PacketFilter)
* @see XMPPConnection#addAsyncPacketListener(PacketListener, org.jivesoftware.smack.filter.PacketFilter)
* @author Matt Tucker
*/
public interface PacketListener {

View File

@ -85,9 +85,11 @@ public class Roster {
private final List<RosterEntry> unfiledEntries = new CopyOnWriteArrayList<RosterEntry>();
private final List<RosterListener> rosterListeners = new CopyOnWriteArrayList<RosterListener>();
private final Map<String, Map<String, Presence>> presenceMap = new ConcurrentHashMap<String, Map<String, Presence>>();
// The roster is marked as initialized when at least a single roster packet
// has been received and processed.
boolean rosterInitialized = false;
private boolean loaded = false;
private final PresencePacketListener presencePacketListener = new PresencePacketListener();
private SubscriptionMode subscriptionMode = getDefaultSubscriptionMode();
@ -124,10 +126,13 @@ public class Roster {
Roster(final XMPPConnection connection) {
this.connection = connection;
rosterStore = connection.getRosterStore();
// Note that we use sync packet listeners because RosterListeners should be invoked in the same order as the
// roster stanzas arrive.
// Listen for any roster packets.
connection.addPacketListener(new RosterPushListener(), ROSTER_PUSH_FILTER);
connection.addSyncPacketListener(new RosterPushListener(), ROSTER_PUSH_FILTER);
// Listen for any presence packets.
connection.addPacketListener(presencePacketListener, PRESENCE_PACKET_FILTER);
connection.addSyncPacketListener(presencePacketListener, PRESENCE_PACKET_FILTER);
// Listen for connection events
connection.addConnectionListener(new AbstractConnectionListener() {
@ -151,22 +156,12 @@ public class Roster {
public void connectionClosed() {
// Changes the presence available contacts to unavailable
try {
setOfflinePresences();
}
catch (NotConnectedException e) {
LOGGER.log(Level.SEVERE, "Not connected exception" ,e);
}
setOfflinePresencesAndResetLoaded();
}
public void connectionClosedOnError(Exception e) {
// Changes the presence available contacts to unavailable
try {
setOfflinePresences();
}
catch (NotConnectedException e1) {
LOGGER.log(Level.SEVERE, "Not connected exception" ,e);
}
setOfflinePresencesAndResetLoaded();
}
});
@ -238,6 +233,40 @@ public class Roster {
});
}
protected boolean waitUntilLoaded() {
long waitTime = connection.getPacketReplyTimeout();
long start = System.currentTimeMillis();
while (!loaded) {
if (waitTime <= 0) {
break;
}
try {
synchronized (this) {
if (!loaded) {
wait(waitTime);
}
}
}
catch (InterruptedException e) {
LOGGER.log(Level.FINE, "spurious interrupt", e);
}
long now = System.currentTimeMillis();
waitTime -= now - start;
start = now;
}
return isLoaded();
}
/**
* Check if the roster is loaded.
*
* @return true if the roster is loaded.
* @since 4.1
*/
public boolean isLoaded() {
return loaded;
}
/**
* Adds a listener to this roster. The listener will be fired anytime one or more
* changes to the roster are pushed from the server.
@ -696,7 +725,7 @@ public class Roster {
* to offline.
* @throws NotConnectedException
*/
private void setOfflinePresences() throws NotConnectedException {
private void setOfflinePresencesAndResetLoaded() {
Presence packetUnavailable;
for (String user : presenceMap.keySet()) {
Map<String, Presence> resources = presenceMap.get(user);
@ -704,10 +733,18 @@ public class Roster {
for (String resource : resources.keySet()) {
packetUnavailable = new Presence(Presence.Type.unavailable);
packetUnavailable.setFrom(user + "/" + resource);
presencePacketListener.processPacket(packetUnavailable);
try {
presencePacketListener.processPacket(packetUnavailable);
}
catch (NotConnectedException e) {
throw new IllegalStateException(
"presencePakcetListener should never throw a NotConnectedException when processPacket is called with a presence of type unavailable",
e);
}
}
}
}
loaded = false;
}
/**
@ -719,8 +756,8 @@ public class Roster {
* @param updatedEntries the collection of address of the updated contacts.
* @param deletedEntries the collection of address of the deleted contacts.
*/
private void fireRosterChangedEvent(Collection<String> addedEntries, Collection<String> updatedEntries,
Collection<String> deletedEntries) {
private void fireRosterChangedEvent(final Collection<String> addedEntries, final Collection<String> updatedEntries,
final Collection<String> deletedEntries) {
for (RosterListener listener : rosterListeners) {
if (!addedEntries.isEmpty()) {
listener.entriesAdded(addedEntries);
@ -739,7 +776,7 @@ public class Roster {
*
* @param presence the presence change.
*/
private void fireRosterPresenceEvent(Presence presence) {
private void fireRosterPresenceEvent(final Presence presence) {
for (RosterListener listener : rosterListeners) {
listener.presenceChanged(presence);
}
@ -1068,7 +1105,7 @@ public class Roster {
}
}
rosterInitialized = true;
loaded = true;
synchronized (Roster.this) {
Roster.this.notifyAll();
}

View File

@ -246,16 +246,20 @@ public interface XMPPConnection {
public void removePacketCollector(PacketCollector collector);
/**
* Registers a packet listener with this connection. A packet listener will be invoked only
* when an incoming packet is received. A packet filter determines
* which packets will be delivered to the listener. If the same packet listener
* is added again with a different filter, only the new filter will be used.
*
* NOTE: If you want get a similar callback for outgoing packets, see {@link #addPacketInterceptor(PacketListener, PacketFilter)}.
*
* Registers a packet listener with this connection.
* <p>
* This method has been deprecated. It is important to differentiate between using an asynchronous packet listener
* (preferred where possible) and a synchronous packet lister. Refer
* {@link #addAsyncPacketListener(PacketListener, PacketFilter)} and
* {@link #addSyncPacketListener(PacketListener, PacketFilter)} for more information.
* </p>
*
* @param packetListener the packet listener to notify of new received packets.
* @param packetFilter the packet filter to use.
* @param packetFilter the packet filter to use.
* @deprecated use {@link #addAsyncPacketListener(PacketListener, PacketFilter)} or
* {@link #addSyncPacketListener(PacketListener, PacketFilter)}.
*/
@Deprecated
public void addPacketListener(PacketListener packetListener, PacketFilter packetFilter);
/**
@ -263,22 +267,54 @@ public interface XMPPConnection {
*
* @param packetListener the packet listener to remove.
* @return true if the packet listener was removed
* @deprecated use {@link #removeAsyncPacketListener(PacketListener)} or {@link #removeSyncPacketListener(PacketListener)}.
*/
@Deprecated
public boolean removePacketListener(PacketListener packetListener);
/**
* Registers a <b>synchronous</b> packet listener with this connection. A packet listener will be invoked only when
* an incoming packet is received. A packet filter determines which packets will be delivered to the listener. If
* the same packet listener is added again with a different filter, only the new filter will be used.
* <p>
* <b>Important:</b> This packet listeners will be called in the same <i>single</i> thread that processes all
* incoming stanzas. Only use this kind of packet filter if it does not perform any XMPP activity that waits for a
* response. Consider using {@link #addAsyncPacketListener(PacketListener, PacketFilter)} when possible, i.e. when
* the invocation order doesn't have to be the same as the order of the arriving packets. If the order of the
* arriving packets, consider using a {@link PacketCollector} when possible.
* </p>
*
* @param packetListener the packet listener to notify of new received packets.
* @param packetFilter the packet filter to use.
* @see {@link #addPacketInterceptor(PacketListener, PacketFilter)} for a similar callback for outgoing stanzas.
* @since 4.1
*/
public void addSyncPacketListener(PacketListener packetListener, PacketFilter packetFilter);
/**
* Removes a packet listener for received packets from this connection.
*
* @param packetListener the packet listener to remove.
* @return true if the packet listener was removed
* @since 4.1
*/
public boolean removeSyncPacketListener(PacketListener packetListener);
/**
* Registers an <b>asynchronous</b> packet listener with this connection. A packet listener will be invoked only
* when an incoming packet is received. A packet filter determines which packets will be delivered to the listener.
* If the same packet listener is added again with a different filter, only the new filter will be used.
* <p>
* Unlike {@link #addPacketListener(PacketListener, PacketFilter)} packet listeners added with this method will be
* Unlike {@link #addAsyncPacketListener(PacketListener, PacketFilter)} packet listeners added with this method will be
* invoked asynchronously in their own thread. Use this method if the order of the packet listeners must not depend
* on the order how the stanzas where received.
* </p>
*
* @param packetListener the packet listener to notify of new received packets.
* @param packetFilter the packet filter to use.
*/
* @see {@link #addPacketInterceptor(PacketListener, PacketFilter)} for a similar callback for outgoing stanzas.
* @since 4.1
*/
public void addAsyncPacketListener(PacketListener packetListener, PacketFilter packetFilter);
/**
@ -286,6 +322,7 @@ public interface XMPPConnection {
*
* @param packetListener the packet listener to remove.
* @return true if the packet listener was removed
* @since 4.1
*/
public boolean removeAsyncPacketListener(PacketListener packetListener);
@ -316,7 +353,7 @@ public interface XMPPConnection {
* will be delivered to the interceptor.
*
* <p>
* NOTE: For a similar functionality on incoming packets, see {@link #addPacketListener(PacketListener, PacketFilter)}.
* NOTE: For a similar functionality on incoming packets, see {@link #addAsyncPacketListener(PacketListener, PacketFilter)}.
*
* @param packetInterceptor the packet interceptor to notify of packets about to be sent.
* @param packetFilter the packet filter to use.

View File

@ -27,102 +27,108 @@ import org.jivesoftware.smack.ChatManager.MatchMode;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Message.Type;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.test.util.WaitForPacketListener;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class ChatConnectionTest {
private DummyConnection connection;
private DummyConnection dc;
private ChatManager cm;
private TestChatManagerListener listener;
private WaitForPacketListener waitListener;
@Before
public void setUp() throws Exception {
connection = getConnection();
// Defaults
ChatManager.setDefaultIsNormalIncluded(true);
ChatManager.setDefaultMatchMode(MatchMode.BARE_JID);
dc = DummyConnection.newConnectedDummyConnection();
cm = ChatManager.getInstanceFor(dc);
listener = new TestChatManagerListener();
cm.addChatListener(listener);
waitListener = new WaitForPacketListener();
dc.addSyncPacketListener(waitListener, null);
}
@After
public void tearDown() throws Exception {
if (connection != null)
connection.disconnect();
if (dc != null) {
dc.disconnect();
}
}
@Test
public void validateDefaultSetNormalIncluded() {
public void validateDefaultSetNormalIncludedFalse() {
ChatManager.setDefaultIsNormalIncluded(false);
assertFalse(ChatManager.getInstanceFor(getConnection()).isNormalIncluded());
assertFalse(ChatManager.getInstanceFor(new DummyConnection()).isNormalIncluded());
}
@Test
public void validateDefaultSetNormalIncludedTrue() {
ChatManager.setDefaultIsNormalIncluded(true);
assertTrue(ChatManager.getInstanceFor(getConnection()).isNormalIncluded());
assertTrue(ChatManager.getInstanceFor(new DummyConnection()).isNormalIncluded());
}
@Test
public void validateDefaultSetMatchMode() {
public void validateDefaultSetMatchModeNone() {
ChatManager.setDefaultMatchMode(MatchMode.NONE);
assertEquals(MatchMode.NONE, ChatManager.getInstanceFor(getConnection()).getMatchMode());
assertEquals(MatchMode.NONE, ChatManager.getInstanceFor(new DummyConnection()).getMatchMode());
}
@Test
public void validateDefaultSetMatchModeBareJid() {
ChatManager.setDefaultMatchMode(MatchMode.BARE_JID);
assertEquals(MatchMode.BARE_JID, ChatManager.getInstanceFor(getConnection()).getMatchMode());
assertEquals(MatchMode.BARE_JID, ChatManager.getInstanceFor(new DummyConnection()).getMatchMode());
}
@Test
public void validateMessageTypeWithDefaults() {
DummyConnection dc = getConnection();
ChatManager cm = ChatManager.getInstanceFor(dc);
TestChatManagerListener listener = new TestChatManagerListener();
cm.addChatListener(listener);
public void validateMessageTypeWithDefaults1() {
Message incomingChat = createChatPacket("134", true);
incomingChat.setType(Type.chat);
processServerMessage(incomingChat, dc);
processServerMessage(incomingChat);
assertNotNull(listener.getNewChat());
}
dc = getConnection();
cm = ChatManager.getInstanceFor(dc);
listener = new TestChatManagerListener();
cm.addChatListener(listener);
incomingChat = createChatPacket("134", true);
@Test
public void validateMessageTypeWithDefaults2() {
Message incomingChat = createChatPacket("134", true);
incomingChat.setType(Type.normal);
processServerMessage(incomingChat, dc);
processServerMessage(incomingChat);
assertNotNull(listener.getNewChat());
dc = getConnection();
cm = ChatManager.getInstanceFor(dc);
listener = new TestChatManagerListener();
cm.addChatListener(listener);
incomingChat = createChatPacket("134", true);
}
@Test
public void validateMessageTypeWithDefaults3() {
Message incomingChat = createChatPacket("134", true);
incomingChat.setType(Type.groupchat);
processServerMessage(incomingChat, dc);
assertNull(listener.getNewChat());
dc = getConnection();
cm = ChatManager.getInstanceFor(dc);
listener = new TestChatManagerListener();
cm.addChatListener(listener);
incomingChat = createChatPacket("134", true);
incomingChat.setType(Type.headline);
processServerMessage(incomingChat, dc);
processServerMessage(incomingChat);
assertNull(listener.getNewChat());
}
@Test
public void validateMessageTypeWithNoNormal() {
DummyConnection dc = getConnection();
ChatManager cm = ChatManager.getInstanceFor(dc);
public void validateMessageTypeWithDefaults4() {
Message incomingChat = createChatPacket("134", true);
incomingChat.setType(Type.headline);
assertNull(listener.getNewChat());
}
@Test
public void validateMessageTypeWithNoNormal1() {
cm.setNormalIncluded(false);
TestChatManagerListener listener = new TestChatManagerListener();
cm.addChatListener(listener);
Message incomingChat = createChatPacket("134", true);
incomingChat.setType(Type.chat);
processServerMessage(incomingChat, dc);
processServerMessage(incomingChat);
assertNotNull(listener.getNewChat());
}
dc = getConnection();
cm = ChatManager.getInstanceFor(dc);
@Test
public void validateMessageTypeWithNoNormal2() {
cm.setNormalIncluded(false);
listener = new TestChatManagerListener();
cm.addChatListener(listener);
incomingChat = createChatPacket("134", true);
Message incomingChat = createChatPacket("134", true);
incomingChat.setType(Type.normal);
processServerMessage(incomingChat, dc);
processServerMessage(incomingChat);
assertNull(listener.getNewChat());
}
@ -130,65 +136,59 @@ public class ChatConnectionTest {
@Test
public void chatMatchedOnJIDWhenNoThreadBareMode() {
// MatchMode.BARE_JID is the default, so setting required.
DummyConnection con = getConnection();
TestMessageListener msgListener = new TestMessageListener();
TestChatManagerListener listener = new TestChatManagerListener(msgListener);
ChatManager cm = ChatManager.getInstanceFor(con);
cm.addChatListener(listener);
Packet incomingChat = createChatPacket(null, true);
processServerMessage(incomingChat, con);
processServerMessage(incomingChat);
Chat newChat = listener.getNewChat();
assertNotNull(newChat);
// Should match on chat with full jid
incomingChat = createChatPacket(null, true);
processServerMessage(incomingChat, con);
processServerMessage(incomingChat);
assertEquals(2, msgListener.getNumMessages());
// Should match on chat with bare jid
incomingChat = createChatPacket(null, false);
processServerMessage(incomingChat, con);
processServerMessage(incomingChat);
assertEquals(3, msgListener.getNumMessages());
}
@Test
public void chatMatchedOnJIDWhenNoThreadJidMode() {
DummyConnection con = getConnection();
TestMessageListener msgListener = new TestMessageListener();
TestChatManagerListener listener = new TestChatManagerListener(msgListener);
ChatManager cm = ChatManager.getInstanceFor(con);
cm.setMatchMode(MatchMode.SUPPLIED_JID);
cm.addChatListener(listener);
Packet incomingChat = createChatPacket(null, true);
processServerMessage(incomingChat, con);
processServerMessage(incomingChat);
Chat newChat = listener.getNewChat();
assertNotNull(newChat);
cm.removeChatListener(listener);
// Should match on chat with full jid
incomingChat = createChatPacket(null, true);
processServerMessage(incomingChat, con);
processServerMessage(incomingChat);
assertEquals(2, msgListener.getNumMessages());
// Should not match on chat with bare jid
TestChatManagerListener listener2 = new TestChatManagerListener();
cm.addChatListener(listener2);
incomingChat = createChatPacket(null, false);
processServerMessage(incomingChat, con);
processServerMessage(incomingChat);
assertEquals(2, msgListener.getNumMessages());
assertNotNull(listener2.getNewChat());
}
@Test
public void chatMatchedOnJIDWhenNoThreadNoneMode() {
DummyConnection con = getConnection();
TestMessageListener msgListener = new TestMessageListener();
TestChatManagerListener listener = new TestChatManagerListener(msgListener);
ChatManager cm = ChatManager.getInstanceFor(con);
cm.setMatchMode(MatchMode.NONE);
cm.addChatListener(listener);
Packet incomingChat = createChatPacket(null, true);
processServerMessage(incomingChat, con);
processServerMessage(incomingChat);
Chat newChat = listener.getNewChat();
assertNotNull(newChat);
assertEquals(1, msgListener.getNumMessages());
@ -198,7 +198,7 @@ public class ChatConnectionTest {
TestChatManagerListener listener2 = new TestChatManagerListener();
cm.addChatListener(listener2);
incomingChat = createChatPacket(null, true);
processServerMessage(incomingChat, con);
processServerMessage(incomingChat);
assertEquals(1, msgListener.getNumMessages());
assertNotNull(newChat);
cm.removeChatListener(listener2);
@ -207,7 +207,7 @@ public class ChatConnectionTest {
TestChatManagerListener listener3 = new TestChatManagerListener();
cm.addChatListener(listener3);
incomingChat = createChatPacket(null, false);
processServerMessage(incomingChat, con);
processServerMessage(incomingChat);
assertEquals(1, msgListener.getNumMessages());
assertNotNull(listener3.getNewChat());
}
@ -218,9 +218,6 @@ public class ChatConnectionTest {
*/
@Test
public void chatFoundWhenNoThreadFullJid() {
TestChatManagerListener listener = new TestChatManagerListener();
ChatManager cm = ChatManager.getInstanceFor(connection);
cm.addChatListener(listener);
Chat outgoing = cm.createChat("you@testserver", null);
Packet incomingChat = createChatPacket(null, true);
@ -237,9 +234,6 @@ public class ChatConnectionTest {
*/
@Test
public void chatFoundWhenNoThreadBaseJid() {
TestChatManagerListener listener = new TestChatManagerListener();
ChatManager cm = ChatManager.getInstanceFor(connection);
cm.addChatListener(listener);
Chat outgoing = cm.createChat("you@testserver", null);
Packet incomingChat = createChatPacket(null, false);
@ -256,9 +250,6 @@ public class ChatConnectionTest {
*/
@Test
public void chatFoundWithSameThreadFullJid() {
TestChatManagerListener listener = new TestChatManagerListener();
ChatManager cm = ChatManager.getInstanceFor(connection);
cm.addChatListener(listener);
Chat outgoing = cm.createChat("you@testserver", null);
Packet incomingChat = createChatPacket(outgoing.getThreadID(), true);
@ -275,9 +266,6 @@ public class ChatConnectionTest {
*/
@Test
public void chatFoundWithSameThreadBaseJid() {
TestChatManagerListener listener = new TestChatManagerListener();
ChatManager cm = ChatManager.getInstanceFor(connection);
cm.addChatListener(listener);
Chat outgoing = cm.createChat("you@testserver", null);
Packet incomingChat = createChatPacket(outgoing.getThreadID(), false);
@ -294,9 +282,6 @@ public class ChatConnectionTest {
*/
@Test
public void chatNotFoundWithDiffThreadBaseJid() {
TestChatManagerListener listener = new TestChatManagerListener();
ChatManager cm = ChatManager.getInstanceFor(connection);
cm.addChatListener(listener);
Chat outgoing = cm.createChat("you@testserver", null);
Packet incomingChat = createChatPacket(outgoing.getThreadID() + "ff", false);
@ -313,9 +298,6 @@ public class ChatConnectionTest {
*/
@Test
public void chatNotFoundWithDiffThreadFullJid() {
TestChatManagerListener listener = new TestChatManagerListener();
ChatManager cm = ChatManager.getInstanceFor(connection);
cm.addChatListener(listener);
Chat outgoing = cm.createChat("you@testserver", null);
Packet incomingChat = createChatPacket(outgoing.getThreadID() + "ff", true);
@ -328,11 +310,7 @@ public class ChatConnectionTest {
@Test
public void chatNotMatchedWithTypeNormal() {
TestChatManagerListener listener = new TestChatManagerListener();
DummyConnection con = getConnection();
ChatManager cm = ChatManager.getInstanceFor(con);
cm.setNormalIncluded(false);
cm.addChatListener(listener);
Message incomingChat = createChatPacket(null, false);
incomingChat.setType(Type.normal);
@ -341,50 +319,26 @@ public class ChatConnectionTest {
assertNull(listener.getNewChat());
}
@SuppressWarnings("unused")
private ChatManager getChatManager(boolean includeNormal, MatchMode mode) {
ChatManager cm = ChatManager.getInstanceFor(getConnection());
cm.setMatchMode(mode);
cm.setNormalIncluded(includeNormal);
return cm;
}
private DummyConnection getConnection() {
DummyConnection con = new DummyConnection();
try {
con.connect();
con.login();
} catch (Exception e) {
// No need for handling in a dummy connection.
}
return con;
}
private Message createChatPacket(final String threadId, final boolean isFullJid) {
Message chatMsg = new Message("me@testserver", Message.Type.chat);
chatMsg.setBody("the body message - " + System.currentTimeMillis());
chatMsg.setFrom("you@testserver" + (isFullJid ? "/resource" : ""));
if (threadId != null)
chatMsg.setThread(threadId);
chatMsg.setThread(threadId);
return chatMsg;
}
private void processServerMessage(Packet incomingChat) {
processServerMessage(incomingChat, connection);
}
private void processServerMessage(Packet incomingChat, DummyConnection con) {
TestChatServer chatServer = new TestChatServer(incomingChat, con);
TestChatServer chatServer = new TestChatServer(incomingChat, dc);
chatServer.start();
try {
chatServer.join();
} catch (InterruptedException e) {
fail();
}
waitListener.waitAndReset();
}
class TestChatManagerListener implements ChatManagerListener {
class TestChatManagerListener extends WaitForPacketListener implements ChatManagerListener {
private Chat newChat;
private ChatMessageListener listener;
@ -401,6 +355,7 @@ public class ChatConnectionTest {
if (listener != null)
newChat.addMessageListener(listener);
reportInvoked();
}
public Chat getNewChat() {

View File

@ -17,6 +17,7 @@
package org.jivesoftware.smack;
import java.io.IOException;
import java.util.Date;
import java.util.Random;
import java.util.concurrent.BlockingQueue;
@ -189,7 +190,7 @@ public class DummyConnection extends AbstractXMPPConnection {
*/
@SuppressWarnings("unchecked")
public <P extends TopLevelStreamElement> P getSentPacket() throws InterruptedException {
return (P) queue.poll();
return (P) queue.poll(5, TimeUnit.MINUTES);
}
/**
@ -221,6 +222,18 @@ public class DummyConnection extends AbstractXMPPConnection {
invokePacketCollectorsAndNotifyRecvListeners(packet);
}
public static DummyConnection newConnectedDummyConnection() {
DummyConnection dummyConnection = new DummyConnection();
try {
dummyConnection.connect();
dummyConnection.login();
}
catch (SmackException | IOException | XMPPException e) {
throw new IllegalStateException(e);
}
return dummyConnection;
}
public static class DummyConnectionConfiguration extends ConnectionConfiguration {
protected DummyConnectionConfiguration(Builder builder) {
super(builder);

View File

@ -26,6 +26,7 @@ import static org.junit.Assert.fail;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import org.jivesoftware.smack.packet.IQ;
@ -36,6 +37,7 @@ import org.jivesoftware.smack.packet.IQ.Type;
import org.jivesoftware.smack.packet.RosterPacket.Item;
import org.jivesoftware.smack.packet.RosterPacket.ItemType;
import org.jivesoftware.smack.test.util.TestUtils;
import org.jivesoftware.smack.test.util.WaitForPacketListener;
import org.jivesoftware.smack.util.PacketParserUtils;
import org.junit.After;
import org.junit.Before;
@ -52,6 +54,7 @@ import org.xmlpull.v1.XmlPullParser;
public class RosterTest {
private DummyConnection connection;
private Roster roster;
private TestRosterListener rosterListener;
@Before
@ -63,7 +66,9 @@ public class RosterTest {
connection.connect();
connection.login();
rosterListener = new TestRosterListener();
connection.getRoster().addRosterListener(rosterListener);
roster = connection.getRoster();
roster.addRosterListener(rosterListener);
connection.setPacketReplyTimeout(1000 * 60 * 5);
}
@After
@ -83,19 +88,17 @@ public class RosterTest {
* <a href="http://xmpp.org/rfcs/rfc3921.html#roster-login"
* >RFC3921: Retrieving One's Roster on Login</a>.
*/
@Test(timeout=5000)
@Test
public void testSimpleRosterInitialization() throws Exception {
// Setup
final Roster roster = connection.getRoster();
assertNotNull("Can't get the roster from the provided connection!", roster);
assertFalse("Roster shouldn't be already initialized!",
roster.rosterInitialized);
assertFalse("Roster shouldn't be already loaded!",
roster.isLoaded());
// Perform roster initialization
initRoster(connection, roster);
initRoster();
// Verify roster
assertTrue("Roster can't be initialized!", roster.rosterInitialized);
assertTrue("Roster can't be loaded!", roster.waitUntilLoaded());
verifyRomeosEntry(roster.getEntry("romeo@example.net"));
verifyMercutiosEntry(roster.getEntry("mercutio@example.com"));
verifyBenvoliosEntry(roster.getEntry("benvolio@example.net"));
@ -121,7 +124,7 @@ public class RosterTest {
* <a href="http://xmpp.org/rfcs/rfc3921.html#roster-add"
* >RFC3921: Adding a Roster Item</a>.
*/
@Test(timeout=5000)
@Test
public void testAddRosterItem() throws Throwable {
// Constants for the new contact
final String contactJID = "nurse@example.com";
@ -129,9 +132,8 @@ public class RosterTest {
final String[] contactGroup = {"Servants"};
// Setup
final Roster roster = connection.getRoster();
assertNotNull("Can't get the roster from the provided connection!", roster);
initRoster(connection, roster);
initRoster();
rosterListener.reset();
// Adding the new roster item
@ -161,6 +163,7 @@ public class RosterTest {
if (exception != null) {
throw exception;
}
rosterListener.waitUntilInvocationOrTimeout();
// Verify the roster entry of the new contact
final RosterEntry addedEntry = roster.getEntry(contactJID);
@ -192,7 +195,7 @@ public class RosterTest {
* <a href="http://xmpp.org/rfcs/rfc3921.html#roster-update"
* >RFC3921: Updating a Roster Item</a>.
*/
@Test(timeout=5000)
@Test
public void testUpdateRosterItem() throws Throwable {
// Constants for the updated contact
final String contactJID = "romeo@example.net";
@ -200,9 +203,8 @@ public class RosterTest {
final String[] contactGroups = {"Friends", "Lovers"};
// Setup
final Roster roster = connection.getRoster();
assertNotNull("Can't get the roster from the provided connection!", roster);
initRoster(connection, roster);
initRoster();
rosterListener.reset();
// Updating the roster item
@ -235,6 +237,7 @@ public class RosterTest {
if (exception != null) {
throw exception;
}
rosterListener.waitUntilInvocationOrTimeout();
// Verify the roster entry of the updated contact
final RosterEntry addedEntry = roster.getEntry(contactJID);
@ -267,15 +270,14 @@ public class RosterTest {
* <a href="http://xmpp.org/rfcs/rfc3921.html#roster-delete"
* >RFC3921: Deleting a Roster Item</a>.
*/
@Test(timeout=5000)
@Test
public void testDeleteRosterItem() throws Throwable {
// The contact which should be deleted
final String contactJID = "romeo@example.net";
// Setup
final Roster roster = connection.getRoster();
assertNotNull("Can't get the roster from the provided connection!", roster);
initRoster(connection, roster);
initRoster();
rosterListener.reset();
// Delete a roster item
@ -296,6 +298,7 @@ public class RosterTest {
if (exception != null) {
throw exception;
}
rosterListener.waitUntilInvocationOrTimeout();
// Verify
final RosterEntry deletedEntry = roster.getEntry(contactJID);
@ -314,10 +317,9 @@ public class RosterTest {
* <a href="http://xmpp.org/internet-drafts/draft-ietf-xmpp-3921bis-03.html#roster-syntax-actions-push"
* >RFC3921bis-03: Roster Push</a>.
*/
@Test(timeout=5000)
@Test
public void testSimpleRosterPush() throws Throwable {
final String contactJID = "nurse@example.com";
final Roster roster = connection.getRoster();
assertNotNull("Can't get the roster from the provided connection!", roster);
final StringBuilder sb = new StringBuilder();
sb.append("<iq id=\"rostertest1\" type=\"set\" ")
@ -328,11 +330,12 @@ public class RosterTest {
.append("</iq>");
final XmlPullParser parser = TestUtils.getIQParser(sb.toString());
final IQ rosterPush = PacketParserUtils.parse(parser, connection);
initRoster(connection, roster);
initRoster();
rosterListener.reset();
// Simulate receiving the roster push
connection.processPacket(rosterPush);
rosterListener.waitUntilInvocationOrTimeout();
// Verify the roster entry of the new contact
final RosterEntry addedEntry = roster.getEntry(contactJID);
@ -358,7 +361,7 @@ public class RosterTest {
*
* @see <a href="http://xmpp.org/rfcs/rfc6121.html#roster-syntax-actions-push">RFC 6121, Section 2.1.6</a>
*/
@Test(timeout=5000)
@Test
public void testIgnoreInvalidFrom() {
RosterPacket packet = new RosterPacket();
packet.setType(Type.set);
@ -366,8 +369,11 @@ public class RosterTest {
packet.setFrom("mallory@example.com");
packet.addRosterItem(new Item("spam@example.com", "Cool products!"));
WaitForPacketListener waitForPacketListener = new WaitForPacketListener();
connection.addAsyncPacketListener(waitForPacketListener, null);
// Simulate receiving the roster push
connection.processPacket(packet);
waitForPacketListener.waitUntilInvocationOrTimeout();
assertNull("Contact was added to roster", connection.getRoster().getEntry("spam@example.com"));
}
@ -386,9 +392,8 @@ public class RosterTest {
final String[] contactGroup = {""};
// Setup
final Roster roster = connection.getRoster();
assertNotNull("Can't get the roster from the provided connection!", roster);
initRoster(connection, roster);
initRoster();
rosterListener.reset();
// Adding the new roster item
@ -416,6 +421,7 @@ public class RosterTest {
if (exception != null) {
throw exception;
}
rosterListener.waitUntilInvocationOrTimeout();
// Verify the roster entry of the new contact
final RosterEntry addedEntry = roster.getEntry(contactJID);
@ -445,10 +451,9 @@ public class RosterTest {
*
* @see <a href="http://www.igniterealtime.org/issues/browse/SMACK-294">SMACK-294</a>
*/
@Test(timeout=5000)
@Test
public void testEmptyGroupRosterPush() throws Throwable {
final String contactJID = "nurse@example.com";
final Roster roster = connection.getRoster();
assertNotNull("Can't get the roster from the provided connection!", roster);
final StringBuilder sb = new StringBuilder();
sb.append("<iq id=\"rostertest2\" type=\"set\" ")
@ -461,11 +466,12 @@ public class RosterTest {
.append("</iq>");
final XmlPullParser parser = TestUtils.getIQParser(sb.toString());
final IQ rosterPush = PacketParserUtils.parse(parser, connection);
initRoster(connection, roster);
initRoster();
rosterListener.reset();
// Simulate receiving the roster push
connection.processPacket(rosterPush);
rosterListener.waitUntilInvocationOrTimeout();
// Verify the roster entry of the new contact
final RosterEntry addedEntry = roster.getEntry(contactJID);
@ -520,7 +526,7 @@ public class RosterTest {
* @param roster the roster (or buddy list) which should be initialized.
* @throws SmackException
*/
public static void initRoster(DummyConnection connection, Roster roster) throws InterruptedException, XMPPException, SmackException {
private void initRoster() throws InterruptedException, XMPPException, SmackException {
roster.reload();
while (true) {
final Packet sentPacket = connection.getSentPacket();
@ -558,6 +564,8 @@ public class RosterTest {
break;
}
}
roster.waitUntilLoaded();
rosterListener.waitUntilInvocationOrTimeout();
}
/**
@ -687,10 +695,10 @@ public class RosterTest {
/**
* This class can be used to check if the RosterListener was invoked.
*/
public static class TestRosterListener implements RosterListener {
private CopyOnWriteArrayList<String> addressesAdded = new CopyOnWriteArrayList<String>();
private CopyOnWriteArrayList<String> addressesDeleted = new CopyOnWriteArrayList<String>();
private CopyOnWriteArrayList<String> addressesUpdated = new CopyOnWriteArrayList<String>();
public static class TestRosterListener extends WaitForPacketListener implements RosterListener {
private final List<String> addressesAdded = new CopyOnWriteArrayList<>();
private final List<String> addressesDeleted = new CopyOnWriteArrayList<>();
private final List<String> addressesUpdated = new CopyOnWriteArrayList<>();
public synchronized void entriesAdded(Collection<String> addresses) {
addressesAdded.addAll(addresses);
@ -699,6 +707,7 @@ public class RosterTest {
System.out.println("Roster entry for " + address + " added.");
}
}
reportInvoked();
}
public synchronized void entriesDeleted(Collection<String> addresses) {
@ -708,6 +717,7 @@ public class RosterTest {
System.out.println("Roster entry for " + address + " deleted.");
}
}
reportInvoked();
}
public synchronized void entriesUpdated(Collection<String> addresses) {
@ -717,12 +727,14 @@ public class RosterTest {
System.out.println("Roster entry for " + address + " updated.");
}
}
reportInvoked();
}
public void presenceChanged(Presence presence) {
if (SmackConfiguration.DEBUG_ENABLED) {
System.out.println("Roster presence changed: " + presence.toXML());
}
reportInvoked();
}
/**
@ -756,6 +768,7 @@ public class RosterTest {
* Reset the lists of added, deleted or updated items.
*/
public synchronized void reset() {
super.reset();
addressesAdded.clear();
addressesDeleted.clear();
addressesUpdated.clear();

View File

@ -27,6 +27,7 @@ import java.util.Collection;
import java.util.HashSet;
import org.jivesoftware.smack.ConnectionConfiguration.Builder;
import org.jivesoftware.smack.RosterTest.TestRosterListener;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.IQ.Type;
import org.jivesoftware.smack.packet.Packet;
@ -53,15 +54,14 @@ import org.junit.rules.TemporaryFolder;
public class RosterVersioningTest {
private DummyConnection connection;
private Roster roster;
private TestRosterListener rosterListener;
@Rule
public TemporaryFolder tmpFolder = new TemporaryFolder();
@Before
public void setUp() throws Exception {
// Uncomment this to enable debug output
//XMPPConnection.DEBUG_ENABLED = true;
DirectoryRosterStore store = DirectoryRosterStore.init(tmpFolder.newFolder("store"));
populateStore(store);
@ -69,13 +69,20 @@ public class RosterVersioningTest {
builder.setRosterStore(store);
connection = new DummyConnection(builder.build());
connection.connect();
connection.login();
rosterListener = new TestRosterListener();
roster = connection.getRoster();
roster.addRosterListener(rosterListener);
roster.reload();
}
@After
public void tearDown() throws Exception {
if (connection != null) {
if (rosterListener != null && roster != null) {
roster.removeRosterListener(rosterListener);
rosterListener = null;
}
connection.disconnect();
connection = null;
}
@ -89,10 +96,9 @@ public class RosterVersioningTest {
*/
@Test(timeout = 5000)
public void testEqualVersionStored() throws InterruptedException, IOException, XMPPException, SmackException {
connection.getRoster().reload();
answerWithEmptyRosterResult();
roster.waitUntilLoaded();
Roster roster = connection.getRoster();
Collection<RosterEntry> entries = roster.getEntries();
assertSame("Size of the roster", 3, entries.size());
@ -124,8 +130,6 @@ public class RosterVersioningTest {
*/
@Test(timeout = 5000)
public void testOtherVersionStored() throws InterruptedException, XMPPException, SmackException {
connection.getRoster().reload();
Item vaglafItem = vaglafItem();
// We expect that the roster request is the only packet sent. This is not part of the specification,
@ -141,7 +145,9 @@ public class RosterVersioningTest {
answer.setVersion("newVersion");
answer.addRosterItem(vaglafItem);
rosterListener.reset();
connection.processPacket(answer);
rosterListener.waitUntilInvocationOrTimeout();
} else {
assertTrue("Expected to get a RosterPacket ", false);
}
@ -164,11 +170,10 @@ public class RosterVersioningTest {
*/
@Test(timeout = 5000)
public void testRosterVersioningWithCachedRosterAndPushes() throws Throwable {
connection.getRoster().reload();
answerWithEmptyRosterResult();
rosterListener.waitAndReset();
RosterStore store = connection.getConfiguration().getRosterStore();
Roster roster = connection.getRoster();
// Simulate a roster push adding vaglaf
{
@ -179,7 +184,9 @@ public class RosterVersioningTest {
Item pushedItem = vaglafItem();
rosterPush.addRosterItem(pushedItem);
rosterListener.reset();
connection.processPacket(rosterPush);
rosterListener.waitAndReset();
assertEquals("Expect store version after push", "v97", store.getRosterVersion());
@ -204,7 +211,9 @@ public class RosterVersioningTest {
Item item = new Item("vaglaf@example.com", "vaglaf the only");
item.setItemType(ItemType.remove);
rosterPush.addRosterItem(item);
rosterListener.reset();
connection.processPacket(rosterPush);
rosterListener.waitAndReset();
assertNull("Store doses not contain vaglaf", store.getEntry("vaglaf@example.com"));
assertEquals("Expect store version after push", "v98", store.getRosterVersion());

View File

@ -0,0 +1,60 @@
/**
*
* Copyright 2015 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smack.test.util;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.jivesoftware.smack.PacketListener;
import org.jivesoftware.smack.SmackException.NotConnectedException;
import org.jivesoftware.smack.packet.Packet;
public class WaitForPacketListener implements PacketListener {
private CountDownLatch latch = new CountDownLatch(1);
@Override
public void processPacket(Packet packet) throws NotConnectedException {
reportInvoked();
}
protected void reportInvoked() {
latch.countDown();
}
public void waitAndReset() {
waitUntilInvocationOrTimeout();
reset();
}
public void waitUntilInvocationOrTimeout() {
try {
boolean res = latch.await(30, TimeUnit.SECONDS);
if (!res) {
throw new IllegalStateException("Latch timed out before it reached zero");
}
}
catch (InterruptedException e) {
// TODO better handling of spurious interrupts
throw new IllegalStateException(e);
}
}
public void reset() {
latch = new CountDownLatch(1);
}
}

View File

@ -956,7 +956,7 @@ public class EnhancedDebugger implements SmackDebugger {
*/
void cancel() {
connection.removeConnectionListener(connListener);
connection.removePacketListener(packetReaderListener);
connection.removeAsyncPacketListener(packetReaderListener);
connection.removePacketSendingListener(packetWriterListener);
((ObservableReader) reader).removeReaderListener(readerListener);
((ObservableWriter) writer).removeWriterListener(writerListener);

View File

@ -278,7 +278,7 @@ public class LiteDebugger implements SmackDebugger {
* @param evt the event that indicates that the root window is closing
*/
public void rootWindowClosing(WindowEvent evt) {
connection.removePacketListener(listener);
connection.removeAsyncPacketListener(listener);
((ObservableReader)reader).removeReaderListener(readerListener);
((ObservableWriter)writer).removeWriterListener(writerListener);
}

View File

@ -101,7 +101,7 @@ public class MessageEventTest extends SmackTestCase {
}
}
};
getConnection(0).addPacketListener(packetListener, packetFilter);
getConnection(0).addAsyncPacketListener(packetListener, packetFilter);
// Create the message to send with the roster
Message msg = new Message();

View File

@ -150,7 +150,7 @@ public class XHTMLExtensionTest extends SmackTestCase {
}
};
getConnection(1).addPacketListener(packetListener, packetFilter);
getConnection(1).addAsyncPacketListener(packetListener, packetFilter);
// User1 creates a message to send to user2
Message msg = new Message();

View File

@ -215,16 +215,16 @@ public class InBandBytestreamManager implements BytestreamManager {
// register bytestream open packet listener
this.initiationListener = new InitiationListener(this);
this.connection.addPacketListener(this.initiationListener,
this.connection.addAsyncPacketListener(this.initiationListener,
this.initiationListener.getFilter());
// register bytestream data packet listener
this.dataListener = new DataListener(this);
this.connection.addPacketListener(this.dataListener, this.dataListener.getFilter());
this.connection.addSyncPacketListener(this.dataListener, this.dataListener.getFilter());
// register bytestream close packet listener
this.closeListener = new CloseListener(this);
this.connection.addPacketListener(this.closeListener, this.closeListener.getFilter());
this.connection.addSyncPacketListener(this.closeListener, this.closeListener.getFilter());
}
@ -548,9 +548,9 @@ public class InBandBytestreamManager implements BytestreamManager {
managers.remove(connection);
// remove all listeners registered by this manager
this.connection.removePacketListener(this.initiationListener);
this.connection.removePacketListener(this.dataListener);
this.connection.removePacketListener(this.closeListener);
this.connection.removeAsyncPacketListener(this.initiationListener);
this.connection.removeSyncPacketListener(this.dataListener);
this.connection.removeSyncPacketListener(this.closeListener);
// shutdown threads
this.initiationListener.shutdown();

View File

@ -264,7 +264,7 @@ public class InBandBytestreamSession implements BytestreamSession {
public IBBInputStream() {
// add data packet listener to connection
this.dataPacketListener = getDataPacketListener();
connection.addPacketListener(this.dataPacketListener, getDataPacketFilter());
connection.addSyncPacketListener(this.dataPacketListener, getDataPacketFilter());
}
/**
@ -431,7 +431,7 @@ public class InBandBytestreamSession implements BytestreamSession {
* Invoked if the session is closed.
*/
private void cleanup() {
connection.removePacketListener(this.dataPacketListener);
connection.removeSyncPacketListener(this.dataPacketListener);
}
}

View File

@ -289,7 +289,7 @@ public final class Socks5BytestreamManager implements BytestreamManager {
public synchronized void disableService() {
// remove initiation packet listener
this.connection.removePacketListener(this.initiationListener);
this.connection.removeAsyncPacketListener(this.initiationListener);
// shutdown threads
this.initiationListener.shutdown();
@ -718,7 +718,7 @@ public final class Socks5BytestreamManager implements BytestreamManager {
*/
private void activate() {
// register bytestream initiation packet listener
this.connection.addPacketListener(this.initiationListener,
this.connection.addAsyncPacketListener(this.initiationListener,
this.initiationListener.getFilter());
// enable SOCKS5 feature

View File

@ -315,7 +315,7 @@ public class EntityCapsManager extends Manager {
if (autoEnableEntityCaps)
enableEntityCaps();
connection.addPacketListener(new PacketListener() {
connection.addAsyncPacketListener(new PacketListener() {
// Listen for remote presence stanzas with the caps extension
// If we receive such a stanza, record the JID and nodeVer
@Override
@ -330,7 +330,7 @@ public class EntityCapsManager extends Manager {
}, PRESENCES_WITH_CAPS);
connection.addPacketListener(new PacketListener() {
connection.addAsyncPacketListener(new PacketListener() {
@Override
public void processPacket(Packet packet) {
// always remove the JID from the map, even if entityCaps are

View File

@ -148,7 +148,7 @@ public class ServiceDiscoveryManager extends Manager {
connection().sendPacket(response);
}
};
connection.addPacketListener(packetListener, GET_DISCOVER_ITEMS);
connection.addAsyncPacketListener(packetListener, GET_DISCOVER_ITEMS);
// Listen for disco#info requests and answer the client's supported features
// To add a new feature as supported use the #addFeature message
@ -187,7 +187,7 @@ public class ServiceDiscoveryManager extends Manager {
connection().sendPacket(response);
}
};
connection.addPacketListener(packetListener, GET_DISCOVER_INFO);
connection.addAsyncPacketListener(packetListener, GET_DISCOVER_INFO);
}
/**

View File

@ -160,7 +160,7 @@ public class LastActivityManager extends Manager {
}, PacketTypeFilter.MESSAGE);
// Register a listener for a last activity query
connection.addPacketListener(new PacketListener() {
connection.addAsyncPacketListener(new PacketListener() {
public void processPacket(Packet packet) throws NotConnectedException {
if (!enabled) return;

View File

@ -86,7 +86,7 @@ public class VersionManager extends Manager {
ServiceDiscoveryManager sdm = ServiceDiscoveryManager.getInstanceFor(connection);
sdm.addFeature(Version.NAMESPACE);
connection.addPacketListener(new PacketListener() {
connection.addAsyncPacketListener(new PacketListener() {
/**
* Sends a Version reply on request
* @throws NotConnectedException

View File

@ -292,12 +292,12 @@ public class MultiUserChat {
+ nickname), new PacketTypeFilter(Presence.class));
// Setup the messageListeners and presenceListeners *before* the join presence is send.
connection.addPacketListener(messageListener, fromRoomGroupchatFilter);
connection.addPacketListener(presenceListener, new AndFilter(fromRoomFilter,
connection.addSyncPacketListener(messageListener, fromRoomGroupchatFilter);
connection.addSyncPacketListener(presenceListener, new AndFilter(fromRoomFilter,
PacketTypeFilter.PRESENCE));
connection.addPacketListener(subjectListener, new AndFilter(fromRoomFilter,
connection.addSyncPacketListener(subjectListener, new AndFilter(fromRoomFilter,
MessageWithSubjectFilter.INSTANCE));
connection.addPacketListener(declinesListener, new AndFilter(new PacketExtensionFilter(MUCUser.ELEMENT,
connection.addSyncPacketListener(declinesListener, new AndFilter(new PacketExtensionFilter(MUCUser.ELEMENT,
MUCUser.NAMESPACE), new NotFilter(MessageTypeFilter.ERROR)));
connection.addPacketInterceptor(presenceInterceptor, new AndFilter(new ToFilter(room),
PacketTypeFilter.PRESENCE));
@ -1702,9 +1702,9 @@ public class MultiUserChat {
* connection.
*/
private void removeConnectionCallbacks() {
connection.removePacketListener(messageListener);
connection.removePacketListener(presenceListener);
connection.removePacketListener(declinesListener);
connection.removeSyncPacketListener(messageListener);
connection.removeSyncPacketListener(presenceListener);
connection.removeSyncPacketListener(declinesListener);
connection.removePacketInterceptor(presenceInterceptor);
if (messageCollector != null) {
messageCollector.cancel();

View File

@ -142,12 +142,12 @@ public class PEPManager {
firePEPListeners(message.getFrom(), event);
}
};
connection.addPacketListener(packetListener, packetFilter);
connection.addSyncPacketListener(packetListener, packetFilter);
}
public void destroy() {
if (connection != null)
connection.removePacketListener(packetListener);
connection.removeSyncPacketListener(packetListener);
}
protected void finalize() throws Throwable {

View File

@ -127,7 +127,7 @@ public class PingManager extends Manager {
ServiceDiscoveryManager sdm = ServiceDiscoveryManager.getInstanceFor(connection);
sdm.addFeature(Ping.NAMESPACE);
connection.addPacketListener(new PacketListener() {
connection.addAsyncPacketListener(new PacketListener() {
// Send a Pong for every Ping
@Override
public void processPacket(Packet packet) throws NotConnectedException {

View File

@ -85,7 +85,7 @@ public class PrivacyListManager extends Manager {
private PrivacyListManager(final XMPPConnection connection) {
super(connection);
connection.addPacketListener(new PacketListener() {
connection.addSyncPacketListener(new PacketListener() {
@Override
public void processPacket(Packet packet) throws NotConnectedException {
Privacy privacy = (Privacy) packet;

View File

@ -399,7 +399,7 @@ abstract public class Node
{
PacketListener conListener = new ItemEventTranslator(listener);
itemEventToListenerMap.put(listener, conListener);
con.addPacketListener(conListener, new EventContentFilter(EventElementType.items.toString(), "item"));
con.addSyncPacketListener(conListener, new EventContentFilter(EventElementType.items.toString(), "item"));
}
/**
@ -412,7 +412,7 @@ abstract public class Node
PacketListener conListener = itemEventToListenerMap.remove(listener);
if (conListener != null)
con.removePacketListener(conListener);
con.removeSyncPacketListener(conListener);
}
/**
@ -425,7 +425,7 @@ abstract public class Node
{
PacketListener conListener = new NodeConfigTranslator(listener);
configEventToListenerMap.put(listener, conListener);
con.addPacketListener(conListener, new EventContentFilter(EventElementType.configuration.toString()));
con.addSyncPacketListener(conListener, new EventContentFilter(EventElementType.configuration.toString()));
}
/**
@ -438,7 +438,7 @@ abstract public class Node
PacketListener conListener = configEventToListenerMap .remove(listener);
if (conListener != null)
con.removePacketListener(conListener);
con.removeSyncPacketListener(conListener);
}
/**
@ -454,7 +454,7 @@ abstract public class Node
EventContentFilter deleteItem = new EventContentFilter(EventElementType.items.toString(), "retract");
EventContentFilter purge = new EventContentFilter(EventElementType.purge.toString());
con.addPacketListener(delListener, new OrFilter(deleteItem, purge));
con.addSyncPacketListener(delListener, new OrFilter(deleteItem, purge));
}
/**
@ -467,7 +467,7 @@ abstract public class Node
PacketListener conListener = itemDeleteToListenerMap .remove(listener);
if (conListener != null)
con.removePacketListener(conListener);
con.removeSyncPacketListener(conListener);
}
@Override

View File

@ -62,7 +62,7 @@ public class DeliveryReceiptManager extends Manager implements PacketListener {
sdm.addFeature(DeliveryReceipt.NAMESPACE);
// register listener for delivery receipts and requests
connection.addPacketListener(this, new PacketExtensionFilter(DeliveryReceipt.NAMESPACE));
connection.addAsyncPacketListener(this, new PacketExtensionFilter(DeliveryReceipt.NAMESPACE));
}
/**

View File

@ -72,7 +72,7 @@ public class EntityTimeManager extends Manager {
if (autoEnable)
enable();
connection.addPacketListener(new PacketListener() {
connection.addAsyncPacketListener(new PacketListener() {
@Override
public void processPacket(Packet packet) throws NotConnectedException {
if (!enabled)

View File

@ -159,7 +159,7 @@ public class JingleManagerTest extends SmackTestCase {
};
// Start a packet listener for session initiation requests
getConnection(0).addPacketListener(new PacketListener() {
getConnection(0).addAsyncPacketListener(new PacketListener() {
public void processPacket(final Packet packet) {
System.out.println("Packet detected... ");
incCounter();

View File

@ -461,7 +461,7 @@ public class JingleManager implements JingleSessionListener {
jingleSessionRequestListeners = new ArrayList<JingleSessionRequestListener>();
// Start a packet listener for session initiation requests
connection.addPacketListener(new PacketListener() {
connection.addAsyncPacketListener(new PacketListener() {
public void processPacket(Packet packet) {
triggerSessionRequested((Jingle) packet);
}

View File

@ -654,9 +654,9 @@ public class JingleSession extends JingleNegotiator implements MediaReceivedList
/**
* Remove the packet listener used for processing packet.
*/
protected void removePacketListener() {
protected void removeAsyncPacketListener() {
if (packetListener != null) {
getConnection().removePacketListener(packetListener);
getConnection().removeAsyncPacketListener(packetListener);
LOGGER.fine("JINGLE SESSION: REMOVE PACKET LISTENER");
}
@ -667,7 +667,7 @@ public class JingleSession extends JingleNegotiator implements MediaReceivedList
* to any packet that we receive...
*/
protected void updatePacketListener() {
removePacketListener();
removeAsyncPacketListener();
LOGGER.fine("UpdatePacketListener");
@ -728,7 +728,7 @@ public class JingleSession extends JingleNegotiator implements MediaReceivedList
}
};
getConnection().addPacketListener(packetListener, packetFilter);
getConnection().addAsyncPacketListener(packetListener, packetFilter);
}
// Listeners
@ -1002,7 +1002,7 @@ public class JingleSession extends JingleNegotiator implements MediaReceivedList
contentNegotiator.close();
}
removePacketListener();
removeAsyncPacketListener();
removeConnectionListener();
getConnection().removeConnectionListener(connectionListener);
LOGGER.fine("Negotiation Closed: " + getConnection().getUser() + " " + sid);

View File

@ -74,9 +74,9 @@ public class AgentRoster {
presenceMap = new HashMap<String, Map<String, Presence>>();
// Listen for any roster packets.
PacketFilter rosterFilter = new PacketTypeFilter(AgentStatusRequest.class);
connection.addPacketListener(new AgentStatusListener(), rosterFilter);
connection.addAsyncPacketListener(new AgentStatusListener(), rosterFilter);
// Listen for any presence packets.
connection.addPacketListener(new PresencePacketListener(),
connection.addAsyncPacketListener(new PresencePacketListener(),
new PacketTypeFilter(Presence.class));
// Send request for roster.

View File

@ -157,7 +157,7 @@ public class AgentSession {
}
}
};
connection.addPacketListener(packetListener, filter);
connection.addAsyncPacketListener(packetListener, filter);
// Create the agent associated to this session
agent = new Agent(connection, workgroupJID);
}
@ -167,7 +167,7 @@ public class AgentSession {
* packet listeners that were added by this agent session will be removed.
*/
public void close() {
connection.removePacketListener(packetListener);
connection.removeAsyncPacketListener(packetListener);
}
/**

View File

@ -142,7 +142,7 @@ public class Workgroup {
// Register a packet listener for all the messages sent to this client.
PacketFilter typeFilter = new PacketTypeFilter(Message.class);
connection.addPacketListener(new PacketListener() {
connection.addAsyncPacketListener(new PacketListener() {
public void processPacket(Packet packet) {
handlePacket(packet);
}

View File

@ -75,7 +75,7 @@ public class MessageEventManager extends Manager {
private MessageEventManager(XMPPConnection connection) {
super(connection);
// Listens for all message event packets and fire the proper message event listeners.
connection.addPacketListener(new PacketListener() {
connection.addAsyncPacketListener(new PacketListener() {
public void processPacket(Packet packet) {
Message message = (Message) packet;
MessageEvent messageEvent =

View File

@ -85,7 +85,7 @@ public class RosterExchangeManager {
fireRosterExchangeListeners(message.getFrom(), rosterExchange.getRosterEntries());
}
};
connection.addPacketListener(packetListener, PACKET_FILTER);
connection.addAsyncPacketListener(packetListener, PACKET_FILTER);
}
/**

View File

@ -568,7 +568,7 @@ public class XMPPTCPConnection extends AbstractXMPPConnection {
// If debugging is enabled, we should start the thread that will listen for
// all packets and then log them.
if (config.isDebuggerEnabled()) {
addPacketListener(debugger.getReaderListener(), null);
addAsyncPacketListener(debugger.getReaderListener(), null);
if (debugger.getWriterListener() != null) {
addPacketSendingListener(debugger.getWriterListener(), null);
}