Home | History | Annotate | Download | only in smackx
      1 /**
      2  * $RCSfile$
      3  * $Revision$
      4  * $Date$
      5  *
      6  * Copyright 2003-2007 Jive Software.
      7  *
      8  * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
      9  * you may not use this file except in compliance with the License.
     10  * You may obtain a copy of the License at
     11  *
     12  *     http://www.apache.org/licenses/LICENSE-2.0
     13  *
     14  * Unless required by applicable law or agreed to in writing, software
     15  * distributed under the License is distributed on an "AS IS" BASIS,
     16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     17  * See the License for the specific language governing permissions and
     18  * limitations under the License.
     19  */
     20 
     21 package org.jivesoftware.smackx;
     22 
     23 import java.lang.reflect.InvocationTargetException;
     24 import java.lang.reflect.Method;
     25 import java.util.ArrayList;
     26 import java.util.Iterator;
     27 import java.util.List;
     28 
     29 import org.jivesoftware.smack.PacketListener;
     30 import org.jivesoftware.smack.Connection;
     31 import org.jivesoftware.smack.filter.PacketExtensionFilter;
     32 import org.jivesoftware.smack.filter.PacketFilter;
     33 import org.jivesoftware.smack.packet.Message;
     34 import org.jivesoftware.smack.packet.Packet;
     35 import org.jivesoftware.smackx.packet.MessageEvent;
     36 
     37 /**
     38  * Manages message events requests and notifications. A MessageEventManager provides a high
     39  * level access to request for notifications and send event notifications. It also provides
     40  * an easy way to hook up custom logic when requests or notifications are received.
     41  *
     42  * @author Gaston Dombiak
     43  */
     44 public class MessageEventManager {
     45 
     46     private List<MessageEventNotificationListener> messageEventNotificationListeners = new ArrayList<MessageEventNotificationListener>();
     47     private List<MessageEventRequestListener> messageEventRequestListeners = new ArrayList<MessageEventRequestListener>();
     48 
     49     private Connection con;
     50 
     51     private PacketFilter packetFilter = new PacketExtensionFilter("x", "jabber:x:event");
     52     private PacketListener packetListener;
     53 
     54     /**
     55      * Creates a new message event manager.
     56      *
     57      * @param con a Connection to a XMPP server.
     58      */
     59     public MessageEventManager(Connection con) {
     60         this.con = con;
     61         init();
     62     }
     63 
     64     /**
     65      * Adds event notification requests to a message. For each event type that
     66      * the user wishes event notifications from the message recepient for, <tt>true</tt>
     67      * should be passed in to this method.
     68      *
     69      * @param message the message to add the requested notifications.
     70      * @param offline specifies if the offline event is requested.
     71      * @param delivered specifies if the delivered event is requested.
     72      * @param displayed specifies if the displayed event is requested.
     73      * @param composing specifies if the composing event is requested.
     74      */
     75     public static void addNotificationsRequests(Message message, boolean offline,
     76             boolean delivered, boolean displayed, boolean composing)
     77     {
     78         // Create a MessageEvent Package and add it to the message
     79         MessageEvent messageEvent = new MessageEvent();
     80         messageEvent.setOffline(offline);
     81         messageEvent.setDelivered(delivered);
     82         messageEvent.setDisplayed(displayed);
     83         messageEvent.setComposing(composing);
     84         message.addExtension(messageEvent);
     85     }
     86 
     87     /**
     88      * Adds a message event request listener. The listener will be fired anytime a request for
     89      * event notification is received.
     90      *
     91      * @param messageEventRequestListener a message event request listener.
     92      */
     93     public void addMessageEventRequestListener(MessageEventRequestListener messageEventRequestListener) {
     94         synchronized (messageEventRequestListeners) {
     95             if (!messageEventRequestListeners.contains(messageEventRequestListener)) {
     96                 messageEventRequestListeners.add(messageEventRequestListener);
     97             }
     98         }
     99     }
    100 
    101     /**
    102      * Removes a message event request listener. The listener will be fired anytime a request for
    103      * event notification is received.
    104      *
    105      * @param messageEventRequestListener a message event request listener.
    106      */
    107     public void removeMessageEventRequestListener(MessageEventRequestListener messageEventRequestListener) {
    108         synchronized (messageEventRequestListeners) {
    109             messageEventRequestListeners.remove(messageEventRequestListener);
    110         }
    111     }
    112 
    113     /**
    114      * Adds a message event notification listener. The listener will be fired anytime a notification
    115      * event is received.
    116      *
    117      * @param messageEventNotificationListener a message event notification listener.
    118      */
    119     public void addMessageEventNotificationListener(MessageEventNotificationListener messageEventNotificationListener) {
    120         synchronized (messageEventNotificationListeners) {
    121             if (!messageEventNotificationListeners.contains(messageEventNotificationListener)) {
    122                 messageEventNotificationListeners.add(messageEventNotificationListener);
    123             }
    124         }
    125     }
    126 
    127     /**
    128      * Removes a message event notification listener. The listener will be fired anytime a notification
    129      * event is received.
    130      *
    131      * @param messageEventNotificationListener a message event notification listener.
    132      */
    133     public void removeMessageEventNotificationListener(MessageEventNotificationListener messageEventNotificationListener) {
    134         synchronized (messageEventNotificationListeners) {
    135             messageEventNotificationListeners.remove(messageEventNotificationListener);
    136         }
    137     }
    138 
    139     /**
    140      * Fires message event request listeners.
    141      */
    142     private void fireMessageEventRequestListeners(
    143         String from,
    144         String packetID,
    145         String methodName) {
    146         MessageEventRequestListener[] listeners = null;
    147         Method method;
    148         synchronized (messageEventRequestListeners) {
    149             listeners = new MessageEventRequestListener[messageEventRequestListeners.size()];
    150             messageEventRequestListeners.toArray(listeners);
    151         }
    152         try {
    153             method =
    154                 MessageEventRequestListener.class.getDeclaredMethod(
    155                     methodName,
    156                     new Class[] { String.class, String.class, MessageEventManager.class });
    157             for (int i = 0; i < listeners.length; i++) {
    158                 method.invoke(listeners[i], new Object[] { from, packetID, this });
    159             }
    160         } catch (NoSuchMethodException e) {
    161             e.printStackTrace();
    162         } catch (InvocationTargetException e) {
    163             e.printStackTrace();
    164         } catch (IllegalAccessException e) {
    165             e.printStackTrace();
    166         }
    167     }
    168 
    169     /**
    170      * Fires message event notification listeners.
    171      */
    172     private void fireMessageEventNotificationListeners(
    173         String from,
    174         String packetID,
    175         String methodName) {
    176         MessageEventNotificationListener[] listeners = null;
    177         Method method;
    178         synchronized (messageEventNotificationListeners) {
    179             listeners =
    180                 new MessageEventNotificationListener[messageEventNotificationListeners.size()];
    181             messageEventNotificationListeners.toArray(listeners);
    182         }
    183         try {
    184             method =
    185                 MessageEventNotificationListener.class.getDeclaredMethod(
    186                     methodName,
    187                     new Class[] { String.class, String.class });
    188             for (int i = 0; i < listeners.length; i++) {
    189                 method.invoke(listeners[i], new Object[] { from, packetID });
    190             }
    191         } catch (NoSuchMethodException e) {
    192             e.printStackTrace();
    193         } catch (InvocationTargetException e) {
    194             e.printStackTrace();
    195         } catch (IllegalAccessException e) {
    196             e.printStackTrace();
    197         }
    198     }
    199 
    200     private void init() {
    201         // Listens for all message event packets and fire the proper message event listeners.
    202         packetListener = new PacketListener() {
    203             public void processPacket(Packet packet) {
    204                 Message message = (Message) packet;
    205                 MessageEvent messageEvent =
    206                     (MessageEvent) message.getExtension("x", "jabber:x:event");
    207                 if (messageEvent.isMessageEventRequest()) {
    208                     // Fire event for requests of message events
    209                     for (Iterator<String> it = messageEvent.getEventTypes(); it.hasNext();)
    210                         fireMessageEventRequestListeners(
    211                             message.getFrom(),
    212                             message.getPacketID(),
    213                             it.next().concat("NotificationRequested"));
    214                 } else
    215                     // Fire event for notifications of message events
    216                     for (Iterator<String> it = messageEvent.getEventTypes(); it.hasNext();)
    217                         fireMessageEventNotificationListeners(
    218                             message.getFrom(),
    219                             messageEvent.getPacketID(),
    220                             it.next().concat("Notification"));
    221 
    222             };
    223 
    224         };
    225         con.addPacketListener(packetListener, packetFilter);
    226     }
    227 
    228     /**
    229      * Sends the notification that the message was delivered to the sender of the original message
    230      *
    231      * @param to the recipient of the notification.
    232      * @param packetID the id of the message to send.
    233      */
    234     public void sendDeliveredNotification(String to, String packetID) {
    235         // Create the message to send
    236         Message msg = new Message(to);
    237         // Create a MessageEvent Package and add it to the message
    238         MessageEvent messageEvent = new MessageEvent();
    239         messageEvent.setDelivered(true);
    240         messageEvent.setPacketID(packetID);
    241         msg.addExtension(messageEvent);
    242         // Send the packet
    243         con.sendPacket(msg);
    244     }
    245 
    246     /**
    247      * Sends the notification that the message was displayed to the sender of the original message
    248      *
    249      * @param to the recipient of the notification.
    250      * @param packetID the id of the message to send.
    251      */
    252     public void sendDisplayedNotification(String to, String packetID) {
    253         // Create the message to send
    254         Message msg = new Message(to);
    255         // Create a MessageEvent Package and add it to the message
    256         MessageEvent messageEvent = new MessageEvent();
    257         messageEvent.setDisplayed(true);
    258         messageEvent.setPacketID(packetID);
    259         msg.addExtension(messageEvent);
    260         // Send the packet
    261         con.sendPacket(msg);
    262     }
    263 
    264     /**
    265      * Sends the notification that the receiver of the message is composing a reply
    266      *
    267      * @param to the recipient of the notification.
    268      * @param packetID the id of the message to send.
    269      */
    270     public void sendComposingNotification(String to, String packetID) {
    271         // Create the message to send
    272         Message msg = new Message(to);
    273         // Create a MessageEvent Package and add it to the message
    274         MessageEvent messageEvent = new MessageEvent();
    275         messageEvent.setComposing(true);
    276         messageEvent.setPacketID(packetID);
    277         msg.addExtension(messageEvent);
    278         // Send the packet
    279         con.sendPacket(msg);
    280     }
    281 
    282     /**
    283      * Sends the notification that the receiver of the message has cancelled composing a reply.
    284      *
    285      * @param to the recipient of the notification.
    286      * @param packetID the id of the message to send.
    287      */
    288     public void sendCancelledNotification(String to, String packetID) {
    289         // Create the message to send
    290         Message msg = new Message(to);
    291         // Create a MessageEvent Package and add it to the message
    292         MessageEvent messageEvent = new MessageEvent();
    293         messageEvent.setCancelled(true);
    294         messageEvent.setPacketID(packetID);
    295         msg.addExtension(messageEvent);
    296         // Send the packet
    297         con.sendPacket(msg);
    298     }
    299 
    300     public void destroy() {
    301         if (con != null) {
    302             con.removePacketListener(packetListener);
    303         }
    304     }
    305 
    306     protected void finalize() throws Throwable {
    307         destroy();
    308         super.finalize();
    309     }
    310 }