diff --git a/smack-core/src/main/java/org/jivesoftware/smack/Chat.java b/smack-core/src/main/java/org/jivesoftware/smack/Chat.java index 6ef28cd44..c1f1a07ef 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/Chat.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/Chat.java @@ -40,7 +40,7 @@ public class Chat { private ChatManager chatManager; private String threadID; private String participant; - private final Set listeners = new CopyOnWriteArraySet(); + private final Set listeners = new CopyOnWriteArraySet(); /** * Creates a new chat with the specified user and thread ID. @@ -118,7 +118,7 @@ public class Chat { * * @param listener a packet listener. */ - public void addMessageListener(MessageListener listener) { + public void addMessageListener(ChatMessageListener listener) { if(listener == null) { return; } @@ -126,7 +126,7 @@ public class Chat { listeners.add(listener); } - public void removeMessageListener(MessageListener listener) { + public void removeMessageListener(ChatMessageListener listener) { listeners.remove(listener); } @@ -145,7 +145,7 @@ public class Chat { * * @return an unmodifiable collection of all of the listeners registered with this chat. */ - public Collection getListeners() { + public Collection getListeners() { return Collections.unmodifiableCollection(listeners); } @@ -174,7 +174,7 @@ public class Chat { // probably never had one. message.setThread(threadID); - for (MessageListener listener : listeners) { + for (ChatMessageListener listener : listeners) { listener.processMessage(this, message); } } diff --git a/smack-core/src/main/java/org/jivesoftware/smack/ChatManager.java b/smack-core/src/main/java/org/jivesoftware/smack/ChatManager.java index 595d0eb83..825a2edc1 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/ChatManager.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/ChatManager.java @@ -206,7 +206,7 @@ public class ChatManager extends Manager{ * @param listener the listener which will listen for new messages from this chat. * @return the created chat. */ - public Chat createChat(String userJID, MessageListener listener) { + public Chat createChat(String userJID, ChatMessageListener listener) { return createChat(userJID, null, listener); } @@ -218,7 +218,7 @@ public class ChatManager extends Manager{ * @param listener the listener to add to the chat * @return the created chat. */ - public Chat createChat(String userJID, String thread, MessageListener listener) { + public Chat createChat(String userJID, String thread, ChatMessageListener listener) { if (thread == null) { thread = nextID(); } diff --git a/smack-core/src/main/java/org/jivesoftware/smack/ChatMessageListener.java b/smack-core/src/main/java/org/jivesoftware/smack/ChatMessageListener.java new file mode 100644 index 000000000..9fcdec355 --- /dev/null +++ b/smack-core/src/main/java/org/jivesoftware/smack/ChatMessageListener.java @@ -0,0 +1,27 @@ +/** + * + * Copyright 2003-2007 Jive Software. + * + * 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; + +import org.jivesoftware.smack.packet.Message; + +/** + * + */ +public interface ChatMessageListener { + void processMessage(Chat chat, Message message); +} diff --git a/smack-core/src/main/java/org/jivesoftware/smack/MessageListener.java b/smack-core/src/main/java/org/jivesoftware/smack/MessageListener.java index 709cffecc..3c66ddf53 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/MessageListener.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/MessageListener.java @@ -1,6 +1,6 @@ /** * - * Copyright 2003-2007 Jive Software. + * Copyright © 2014 Florian Schmaus * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,5 +23,5 @@ import org.jivesoftware.smack.packet.Message; * */ public interface MessageListener { - void processMessage(Chat chat, Message message); + void processMessage(Message message); } diff --git a/smack-core/src/main/java/org/jivesoftware/smack/PresenceListener.java b/smack-core/src/main/java/org/jivesoftware/smack/PresenceListener.java new file mode 100644 index 000000000..a2156d981 --- /dev/null +++ b/smack-core/src/main/java/org/jivesoftware/smack/PresenceListener.java @@ -0,0 +1,27 @@ +/** + * + * Copyright © 2014 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; + +import org.jivesoftware.smack.packet.Presence; + +/** + * + */ +public interface PresenceListener { + void processPresence(Presence presence); +} diff --git a/smack-core/src/main/java/org/jivesoftware/smack/filter/MessageWithSubjectFilter.java b/smack-core/src/main/java/org/jivesoftware/smack/filter/MessageWithSubjectFilter.java new file mode 100644 index 000000000..fa29ec497 --- /dev/null +++ b/smack-core/src/main/java/org/jivesoftware/smack/filter/MessageWithSubjectFilter.java @@ -0,0 +1,39 @@ +/** + * + * Copyright © 2014 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.filter; + +import org.jivesoftware.smack.packet.Message; + +/** + * Filters message stanzas which have at least one body + */ +public class MessageWithSubjectFilter extends FlexiblePacketTypeFilter { + + public static final PacketFilter INSTANCE = new MessageWithSubjectFilter(); + + private MessageWithSubjectFilter() { + super(Message.class); + } + + @Override + protected boolean acceptSpecific(Message message) { + // Accept only messages which have a subject set + return message.getSubject() != null; + } + +} diff --git a/smack-core/src/test/java/org/jivesoftware/smack/ChatConnectionTest.java b/smack-core/src/test/java/org/jivesoftware/smack/ChatConnectionTest.java index dd04dc1ed..e1f921540 100644 --- a/smack-core/src/test/java/org/jivesoftware/smack/ChatConnectionTest.java +++ b/smack-core/src/test/java/org/jivesoftware/smack/ChatConnectionTest.java @@ -386,7 +386,7 @@ public class ChatConnectionTest { class TestChatManagerListener implements ChatManagerListener { private Chat newChat; - private MessageListener listener; + private ChatMessageListener listener; public TestChatManagerListener(TestMessageListener msgListener) { listener = msgListener; @@ -423,7 +423,7 @@ public class ChatConnectionTest { } } - private class TestMessageListener implements MessageListener { + private class TestMessageListener implements ChatMessageListener { private Chat msgChat; private int counter = 0; diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/chatstates/ChatStateListener.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/chatstates/ChatStateListener.java index 65bf80924..856b769f1 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/chatstates/ChatStateListener.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/chatstates/ChatStateListener.java @@ -18,14 +18,14 @@ package org.jivesoftware.smackx.chatstates; import org.jivesoftware.smack.Chat; -import org.jivesoftware.smack.MessageListener; +import org.jivesoftware.smack.ChatMessageListener; /** * Events for when the state of a user in a chat changes. * * @author Alexander Wenckus */ -public interface ChatStateListener extends MessageListener { +public interface ChatStateListener extends ChatMessageListener { /** * Fired when the state of a chat with another user changes. diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/chatstates/ChatStateManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/chatstates/ChatStateManager.java index 1f6cabd35..ec5431c6b 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/chatstates/ChatStateManager.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/chatstates/ChatStateManager.java @@ -23,10 +23,10 @@ import java.util.WeakHashMap; import org.jivesoftware.smack.Chat; import org.jivesoftware.smack.ChatManager; import org.jivesoftware.smack.ChatManagerListener; +import org.jivesoftware.smack.ChatMessageListener; import org.jivesoftware.smack.SmackException.NotConnectedException; import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smack.Manager; -import org.jivesoftware.smack.MessageListener; import org.jivesoftware.smack.PacketInterceptor; import org.jivesoftware.smack.filter.NotFilter; import org.jivesoftware.smack.filter.PacketExtensionFilter; @@ -143,7 +143,7 @@ public class ChatStateManager extends Manager { } private void fireNewChatState(Chat chat, ChatState state) { - for (MessageListener listener : chat.getListeners()) { + for (ChatMessageListener listener : chat.getListeners()) { if (listener instanceof ChatStateListener) { ((ChatStateListener) listener).stateChanged(chat, state); } @@ -164,7 +164,7 @@ public class ChatStateManager extends Manager { } } - private class IncomingMessageInterceptor implements ChatManagerListener, MessageListener { + private class IncomingMessageInterceptor implements ChatManagerListener, ChatMessageListener { public void chatCreated(final Chat chat, boolean createdLocally) { chat.addMessageListener(this); diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/ConnectionDetachedPacketCollector.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/ConnectionDetachedPacketCollector.java index 4d5456056..16f0a182e 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/ConnectionDetachedPacketCollector.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/ConnectionDetachedPacketCollector.java @@ -31,8 +31,8 @@ import org.jivesoftware.smack.packet.Packet; * * @author Larry Kirschner */ -class ConnectionDetachedPacketCollector { - private ArrayBlockingQueue resultQueue; +class ConnectionDetachedPacketCollector

{ + private ArrayBlockingQueue

resultQueue; /** * Creates a new packet collector. If the packet filter is null, then @@ -47,7 +47,7 @@ class ConnectionDetachedPacketCollector { * all packets will match this collector. */ public ConnectionDetachedPacketCollector(int maxSize) { - this.resultQueue = new ArrayBlockingQueue(maxSize); + this.resultQueue = new ArrayBlockingQueue

(maxSize); } /** @@ -58,7 +58,7 @@ class ConnectionDetachedPacketCollector { * @return the next packet result, or null if there are no more * results. */ - public Packet pollResult() { + public P pollResult() { return resultQueue.poll(); } @@ -68,7 +68,7 @@ class ConnectionDetachedPacketCollector { * * @return the next available packet. */ - public Packet nextResult() { + public P nextResult() { try { return resultQueue.take(); } @@ -85,7 +85,7 @@ class ConnectionDetachedPacketCollector { * @param timeout the amount of time to wait for the next packet (in milleseconds). * @return the next available packet. */ - public Packet nextResult(long timeout) { + public P nextResult(long timeout) { try { return resultQueue.poll(timeout, TimeUnit.MILLISECONDS); } @@ -100,7 +100,7 @@ class ConnectionDetachedPacketCollector { * * @param packet the packet to process. */ - protected void processPacket(Packet packet) { + protected void processPacket(P packet) { if (packet == null) { return; } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChat.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChat.java index 2b6312607..e43c377d1 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChat.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChat.java @@ -35,12 +35,14 @@ import java.util.logging.Logger; import org.jivesoftware.smack.Chat; import org.jivesoftware.smack.ChatManager; +import org.jivesoftware.smack.ChatMessageListener; import org.jivesoftware.smack.ConnectionCreationListener; import org.jivesoftware.smack.Manager; import org.jivesoftware.smack.MessageListener; import org.jivesoftware.smack.PacketCollector; import org.jivesoftware.smack.PacketInterceptor; import org.jivesoftware.smack.PacketListener; +import org.jivesoftware.smack.PresenceListener; import org.jivesoftware.smack.SmackException; import org.jivesoftware.smack.SmackException.NoResponseException; import org.jivesoftware.smack.SmackException.NotConnectedException; @@ -107,13 +109,16 @@ public class MultiUserChat { new ArrayList(); private final List participantStatusListeners = new ArrayList(); + private final Set messageListeners = new CopyOnWriteArraySet(); + private final Set presenceListeners = new CopyOnWriteArraySet(); + private final PacketFilter fromRoomFilter; + private final PacketListener messageListener; + private final PacketListener presenceListener; - private PacketFilter presenceFilter; private List presenceInterceptors = new ArrayList(); - private PacketFilter messageFilter; private RoomListenerMultiplexor roomListenerMultiplexor; - private ConnectionDetachedPacketCollector messageCollector; - private List connectionListeners = new ArrayList(); + private ConnectionDetachedPacketCollector messageCollector; + static { XMPPConnectionRegistry.addConnectionCreationListener(new ConnectionCreationListener() { @@ -174,6 +179,27 @@ public class MultiUserChat { public MultiUserChat(XMPPConnection connection, String room) { this.connection = connection; this.room = room.toLowerCase(Locale.US); + + messageListener = new PacketListener() { + @Override + public void processPacket(Packet packet) throws NotConnectedException { + Message message = (Message) packet; + for (MessageListener listener : messageListeners) { + listener.processMessage(message); + } + } + }; + presenceListener = new PacketListener() { + @Override + public void processPacket(Packet packet) throws NotConnectedException { + Presence presence = (Presence) packet; + for (PresenceListener listener : presenceListeners) { + listener.processPresence(presence); + } + } + }; + fromRoomFilter = FromMatchesFilter.create(room); + init(); } @@ -349,6 +375,11 @@ public class MultiUserChat { this.nickname = nickname; joined = true; + // Setup the messageListeners and presenceListeners + connection.addPacketListener(messageListener, new AndFilter(fromRoomFilter, + MessageTypeFilter.GROUPCHAT)); + connection.addPacketListener(presenceListener, new AndFilter(fromRoomFilter, + PacketTypeFilter.PRESENCE)); // Update the list of joined rooms through this connection List rooms = joinedRooms.get(connection); if (rooms == null) { @@ -1499,22 +1530,22 @@ public class MultiUserChat { * * @param listener a packet listener that will be notified of any presence packets * sent to the group chat. + * @return true if the listener was not already added. */ - public void addParticipantListener(PacketListener listener) { - connection.addPacketListener(listener, presenceFilter); - connectionListeners.add(listener); + public boolean addParticipantListener(PresenceListener listener) { + return presenceListeners.add(listener); } /** - * Remoces a packet listener that was being notified of any new Presence packets + * Removes a packet listener that was being notified of any new Presence packets * sent to the group chat. * * @param listener a packet listener that was being notified of any presence packets * sent to the group chat. + * @return true if the listener was removed, otherwise the listener was not added previously. */ - public void removeParticipantListener(PacketListener listener) { - connection.removePacketListener(listener); - connectionListeners.remove(listener); + public boolean removeParticipantListener(PresenceListener listener) { + return presenceListeners.remove(listener); } /** @@ -1668,7 +1699,7 @@ public class MultiUserChat { * created chat. * @return new Chat for sending private messages to a given room occupant. */ - public Chat createPrivateChat(String occupant, MessageListener listener) { + public Chat createPrivateChat(String occupant, ChatMessageListener listener) { return ChatManager.getInstanceFor(connection).createChat(occupant, listener); } @@ -1704,7 +1735,7 @@ public class MultiUserChat { * null otherwise. */ public Message pollMessage() { - return (Message) messageCollector.pollResult(); + return messageCollector.pollResult(); } /** @@ -1714,7 +1745,7 @@ public class MultiUserChat { * @return the next message. */ public Message nextMessage() { - return (Message) messageCollector.nextResult(); + return messageCollector.nextResult(); } /** @@ -1727,7 +1758,7 @@ public class MultiUserChat { * message becoming available. */ public Message nextMessage(long timeout) { - return (Message) messageCollector.nextResult(timeout); + return messageCollector.nextResult(timeout); } /** @@ -1739,10 +1770,10 @@ public class MultiUserChat { * PacketListener. * * @param listener a packet listener. + * @return true if the listener was not already added. */ - public void addMessageListener(PacketListener listener) { - connection.addPacketListener(listener, messageFilter); - connectionListeners.add(listener); + public boolean addMessageListener(MessageListener listener) { + return messageListeners.add(listener); } /** @@ -1751,10 +1782,10 @@ public class MultiUserChat { * being delivered to the listener. * * @param listener a packet listener. + * @return true if the listener was removed, otherwise the listener was not added previously. */ - public void removeMessageListener(PacketListener listener) { - connection.removePacketListener(listener); - connectionListeners.remove(listener); + public boolean removeMessageListener(MessageListener listener) { + return messageListeners.remove(listener); } /** @@ -1798,6 +1829,8 @@ public class MultiUserChat { if (rooms == null) { return; } + connection.removePacketListener(messageListener); + connection.removePacketListener(presenceListener); rooms.remove(room); cleanup(); } @@ -1906,12 +1939,8 @@ public class MultiUserChat { } private void init() { - // Create filters - messageFilter = new AndFilter(FromMatchesFilter.create(room), MessageTypeFilter.GROUPCHAT); - presenceFilter = new AndFilter(FromMatchesFilter.create(room), PacketTypeFilter.PRESENCE); - // Create a collector for incoming messages. - messageCollector = new ConnectionDetachedPacketCollector(); + messageCollector = new ConnectionDetachedPacketCollector(); // Create a listener for subject updates. PacketListener subjectListener = new PacketListener() { @@ -2324,10 +2353,6 @@ public class MultiUserChat { try { if (connection != null) { roomListenerMultiplexor.removeRoom(room); - // Remove all the PacketListeners added to the connection by this chat - for (PacketListener connectionListener : connectionListeners) { - connection.removePacketListener(connectionListener); - } } } catch (Exception e) { // Do nothing diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/PacketMultiplexListener.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/PacketMultiplexListener.java index cc208cedb..b64915a19 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/PacketMultiplexListener.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/PacketMultiplexListener.java @@ -20,6 +20,7 @@ package org.jivesoftware.smackx.muc; import org.jivesoftware.smack.PacketListener; import org.jivesoftware.smack.SmackException.NotConnectedException; import org.jivesoftware.smack.filter.MessageTypeFilter; +import org.jivesoftware.smack.filter.MessageWithSubjectFilter; import org.jivesoftware.smack.filter.PacketExtensionFilter; import org.jivesoftware.smack.filter.PacketFilter; import org.jivesoftware.smack.filter.PacketTypeFilter; @@ -37,22 +38,16 @@ import org.jivesoftware.smackx.muc.packet.MUCUser; class PacketMultiplexListener implements PacketListener { private static final PacketFilter PRESENCE_FILTER = new PacketTypeFilter(Presence.class); - private static final PacketFilter SUBJECT_FILTER = new PacketFilter() { - public boolean accept(Packet packet) { - Message msg = (Message) packet; - return msg.getSubject() != null; - } - }; private static final PacketFilter DECLINES_FILTER = new PacketExtensionFilter(MUCUser.ELEMENT, MUCUser.NAMESPACE); - private ConnectionDetachedPacketCollector messageCollector; + private ConnectionDetachedPacketCollector messageCollector; private PacketListener presenceListener; private PacketListener subjectListener; private PacketListener declinesListener; public PacketMultiplexListener( - ConnectionDetachedPacketCollector messageCollector, + ConnectionDetachedPacketCollector messageCollector, PacketListener presenceListener, PacketListener subjectListener, PacketListener declinesListener) { if (messageCollector == null) { @@ -78,9 +73,9 @@ class PacketMultiplexListener implements PacketListener { presenceListener.processPacket(p); } else if (MessageTypeFilter.GROUPCHAT.accept(p)) { - messageCollector.processPacket(p); + messageCollector.processPacket((Message) p); - if (SUBJECT_FILTER.accept(p)) { + if (MessageWithSubjectFilter.INSTANCE.accept(p)) { subjectListener.processPacket(p); } } diff --git a/smack-extensions/src/test/java/org/jivesoftware/smackx/muc/ConnectionDetachedPacketCollectorTest.java b/smack-extensions/src/test/java/org/jivesoftware/smackx/muc/ConnectionDetachedPacketCollectorTest.java index 9f6a56ac0..61f05f22b 100644 --- a/smack-extensions/src/test/java/org/jivesoftware/smackx/muc/ConnectionDetachedPacketCollectorTest.java +++ b/smack-extensions/src/test/java/org/jivesoftware/smackx/muc/ConnectionDetachedPacketCollectorTest.java @@ -28,7 +28,7 @@ public class ConnectionDetachedPacketCollectorTest @Test public void verifyRollover() { - ConnectionDetachedPacketCollector collector = new ConnectionDetachedPacketCollector(5); + ConnectionDetachedPacketCollector collector = new ConnectionDetachedPacketCollector(5); for (int i=0; i<6; i++) { @@ -68,7 +68,7 @@ public class ConnectionDetachedPacketCollectorTest public void verifyThreadSafety() { int insertCount = 500; - final ConnectionDetachedPacketCollector collector = new ConnectionDetachedPacketCollector(insertCount); + final ConnectionDetachedPacketCollector collector = new ConnectionDetachedPacketCollector(insertCount); Thread consumer1 = new Thread(new Runnable() {