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}