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