diff --git a/source/org/jivesoftware/smack/Chat.java b/source/org/jivesoftware/smack/Chat.java index c29832dd9..57e1633e4 100644 --- a/source/org/jivesoftware/smack/Chat.java +++ b/source/org/jivesoftware/smack/Chat.java @@ -24,15 +24,16 @@ import org.jivesoftware.smack.packet.Message; import org.jivesoftware.smack.util.StringUtils; import org.jivesoftware.smack.filter.*; +import java.util.*; +import java.lang.ref.WeakReference; + /** - * A chat is a series of messages sent between two users. Each chat can have - * a unique thread ID, which is used to track which messages are part of a particular - * conversation.
- *
- * In some situations, it is better to have all messages from the other user delivered
- * to a Chat rather than just the messages that have a particular thread ID. To
- * enable this behavior, call {@link #setFilteredOnThreadID(boolean)} with
- * false as the parameter.
+ * A chat is a series of messages sent between two users. Each chat has a unique
+ * thread ID, which is used to track which messages are part of a particular
+ * conversation. Some messages are sent without a thread ID, and some clients
+ * don't send thread IDs at all. Therefore, if a message without a thread ID
+ * arrives it is routed to the most recently created Chat with the message
+ * sender.
*
* @see XMPPConnection#createChat(String)
* @author Matt Tucker
@@ -43,13 +44,7 @@ public class Chat {
* A prefix helps to make sure that ID's are unique across mutliple instances.
*/
private static String prefix = StringUtils.randomString(5);
-
- /**
- * True if only messages that have a matching threadID will be delivered to a Chat. When
- * false, any message from the other participant will be delivered to a Chat.
- */
- private static boolean filteredOnThreadID = true;
-
+
/**
* Keeps track of the current increment, which is appended to the prefix to
* forum a unique ID.
@@ -71,6 +66,7 @@ public class Chat {
private String participant;
private PacketFilter messageFilter;
private PacketCollector messageCollector;
+ private Set listeners = new HashSet();
/**
* Creates a new chat with the specified user.
@@ -81,10 +77,6 @@ public class Chat {
public Chat(XMPPConnection connection, String participant) {
// Automatically assign the next chat ID.
this(connection, participant, nextID());
- // If not filtering on thread ID, force the thread ID for this Chat to be null.
- if (!filteredOnThreadID) {
- this.threadID = null;
- }
}
/**
@@ -99,42 +91,17 @@ public class Chat {
this.participant = participant;
this.threadID = threadID;
- if (filteredOnThreadID) {
- // Filter the messages whose thread equals Chat's id
- messageFilter = new ThreadFilter(threadID);
- }
- else {
- // Filter the messages of type "chat" and sender equals Chat's participant
- messageFilter =
- new OrFilter(
- new AndFilter(
- new MessageTypeFilter(Message.Type.CHAT),
- new FromContainsFilter(participant)),
- new ThreadFilter(threadID));
- }
+ // Register with the map of chats so that messages with no thread ID
+ // set will be delivered to this Chat.
+ connection.chats.put(StringUtils.parseBareAddress(participant),
+ new WeakReference(this));
+
+ // Filter the messages whose thread equals Chat's id
+ messageFilter = new ThreadFilter(threadID);
+
messageCollector = connection.createPacketCollector(messageFilter);
}
- /**
- * Returns true if only messages that have a matching threadID will be delivered to Chat
- * instances. When false, any message from the other participant will be delivered to Chat instances.
- *
- * @return true if messages delivered to Chat instances are filtered on thread ID.
- */
- public static boolean isFilteredOnThreadID() {
- return filteredOnThreadID;
- }
-
- /**
- * Sets whether only messages that have a matching threadID will be delivered to Chat instances.
- * When false, any message from the other participant will be delivered to a Chat instances.
- *
- * @param value true if messages delivered to Chat instances are filtered on thread ID.
- */
- public static void setFilteredOnThreadID(boolean value) {
- filteredOnThreadID = value;
- }
-
/**
* Returns the thread id associated with this chat, which corresponds to the
* thread field of XMPP messages. This method may return null
@@ -252,6 +219,41 @@ public class Chat {
*/
public void addMessageListener(PacketListener listener) {
connection.addPacketListener(listener, messageFilter);
+ // Keep track of the listener so that we can manually deliver extra
+ // messages to it later if needed.
+ synchronized (listeners) {
+ listeners.add(new WeakReference(listener));
+ }
+ }
+
+ /**
+ * Delivers a message directly to this chat, which will add the message
+ * to the collector and deliver it to all listeners registered with the
+ * Chat. This is used by the XMPPConnection class to deliver messages
+ * without a thread ID.
+ *
+ * @param message the message.
+ */
+ void deliver(Message message) {
+ // Because the collector and listeners are expecting a thread ID with
+ // a specific value, set the thread ID on the message even though it
+ // probably never had one.
+ message.setThread(threadID);
+
+ messageCollector.processPacket(message);
+ synchronized (listeners) {
+ for (Iterator i=listeners.iterator(); i.hasNext(); ) {
+ WeakReference listenerRef = (WeakReference)i.next();
+ PacketListener listener;
+ if ((listener = (PacketListener)listenerRef.get()) != null) {
+ listener.processPacket(message);
+ }
+ // If the reference was cleared, remove it from the set.
+ else {
+ i.remove();
+ }
+ }
+ }
}
public void finalize() throws Throwable {
@@ -261,6 +263,8 @@ public class Chat {
messageCollector.cancel();
}
}
- catch (Exception e) {}
+ catch (Exception e) {
+ // Ignore.
+ }
}
}
\ No newline at end of file
diff --git a/source/org/jivesoftware/smack/PacketCollector.java b/source/org/jivesoftware/smack/PacketCollector.java
index 75fba96cf..b54cc82dc 100644
--- a/source/org/jivesoftware/smack/PacketCollector.java
+++ b/source/org/jivesoftware/smack/PacketCollector.java
@@ -76,10 +76,7 @@ public class PacketCollector {
*/
public void cancel() {
// If the packet collector has already been cancelled, do nothing.
- if (cancelled) {
- return;
- }
- else {
+ if (!cancelled) {
cancelled = true;
// Remove object from collectors list by setting the value in the
// list at the correct index to null. The collector thread will
@@ -130,7 +127,9 @@ public class PacketCollector {
try {
wait();
}
- catch (InterruptedException ie) { }
+ catch (InterruptedException ie) {
+ // Ignore.
+ }
}
return (Packet)resultQueue.removeLast();
}
@@ -149,7 +148,9 @@ public class PacketCollector {
try {
wait(timeout);
}
- catch (InterruptedException ie) { }
+ catch (InterruptedException ie) {
+ // Ignore.
+ }
}
// If still no result, return null.
if (resultQueue.isEmpty()) {
diff --git a/source/org/jivesoftware/smack/PacketReader.java b/source/org/jivesoftware/smack/PacketReader.java
index 157602c47..148ed77ae 100644
--- a/source/org/jivesoftware/smack/PacketReader.java
+++ b/source/org/jivesoftware/smack/PacketReader.java
@@ -165,7 +165,9 @@ class PacketReader {
}
}
}
- catch (InterruptedException ie) { }
+ catch (InterruptedException ie) {
+ // Ignore.
+ }
if (connectionID == null) {
throw new XMPPException("Connection failed. No response from server.");
}
@@ -229,7 +231,6 @@ class PacketReader {
* Process listeners.
*/
private void processListeners() {
- boolean processedPacket = false;
while (!done) {
synchronized (listeners) {
if (listeners.size() > 0) {
@@ -240,7 +241,7 @@ class PacketReader {
}
}
}
- processedPacket = false;
+ boolean processedPacket = false;
int size = listeners.size();
for (int i=0; i