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 }