001/** 002 * 003 * Copyright 2003-2007 Jive Software. 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018package org.jivesoftware.smackx.offline; 019 020import org.jivesoftware.smack.PacketCollector; 021import org.jivesoftware.smack.SmackException.NoResponseException; 022import org.jivesoftware.smack.SmackException.NotConnectedException; 023import org.jivesoftware.smack.XMPPConnection; 024import org.jivesoftware.smack.XMPPException.XMPPErrorException; 025import org.jivesoftware.smack.filter.AndFilter; 026import org.jivesoftware.smack.filter.PacketExtensionFilter; 027import org.jivesoftware.smack.filter.PacketFilter; 028import org.jivesoftware.smack.filter.PacketTypeFilter; 029import org.jivesoftware.smack.packet.Message; 030import org.jivesoftware.smack.packet.Packet; 031import org.jivesoftware.smackx.disco.ServiceDiscoveryManager; 032import org.jivesoftware.smackx.disco.packet.DiscoverInfo; 033import org.jivesoftware.smackx.disco.packet.DiscoverItems; 034import org.jivesoftware.smackx.offline.packet.OfflineMessageInfo; 035import org.jivesoftware.smackx.offline.packet.OfflineMessageRequest; 036import org.jivesoftware.smackx.xdata.Form; 037 038import java.util.ArrayList; 039import java.util.List; 040 041/** 042 * The OfflineMessageManager helps manage offline messages even before the user has sent an 043 * available presence. When a user asks for his offline messages before sending an available 044 * presence then the server will not send a flood with all the offline messages when the user 045 * becomes online. The server will not send a flood with all the offline messages to the session 046 * that made the offline messages request or to any other session used by the user that becomes 047 * online.<p> 048 * 049 * Once the session that made the offline messages request has been closed and the user becomes 050 * offline in all the resources then the server will resume storing the messages offline and will 051 * send all the offline messages to the user when he becomes online. Therefore, the server will 052 * flood the user when he becomes online unless the user uses this class to manage his offline 053 * messages. 054 * 055 * @author Gaston Dombiak 056 */ 057public class OfflineMessageManager { 058 059 private final static String namespace = "http://jabber.org/protocol/offline"; 060 061 private XMPPConnection connection; 062 063 private PacketFilter packetFilter; 064 065 public OfflineMessageManager(XMPPConnection connection) { 066 this.connection = connection; 067 packetFilter = 068 new AndFilter(new PacketExtensionFilter("offline", namespace), 069 new PacketTypeFilter(Message.class)); 070 } 071 072 /** 073 * Returns true if the server supports Flexible Offline Message Retrieval. When the server 074 * supports Flexible Offline Message Retrieval it is possible to get the header of the offline 075 * messages, get specific messages, delete specific messages, etc. 076 * 077 * @return a boolean indicating if the server supports Flexible Offline Message Retrieval. 078 * @throws XMPPErrorException If the user is not allowed to make this request. 079 * @throws NoResponseException if there was no response from the server. 080 * @throws NotConnectedException 081 */ 082 public boolean supportsFlexibleRetrieval() throws NoResponseException, XMPPErrorException, NotConnectedException { 083 return ServiceDiscoveryManager.getInstanceFor(connection).supportsFeature(connection.getServiceName(), namespace); 084 } 085 086 /** 087 * Returns the number of offline messages for the user of the connection. 088 * 089 * @return the number of offline messages for the user of the connection. 090 * @throws XMPPErrorException If the user is not allowed to make this request or the server does 091 * not support offline message retrieval. 092 * @throws NoResponseException if there was no response from the server. 093 * @throws NotConnectedException 094 */ 095 public int getMessageCount() throws NoResponseException, XMPPErrorException, NotConnectedException { 096 DiscoverInfo info = ServiceDiscoveryManager.getInstanceFor(connection).discoverInfo(null, 097 namespace); 098 Form extendedInfo = Form.getFormFrom(info); 099 if (extendedInfo != null) { 100 String value = extendedInfo.getField("number_of_messages").getValues().get(0); 101 return Integer.parseInt(value); 102 } 103 return 0; 104 } 105 106 /** 107 * Returns a List of <tt>OfflineMessageHeader</tt> that keep information about the 108 * offline message. The OfflineMessageHeader includes a stamp that could be used to retrieve 109 * the complete message or delete the specific message. 110 * 111 * @return a List of <tt>OfflineMessageHeader</tt> that keep information about the offline 112 * message. 113 * @throws XMPPErrorException If the user is not allowed to make this request or the server does 114 * not support offline message retrieval. 115 * @throws NoResponseException if there was no response from the server. 116 * @throws NotConnectedException 117 */ 118 public List<OfflineMessageHeader> getHeaders() throws NoResponseException, XMPPErrorException, NotConnectedException { 119 List<OfflineMessageHeader> answer = new ArrayList<OfflineMessageHeader>(); 120 DiscoverItems items = ServiceDiscoveryManager.getInstanceFor(connection).discoverItems( 121 null, namespace); 122 for (DiscoverItems.Item item : items.getItems()) { 123 answer.add(new OfflineMessageHeader(item)); 124 } 125 return answer; 126 } 127 128 /** 129 * Returns a List of the offline <tt>Messages</tt> whose stamp matches the specified 130 * request. The request will include the list of stamps that uniquely identifies 131 * the offline messages to retrieve. The returned offline messages will not be deleted 132 * from the server. Use {@link #deleteMessages(java.util.List)} to delete the messages. 133 * 134 * @param nodes the list of stamps that uniquely identifies offline message. 135 * @return a List with the offline <tt>Messages</tt> that were received as part of 136 * this request. 137 * @throws XMPPErrorException If the user is not allowed to make this request or the server does 138 * not support offline message retrieval. 139 * @throws NoResponseException if there was no response from the server. 140 * @throws NotConnectedException 141 */ 142 public List<Message> getMessages(final List<String> nodes) throws NoResponseException, XMPPErrorException, NotConnectedException { 143 List<Message> messages = new ArrayList<Message>(); 144 OfflineMessageRequest request = new OfflineMessageRequest(); 145 for (String node : nodes) { 146 OfflineMessageRequest.Item item = new OfflineMessageRequest.Item(node); 147 item.setAction("view"); 148 request.addItem(item); 149 } 150 // Filter offline messages that were requested by this request 151 PacketFilter messageFilter = new AndFilter(packetFilter, new PacketFilter() { 152 public boolean accept(Packet packet) { 153 OfflineMessageInfo info = (OfflineMessageInfo) packet.getExtension("offline", 154 namespace); 155 return nodes.contains(info.getNode()); 156 } 157 }); 158 PacketCollector messageCollector = connection.createPacketCollector(messageFilter); 159 connection.createPacketCollectorAndSend(request).nextResultOrThrow(); 160 // Collect the received offline messages 161 Message message = (Message) messageCollector.nextResult(); 162 while (message != null) { 163 messages.add(message); 164 message = (Message) messageCollector.nextResult(); 165 } 166 // Stop queuing offline messages 167 messageCollector.cancel(); 168 return messages; 169 } 170 171 /** 172 * Returns an Iterator with all the offline <tt>Messages</tt> of the user. The returned offline 173 * messages will not be deleted from the server. Use {@link #deleteMessages(java.util.List)} 174 * to delete the messages. 175 * 176 * @return a List with all the offline <tt>Messages</tt> of the user. 177 * @throws XMPPErrorException If the user is not allowed to make this request or the server does 178 * not support offline message retrieval. 179 * @throws NoResponseException if there was no response from the server. 180 * @throws NotConnectedException 181 */ 182 public List<Message> getMessages() throws NoResponseException, XMPPErrorException, NotConnectedException { 183 List<Message> messages = new ArrayList<Message>(); 184 OfflineMessageRequest request = new OfflineMessageRequest(); 185 request.setFetch(true); 186 connection.createPacketCollectorAndSend(request).nextResultOrThrow(); 187 188 PacketCollector messageCollector = connection.createPacketCollector(packetFilter); 189 // Collect the received offline messages 190 Message message = (Message) messageCollector.nextResult(); 191 while (message != null) { 192 messages.add(message); 193 message = (Message) messageCollector.nextResult(); 194 } 195 // Stop queuing offline messages 196 messageCollector.cancel(); 197 return messages; 198 } 199 200 /** 201 * Deletes the specified list of offline messages. The request will include the list of 202 * stamps that uniquely identifies the offline messages to delete. 203 * 204 * @param nodes the list of stamps that uniquely identifies offline message. 205 * @throws XMPPErrorException If the user is not allowed to make this request or the server does 206 * not support offline message retrieval. 207 * @throws NoResponseException if there was no response from the server. 208 * @throws NotConnectedException 209 */ 210 public void deleteMessages(List<String> nodes) throws NoResponseException, XMPPErrorException, NotConnectedException { 211 OfflineMessageRequest request = new OfflineMessageRequest(); 212 for (String node : nodes) { 213 OfflineMessageRequest.Item item = new OfflineMessageRequest.Item(node); 214 item.setAction("remove"); 215 request.addItem(item); 216 } 217 connection.createPacketCollectorAndSend(request).nextResultOrThrow(); 218 } 219 220 /** 221 * Deletes all offline messages of the user. 222 * 223 * @throws XMPPErrorException If the user is not allowed to make this request or the server does 224 * not support offline message retrieval. 225 * @throws NoResponseException if there was no response from the server. 226 * @throws NotConnectedException 227 */ 228 public void deleteMessages() throws NoResponseException, XMPPErrorException, NotConnectedException { 229 OfflineMessageRequest request = new OfflineMessageRequest(); 230 request.setPurge(true); 231 connection.createPacketCollectorAndSend(request).nextResultOrThrow(); 232 } 233}