MessageEventManager.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.smackx.xevent;

  18. import java.lang.reflect.Method;
  19. import java.util.List;
  20. import java.util.Map;
  21. import java.util.WeakHashMap;
  22. import java.util.concurrent.CopyOnWriteArrayList;
  23. import java.util.logging.Level;
  24. import java.util.logging.Logger;

  25. import org.jivesoftware.smack.Manager;
  26. import org.jivesoftware.smack.StanzaListener;
  27. import org.jivesoftware.smack.SmackException.NotConnectedException;
  28. import org.jivesoftware.smack.XMPPConnection;
  29. import org.jivesoftware.smack.filter.AndFilter;
  30. import org.jivesoftware.smack.filter.MessageTypeFilter;
  31. import org.jivesoftware.smack.filter.NotFilter;
  32. import org.jivesoftware.smack.filter.StanzaExtensionFilter;
  33. import org.jivesoftware.smack.filter.StanzaFilter;
  34. import org.jivesoftware.smack.packet.Message;
  35. import org.jivesoftware.smack.packet.Stanza;
  36. import org.jivesoftware.smackx.xevent.packet.MessageEvent;
  37. import org.jxmpp.jid.Jid;

  38. /**
  39.  *
  40.  * Manages message events requests and notifications. A MessageEventManager provides a high
  41.  * level access to request for notifications and send event notifications. It also provides
  42.  * an easy way to hook up custom logic when requests or notifications are received.
  43.  *
  44.  * @author Gaston Dombiak
  45.  * @see <a href="http://xmpp.org/extensions/xep-0022.html">XEP-22: Message Events</a>
  46.  */
  47. public class MessageEventManager extends Manager {
  48.     private static final Logger LOGGER = Logger.getLogger(MessageEventManager.class.getName());
  49.    
  50.     private static final Map<XMPPConnection, MessageEventManager> INSTANCES = new WeakHashMap<>();

  51.     private static final StanzaFilter PACKET_FILTER = new AndFilter(new StanzaExtensionFilter(
  52.                     new MessageEvent()), new NotFilter(MessageTypeFilter.ERROR));

  53.     private List<MessageEventNotificationListener> messageEventNotificationListeners = new CopyOnWriteArrayList<MessageEventNotificationListener>();
  54.     private List<MessageEventRequestListener> messageEventRequestListeners = new CopyOnWriteArrayList<MessageEventRequestListener>();

  55.     public synchronized static MessageEventManager getInstanceFor(XMPPConnection connection) {
  56.         MessageEventManager messageEventManager = INSTANCES.get(connection);
  57.         if (messageEventManager == null) {
  58.             messageEventManager = new MessageEventManager(connection);
  59.             INSTANCES.put(connection, messageEventManager);
  60.         }
  61.         return messageEventManager;
  62.     }

  63.     /**
  64.      * Creates a new message event manager.
  65.      *
  66.      * @param con an XMPPConnection to a XMPP server.
  67.      */
  68.     private MessageEventManager(XMPPConnection connection) {
  69.         super(connection);
  70.         // Listens for all message event packets and fire the proper message event listeners.
  71.         connection.addAsyncStanzaListener(new StanzaListener() {
  72.             public void processPacket(Stanza packet) {
  73.                 Message message = (Message) packet;
  74.                 MessageEvent messageEvent =
  75.                     (MessageEvent) message.getExtension("x", "jabber:x:event");
  76.                 if (messageEvent.isMessageEventRequest()) {
  77.                     // Fire event for requests of message events
  78.                     for (String eventType : messageEvent.getEventTypes())
  79.                         fireMessageEventRequestListeners(
  80.                             message.getFrom(),
  81.                             message.getStanzaId(),
  82.                             eventType.concat("NotificationRequested"));
  83.                 } else
  84.                     // Fire event for notifications of message events
  85.                     for (String eventType : messageEvent.getEventTypes())
  86.                         fireMessageEventNotificationListeners(
  87.                             message.getFrom(),
  88.                             messageEvent.getStanzaId(),
  89.                             eventType.concat("Notification"));
  90.             }
  91.         }, PACKET_FILTER);
  92.     }

  93.     /**
  94.      * Adds event notification requests to a message. For each event type that
  95.      * the user wishes event notifications from the message recepient for, <tt>true</tt>
  96.      * should be passed in to this method.
  97.      *
  98.      * @param message the message to add the requested notifications.
  99.      * @param offline specifies if the offline event is requested.
  100.      * @param delivered specifies if the delivered event is requested.
  101.      * @param displayed specifies if the displayed event is requested.
  102.      * @param composing specifies if the composing event is requested.
  103.      */
  104.     public static void addNotificationsRequests(Message message, boolean offline,
  105.             boolean delivered, boolean displayed, boolean composing)
  106.     {
  107.         // Create a MessageEvent Package and add it to the message
  108.         MessageEvent messageEvent = new MessageEvent();
  109.         messageEvent.setOffline(offline);
  110.         messageEvent.setDelivered(delivered);
  111.         messageEvent.setDisplayed(displayed);
  112.         messageEvent.setComposing(composing);
  113.         message.addExtension(messageEvent);
  114.     }

  115.     /**
  116.      * Adds a message event request listener. The listener will be fired anytime a request for
  117.      * event notification is received.
  118.      *
  119.      * @param messageEventRequestListener a message event request listener.
  120.      */
  121.     public void addMessageEventRequestListener(MessageEventRequestListener messageEventRequestListener) {
  122.         messageEventRequestListeners.add(messageEventRequestListener);

  123.     }

  124.     /**
  125.      * Removes a message event request listener. The listener will be fired anytime a request for
  126.      * event notification is received.
  127.      *
  128.      * @param messageEventRequestListener a message event request listener.
  129.      */
  130.     public void removeMessageEventRequestListener(MessageEventRequestListener messageEventRequestListener) {
  131.         messageEventRequestListeners.remove(messageEventRequestListener);
  132.     }

  133.     /**
  134.      * Adds a message event notification listener. The listener will be fired anytime a notification
  135.      * event is received.
  136.      *
  137.      * @param messageEventNotificationListener a message event notification listener.
  138.      */
  139.     public void addMessageEventNotificationListener(MessageEventNotificationListener messageEventNotificationListener) {
  140.         messageEventNotificationListeners.add(messageEventNotificationListener);
  141.     }

  142.     /**
  143.      * Removes a message event notification listener. The listener will be fired anytime a notification
  144.      * event is received.
  145.      *
  146.      * @param messageEventNotificationListener a message event notification listener.
  147.      */
  148.     public void removeMessageEventNotificationListener(MessageEventNotificationListener messageEventNotificationListener) {
  149.         messageEventNotificationListeners.remove(messageEventNotificationListener);
  150.     }

  151.     /**
  152.      * Fires message event request listeners.
  153.      */
  154.     private void fireMessageEventRequestListeners(
  155.         Jid from,
  156.         String packetID,
  157.         String methodName) {
  158.         try {
  159.             Method method =
  160.                 MessageEventRequestListener.class.getDeclaredMethod(
  161.                     methodName,
  162.                     new Class[] { String.class, String.class, MessageEventManager.class });
  163.             for (MessageEventRequestListener listener : messageEventRequestListeners) {
  164.                 method.invoke(listener, new Object[] { from, packetID, this });
  165.             }
  166.         } catch (Exception e) {
  167.             LOGGER.log(Level.SEVERE, "Error while invoking MessageEventRequestListener", e);
  168.         }
  169.     }

  170.     /**
  171.      * Fires message event notification listeners.
  172.      */
  173.     private void fireMessageEventNotificationListeners(
  174.         Jid from,
  175.         String packetID,
  176.         String methodName) {
  177.         try {
  178.             Method method =
  179.                 MessageEventNotificationListener.class.getDeclaredMethod(
  180.                     methodName,
  181.                     new Class[] { String.class, String.class });
  182.             for (MessageEventNotificationListener listener : messageEventNotificationListeners) {
  183.                 method.invoke(listener, new Object[] { from, packetID });
  184.             }
  185.         } catch (Exception e) {
  186.             LOGGER.log(Level.SEVERE, "Error while invoking MessageEventNotificationListener", e);
  187.         }
  188.     }

  189.     /**
  190.      * Sends the notification that the message was delivered to the sender of the original message
  191.      *
  192.      * @param to the recipient of the notification.
  193.      * @param packetID the id of the message to send.
  194.      * @throws NotConnectedException
  195.      * @throws InterruptedException
  196.      */
  197.     public void sendDeliveredNotification(Jid to, String packetID) throws NotConnectedException, InterruptedException {
  198.         // Create the message to send
  199.         Message msg = new Message(to);
  200.         // Create a MessageEvent Package and add it to the message
  201.         MessageEvent messageEvent = new MessageEvent();
  202.         messageEvent.setDelivered(true);
  203.         messageEvent.setStanzaId(packetID);
  204.         msg.addExtension(messageEvent);
  205.         // Send the packet
  206.         connection().sendStanza(msg);
  207.     }

  208.     /**
  209.      * Sends the notification that the message was displayed to the sender of the original message
  210.      *
  211.      * @param to the recipient of the notification.
  212.      * @param packetID the id of the message to send.
  213.      * @throws NotConnectedException
  214.      * @throws InterruptedException
  215.      */
  216.     public void sendDisplayedNotification(Jid to, String packetID) throws NotConnectedException, InterruptedException {
  217.         // Create the message to send
  218.         Message msg = new Message(to);
  219.         // Create a MessageEvent Package and add it to the message
  220.         MessageEvent messageEvent = new MessageEvent();
  221.         messageEvent.setDisplayed(true);
  222.         messageEvent.setStanzaId(packetID);
  223.         msg.addExtension(messageEvent);
  224.         // Send the packet
  225.         connection().sendStanza(msg);
  226.     }

  227.     /**
  228.      * Sends the notification that the receiver of the message is composing a reply
  229.      *
  230.      * @param to the recipient of the notification.
  231.      * @param packetID the id of the message to send.
  232.      * @throws NotConnectedException
  233.      * @throws InterruptedException
  234.      */
  235.     public void sendComposingNotification(Jid to, String packetID) throws NotConnectedException, InterruptedException {
  236.         // Create the message to send
  237.         Message msg = new Message(to);
  238.         // Create a MessageEvent Package and add it to the message
  239.         MessageEvent messageEvent = new MessageEvent();
  240.         messageEvent.setComposing(true);
  241.         messageEvent.setStanzaId(packetID);
  242.         msg.addExtension(messageEvent);
  243.         // Send the packet
  244.         connection().sendStanza(msg);
  245.     }

  246.     /**
  247.      * Sends the notification that the receiver of the message has cancelled composing a reply.
  248.      *
  249.      * @param to the recipient of the notification.
  250.      * @param packetID the id of the message to send.
  251.      * @throws NotConnectedException
  252.      * @throws InterruptedException
  253.      */
  254.     public void sendCancelledNotification(Jid to, String packetID) throws NotConnectedException, InterruptedException {
  255.         // Create the message to send
  256.         Message msg = new Message(to);
  257.         // Create a MessageEvent Package and add it to the message
  258.         MessageEvent messageEvent = new MessageEvent();
  259.         messageEvent.setCancelled(true);
  260.         messageEvent.setStanzaId(packetID);
  261.         msg.addExtension(messageEvent);
  262.         // Send the packet
  263.         connection().sendStanza(msg);
  264.     }
  265. }