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