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 occurring 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 chatMessage = message.asBuilder() 137 .to(participant) 138 .ofType(Message.Type.chat) 139 .setThread(threadID) 140 .build(); 141 chatManager.sendMessage(this, chatMessage); 142 } 143 144 /** 145 * Adds a stanza listener that will be notified of any new messages in the 146 * chat. 147 * 148 * @param listener a stanza listener. 149 */ 150 public void addMessageListener(ChatMessageListener listener) { 151 if (listener == null) { 152 return; 153 } 154 // TODO these references should be weak. 155 listeners.add(listener); 156 } 157 158 public void removeMessageListener(ChatMessageListener listener) { 159 listeners.remove(listener); 160 } 161 162 /** 163 * Closes the Chat and removes all references to it from the {@link ChatManager}. The chat will 164 * be unusable when this method returns, so it's recommend to drop all references to the 165 * instance right after calling {@link #close()}. 166 */ 167 public void close() { 168 chatManager.closeChat(this); 169 listeners.clear(); 170 } 171 172 /** 173 * Returns an unmodifiable set of all of the listeners registered with this chat. 174 * 175 * @return an unmodifiable set of all of the listeners registered with this chat. 176 */ 177 public Set<ChatMessageListener> getListeners() { 178 return Collections.unmodifiableSet(listeners); 179 } 180 181 /** 182 * Creates a {@link org.jivesoftware.smack.StanzaCollector} which will accumulate the Messages 183 * for this chat. Always cancel StanzaCollectors when finished with them as they will accumulate 184 * messages indefinitely. 185 * 186 * @return the StanzaCollector which returns Messages for this chat. 187 */ 188 public StanzaCollector createCollector() { 189 return chatManager.createStanzaCollector(this); 190 } 191 192 /** 193 * Delivers a message directly to this chat, which will add the message 194 * to the collector and deliver it to all listeners registered with the 195 * Chat. This is used by the XMPPConnection class to deliver messages 196 * without a thread ID. 197 * 198 * @param message the message. 199 */ 200 void deliver(Message message) { 201 // Because the collector and listeners are expecting a thread ID with 202 // a specific value, set the thread ID on the message even though it 203 // probably never had one. 204 Message chatMessage = message.asBuilder().setThread(threadID).build(); 205 206 for (ChatMessageListener listener : listeners) { 207 listener.processMessage(this, chatMessage); 208 } 209 } 210 211 @Override 212 public String toString() { 213 return "Chat [(participant=" + participant + "), (thread=" + threadID + ")]"; 214 } 215 216 @Override 217 public int hashCode() { 218 int hash = 1; 219 hash = hash * 31 + threadID.hashCode(); 220 hash = hash * 31 + participant.hashCode(); 221 return hash; 222 } 223 224 @Override 225 public boolean equals(Object obj) { 226 return obj instanceof Chat 227 && threadID.equals(((Chat) obj).getThreadID()) 228 && participant.equals(((Chat) obj).getParticipant()); 229 } 230}