1d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/** 2d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * $RCSfile$ 3d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * $Revision$ 4d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * $Date$ 5d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 6d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Copyright 2003-2007 Jive Software. 7d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 8d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); 9d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * you may not use this file except in compliance with the License. 10d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * You may obtain a copy of the License at 11d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 12d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * http://www.apache.org/licenses/LICENSE-2.0 13d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 14d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Unless required by applicable law or agreed to in writing, software 15d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * distributed under the License is distributed on an "AS IS" BASIS, 16d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * See the License for the specific language governing permissions and 18d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * limitations under the License. 19d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 20d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 21d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpackage org.jivesoftware.smack; 22d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 23d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smack.packet.Message; 24d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 25d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.util.Set; 26d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.util.Collection; 27d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.util.Collections; 28d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.util.concurrent.CopyOnWriteArraySet; 29d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 30d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/** 31d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * A chat is a series of messages sent between two users. Each chat has a unique 32d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * thread ID, which is used to track which messages are part of a particular 33d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * conversation. Some messages are sent without a thread ID, and some clients 34d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * don't send thread IDs at all. Therefore, if a message without a thread ID 35d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * arrives it is routed to the most recently created Chat with the message 36d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * sender. 37d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 38d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @author Matt Tucker 39d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 40d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic class Chat { 41d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 42d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen private ChatManager chatManager; 43d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen private String threadID; 44d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen private String participant; 45d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen private final Set<MessageListener> listeners = new CopyOnWriteArraySet<MessageListener>(); 46d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 47d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /** 48d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Creates a new chat with the specified user and thread ID. 49d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 50d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @param chatManager the chatManager the chat will use. 51d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @param participant the user to chat with. 52d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @param threadID the thread ID to use. 53d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 54d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen Chat(ChatManager chatManager, String participant, String threadID) { 55d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen this.chatManager = chatManager; 56d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen this.participant = participant; 57d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen this.threadID = threadID; 58d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 59d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 60d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /** 61d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Returns the thread id associated with this chat, which corresponds to the 62d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * <tt>thread</tt> field of XMPP messages. This method may return <tt>null</tt> 63d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * if there is no thread ID is associated with this Chat. 64d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 65d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @return the thread ID of this chat. 66d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 67d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen public String getThreadID() { 68d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen return threadID; 69d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 70d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 71d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /** 72d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Returns the name of the user the chat is with. 73d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 74d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @return the name of the user the chat is occuring with. 75d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 76d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen public String getParticipant() { 77d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen return participant; 78d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 79d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 80d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /** 81d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Sends the specified text as a message to the other chat participant. 82d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * This is a convenience method for: 83d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 84d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * <pre> 85d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Message message = chat.createMessage(); 86d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * message.setBody(messageText); 87d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * chat.sendMessage(message); 88d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * </pre> 89d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 90d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @param text the text to send. 91d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @throws XMPPException if sending the message fails. 92d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 93d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen public void sendMessage(String text) throws XMPPException { 94d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen Message message = new Message(participant, Message.Type.chat); 95d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen message.setThread(threadID); 96d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen message.setBody(text); 97d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen chatManager.sendMessage(this, message); 98d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 99d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 100d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /** 101d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Sends a message to the other chat participant. The thread ID, recipient, 102d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * and message type of the message will automatically set to those of this chat. 103d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 104d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @param message the message to send. 105d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @throws XMPPException if an error occurs sending the message. 106d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 107d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen public void sendMessage(Message message) throws XMPPException { 108d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen // Force the recipient, message type, and thread ID since the user elected 109d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen // to send the message through this chat object. 110d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen message.setTo(participant); 111d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen message.setType(Message.Type.chat); 112d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen message.setThread(threadID); 113d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen chatManager.sendMessage(this, message); 114d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 115d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 116d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /** 117d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Adds a packet listener that will be notified of any new messages in the 118d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * chat. 119d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 120d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @param listener a packet listener. 121d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 122d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen public void addMessageListener(MessageListener listener) { 123d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen if(listener == null) { 124d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen return; 125d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 126d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen // TODO these references should be weak. 127d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen listeners.add(listener); 128d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 129d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 130d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen public void removeMessageListener(MessageListener listener) { 131d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen listeners.remove(listener); 132d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 133d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 134d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /** 135d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Returns an unmodifiable collection of all of the listeners registered with this chat. 136d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 137d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @return an unmodifiable collection of all of the listeners registered with this chat. 138d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 139d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen public Collection<MessageListener> getListeners() { 140d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen return Collections.unmodifiableCollection(listeners); 141d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 142d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 143d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /** 144d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Creates a {@link org.jivesoftware.smack.PacketCollector} which will accumulate the Messages 145d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * for this chat. Always cancel PacketCollectors when finished with them as they will accumulate 146d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * messages indefinitely. 147d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 148d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @return the PacketCollector which returns Messages for this chat. 149d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 150d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen public PacketCollector createCollector() { 151d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen return chatManager.createPacketCollector(this); 152d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 153d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 154d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /** 155d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Delivers a message directly to this chat, which will add the message 156d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * to the collector and deliver it to all listeners registered with the 157d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Chat. This is used by the Connection class to deliver messages 158d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * without a thread ID. 159d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 160d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @param message the message. 161d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 162d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen void deliver(Message message) { 163d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen // Because the collector and listeners are expecting a thread ID with 164d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen // a specific value, set the thread ID on the message even though it 165d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen // probably never had one. 166d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen message.setThread(threadID); 167d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 168d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen for (MessageListener listener : listeners) { 169d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen listener.processMessage(this, message); 170d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 171d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 172d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 173d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 174d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen @Override 175d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen public boolean equals(Object obj) { 176d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen return obj instanceof Chat 177d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen && threadID.equals(((Chat)obj).getThreadID()) 178d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen && participant.equals(((Chat)obj).getParticipant()); 179d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 180d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}