001/** 002 * 003 * Copyright 2003-2007 Jive Software. 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018package org.jivesoftware.smack.chat; 019 020import java.util.Collections; 021import java.util.Set; 022import java.util.concurrent.CopyOnWriteArraySet; 023 024import org.jivesoftware.smack.SmackException.NotConnectedException; 025import org.jivesoftware.smack.StanzaCollector; 026import org.jivesoftware.smack.packet.Message; 027import org.jivesoftware.smack.packet.MessageBuilder; 028import org.jivesoftware.smack.packet.StanzaBuilder; 029import org.jivesoftware.smack.util.StringUtils; 030 031import org.jxmpp.jid.EntityJid; 032 033/** 034 * A chat is a series of messages sent between two users. Each chat has a unique 035 * thread ID, which is used to track which messages are part of a particular 036 * conversation. Some messages are sent without a thread ID, and some clients 037 * don't send thread IDs at all. Therefore, if a message without a thread ID 038 * arrives it is routed to the most recently created Chat with the message 039 * sender. 040 * 041 * @author Matt Tucker 042 * @deprecated use <code>org.jivesoftware.smack.chat2.Chat</code> from <code>smack-extensions</code> instead. 043 */ 044@Deprecated 045public class Chat { 046 047 private final ChatManager chatManager; 048 private final String threadID; 049 private final EntityJid participant; 050 private final Set<ChatMessageListener> listeners = new CopyOnWriteArraySet<>(); 051 052 /** 053 * Creates a new chat with the specified user and thread ID. 054 * 055 * @param chatManager the chatManager the chat will use. 056 * @param participant the user to chat with. 057 * @param threadID the thread ID to use. 058 */ 059 Chat(ChatManager chatManager, EntityJid participant, String threadID) { 060 if (StringUtils.isEmpty(threadID)) { 061 throw new IllegalArgumentException("Thread ID must not be null"); 062 } 063 this.chatManager = chatManager; 064 this.participant = participant; 065 this.threadID = threadID; 066 } 067 068 /** 069 * Returns the thread id associated with this chat, which corresponds to the 070 * <code>thread</code> field of XMPP messages. This method may return <code>null</code> 071 * if there is no thread ID is associated with this Chat. 072 * 073 * @return the thread ID of this chat. 074 */ 075 public String getThreadID() { 076 return threadID; 077 } 078 079 /** 080 * Returns the name of the user the chat is with. 081 * 082 * @return the name of the user the chat is occuring with. 083 */ 084 public EntityJid getParticipant() { 085 return participant; 086 } 087 088 /** 089 * Sends the specified text as a message to the other chat participant. 090 * This is a convenience method for: 091 * 092 * <pre> 093 * Message message = chat.createMessage(); 094 * message.setBody(messageText); 095 * chat.sendMessage(message); 096 * </pre> 097 * 098 * @param text the text to send. 099 * @throws NotConnectedException if the XMPP connection is not connected. 100 * @throws InterruptedException if the calling thread was interrupted. 101 */ 102 public void sendMessage(String text) throws NotConnectedException, InterruptedException { 103 MessageBuilder message = StanzaBuilder.buildMessage() 104 .setBody(text); 105 sendMessage(message); 106 } 107 108 /** 109 * Sends a message to the other chat participant. The thread ID, recipient, 110 * and message type of the message will automatically set to those of this chat. 111 * 112 * @param message the message to send. 113 * @throws NotConnectedException if the XMPP connection is not connected. 114 * @throws InterruptedException if the calling thread was interrupted. 115 */ 116 public void sendMessage(MessageBuilder message) throws NotConnectedException, InterruptedException { 117 // Force the recipient, message type, and thread ID since the user elected 118 // to send the message through this chat object. 119 message.to(participant); 120 message.ofType(Message.Type.chat); 121 message.setThread(threadID); 122 chatManager.sendMessage(this, message.build()); 123 } 124 125 /** 126 * Sends a message to the other chat participant. The thread ID, recipient, 127 * and message type of the message will automatically set to those of this chat. 128 * 129 * @param message the message to send. 130 * @throws NotConnectedException if the XMPP connection is not connected. 131 * @throws InterruptedException if the calling thread was interrupted. 132 */ 133 public void sendMessage(Message message) throws NotConnectedException, InterruptedException { 134 // Force the recipient, message type, and thread ID since the user elected 135 // to send the message through this chat object. 136 message.setTo(participant); 137 message.setType(Message.Type.chat); 138 message.setThread(threadID); 139 chatManager.sendMessage(this, message); 140 } 141 142 /** 143 * Adds a stanza listener that will be notified of any new messages in the 144 * chat. 145 * 146 * @param listener a stanza listener. 147 */ 148 public void addMessageListener(ChatMessageListener listener) { 149 if (listener == null) { 150 return; 151 } 152 // TODO these references should be weak. 153 listeners.add(listener); 154 } 155 156 public void removeMessageListener(ChatMessageListener listener) { 157 listeners.remove(listener); 158 } 159 160 /** 161 * Closes the Chat and removes all references to it from the {@link ChatManager}. The chat will 162 * be unusable when this method returns, so it's recommend to drop all references to the 163 * instance right after calling {@link #close()}. 164 */ 165 public void close() { 166 chatManager.closeChat(this); 167 listeners.clear(); 168 } 169 170 /** 171 * Returns an unmodifiable set of all of the listeners registered with this chat. 172 * 173 * @return an unmodifiable set of all of the listeners registered with this chat. 174 */ 175 public Set<ChatMessageListener> getListeners() { 176 return Collections.unmodifiableSet(listeners); 177 } 178 179 /** 180 * Creates a {@link org.jivesoftware.smack.StanzaCollector} which will accumulate the Messages 181 * for this chat. Always cancel StanzaCollectors when finished with them as they will accumulate 182 * messages indefinitely. 183 * 184 * @return the StanzaCollector which returns Messages for this chat. 185 */ 186 public StanzaCollector createCollector() { 187 return chatManager.createStanzaCollector(this); 188 } 189 190 /** 191 * Delivers a message directly to this chat, which will add the message 192 * to the collector and deliver it to all listeners registered with the 193 * Chat. This is used by the XMPPConnection class to deliver messages 194 * without a thread ID. 195 * 196 * @param message the message. 197 */ 198 void deliver(Message message) { 199 // Because the collector and listeners are expecting a thread ID with 200 // a specific value, set the thread ID on the message even though it 201 // probably never had one. 202 message.setThread(threadID); 203 204 for (ChatMessageListener listener : listeners) { 205 listener.processMessage(this, message); 206 } 207 } 208 209 @Override 210 public String toString() { 211 return "Chat [(participant=" + participant + "), (thread=" + threadID + ")]"; 212 } 213 214 @Override 215 public int hashCode() { 216 int hash = 1; 217 hash = hash * 31 + threadID.hashCode(); 218 hash = hash * 31 + participant.hashCode(); 219 return hash; 220 } 221 222 @Override 223 public boolean equals(Object obj) { 224 return obj instanceof Chat 225 && threadID.equals(((Chat) obj).getThreadID()) 226 && participant.equals(((Chat) obj).getParticipant()); 227 } 228}