Chat.java

  1. /**
  2.  *
  3.  * Copyright 2003-2007 Jive Software.
  4.  *
  5.  * Licensed under the Apache License, Version 2.0 (the "License");
  6.  * you may not use this file except in compliance with the License.
  7.  * You may obtain a copy of the License at
  8.  *
  9.  *     http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */

  17. package org.jivesoftware.smack.chat;

  18. import org.jivesoftware.smack.PacketCollector;
  19. import org.jivesoftware.smack.SmackException.NotConnectedException;
  20. import org.jivesoftware.smack.packet.Message;
  21. import org.jivesoftware.smack.util.StringUtils;
  22. import org.jxmpp.jid.JidWithLocalpart;

  23. import java.util.Set;
  24. import java.util.Collections;
  25. import java.util.concurrent.CopyOnWriteArraySet;

  26. /**
  27.  * A chat is a series of messages sent between two users. Each chat has a unique
  28.  * thread ID, which is used to track which messages are part of a particular
  29.  * conversation. Some messages are sent without a thread ID, and some clients
  30.  * don't send thread IDs at all. Therefore, if a message without a thread ID
  31.  * arrives it is routed to the most recently created Chat with the message
  32.  * sender.
  33.  *
  34.  * @author Matt Tucker
  35.  */
  36. public class Chat {

  37.     private ChatManager chatManager;
  38.     private String threadID;
  39.     private JidWithLocalpart participant;
  40.     private final Set<ChatMessageListener> listeners = new CopyOnWriteArraySet<ChatMessageListener>();

  41.     /**
  42.      * Creates a new chat with the specified user and thread ID.
  43.      *
  44.      * @param chatManager the chatManager the chat will use.
  45.      * @param participant the user to chat with.
  46.      * @param threadID the thread ID to use.
  47.      */
  48.     Chat(ChatManager chatManager, JidWithLocalpart participant, String threadID) {
  49.         if (StringUtils.isEmpty(threadID)) {
  50.             throw new IllegalArgumentException("Thread ID must not be null");
  51.         }
  52.         this.chatManager = chatManager;
  53.         this.participant = participant;
  54.         this.threadID = threadID;
  55.     }

  56.     /**
  57.      * Returns the thread id associated with this chat, which corresponds to the
  58.      * <tt>thread</tt> field of XMPP messages. This method may return <tt>null</tt>
  59.      * if there is no thread ID is associated with this Chat.
  60.      *
  61.      * @return the thread ID of this chat.
  62.      */
  63.     public String getThreadID() {
  64.         return threadID;
  65.     }

  66.     /**
  67.      * Returns the name of the user the chat is with.
  68.      *
  69.      * @return the name of the user the chat is occuring with.
  70.      */
  71.     public JidWithLocalpart getParticipant() {
  72.         return participant;
  73.     }

  74.     /**
  75.      * Sends the specified text as a message to the other chat participant.
  76.      * This is a convenience method for:
  77.      *
  78.      * <pre>
  79.      *     Message message = chat.createMessage();
  80.      *     message.setBody(messageText);
  81.      *     chat.sendMessage(message);
  82.      * </pre>
  83.      *
  84.      * @param text the text to send.
  85.      * @throws NotConnectedException
  86.      * @throws InterruptedException
  87.      */
  88.     public void sendMessage(String text) throws NotConnectedException, InterruptedException {
  89.         Message message = new Message();
  90.         message.setBody(text);
  91.         sendMessage(message);
  92.     }

  93.     /**
  94.      * Sends a message to the other chat participant. The thread ID, recipient,
  95.      * and message type of the message will automatically set to those of this chat.
  96.      *
  97.      * @param message the message to send.
  98.      * @throws NotConnectedException
  99.      * @throws InterruptedException
  100.      */
  101.     public void sendMessage(Message message) throws NotConnectedException, InterruptedException {
  102.         // Force the recipient, message type, and thread ID since the user elected
  103.         // to send the message through this chat object.
  104.         message.setTo(participant);
  105.         message.setType(Message.Type.chat);
  106.         message.setThread(threadID);
  107.         chatManager.sendMessage(this, message);
  108.     }

  109.     /**
  110.      * Adds a packet listener that will be notified of any new messages in the
  111.      * chat.
  112.      *
  113.      * @param listener a packet listener.
  114.      */
  115.     public void addMessageListener(ChatMessageListener listener) {
  116.         if(listener == null) {
  117.             return;
  118.         }
  119.         // TODO these references should be weak.
  120.         listeners.add(listener);
  121.     }

  122.     public void removeMessageListener(ChatMessageListener listener) {
  123.         listeners.remove(listener);
  124.     }

  125.     /**
  126.      * Closes the Chat and removes all references to it from the {@link ChatManager}. The chat will
  127.      * be unusable when this method returns, so it's recommend to drop all references to the
  128.      * instance right after calling {@link #close()}.
  129.      */
  130.     public void close() {
  131.         chatManager.closeChat(this);
  132.         listeners.clear();
  133.     }

  134.     /**
  135.      * Returns an unmodifiable set of all of the listeners registered with this chat.
  136.      *
  137.      * @return an unmodifiable set of all of the listeners registered with this chat.
  138.      */
  139.     public Set<ChatMessageListener> getListeners() {
  140.         return Collections.unmodifiableSet(listeners);
  141.     }

  142.     /**
  143.      * Creates a {@link org.jivesoftware.smack.PacketCollector} which will accumulate the Messages
  144.      * for this chat. Always cancel PacketCollectors when finished with them as they will accumulate
  145.      * messages indefinitely.
  146.      *
  147.      * @return the PacketCollector which returns Messages for this chat.
  148.      */
  149.     public PacketCollector createCollector() {
  150.         return chatManager.createPacketCollector(this);
  151.     }

  152.     /**
  153.      * Delivers a message directly to this chat, which will add the message
  154.      * to the collector and deliver it to all listeners registered with the
  155.      * Chat. This is used by the XMPPConnection class to deliver messages
  156.      * without a thread ID.
  157.      *
  158.      * @param message the message.
  159.      */
  160.     void deliver(Message message) {
  161.         // Because the collector and listeners are expecting a thread ID with
  162.         // a specific value, set the thread ID on the message even though it
  163.         // probably never had one.
  164.         message.setThread(threadID);

  165.         for (ChatMessageListener listener : listeners) {
  166.             listener.processMessage(this, message);
  167.         }
  168.     }

  169.     @Override
  170.     public String toString() {
  171.         return "Chat [(participant=" + participant + "), (thread=" + threadID + ")]";
  172.     }
  173.    
  174.     @Override
  175.     public int hashCode() {
  176.         int hash = 1;
  177.         hash = hash * 31 + threadID.hashCode();
  178.         hash = hash * 31 + participant.hashCode();
  179.         return hash;
  180.     }
  181.    
  182.     @Override
  183.     public boolean equals(Object obj) {
  184.         return obj instanceof Chat
  185.                 && threadID.equals(((Chat)obj).getThreadID())
  186.                 && participant.equals(((Chat)obj).getParticipant());
  187.     }
  188. }