KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jivesoftware > messenger > OfflineMessageStore


1 /**
2  * $RCSfile: OfflineMessageStore.java,v $
3  * $Revision: 1.13 $
4  * $Date: 2005/07/26 05:18:27 $
5  *
6  * Copyright (C) 2004 Jive Software. All rights reserved.
7  *
8  * This software is published under the terms of the GNU Public License (GPL),
9  * a copy of which is included in this distribution.
10  */

11
12 package org.jivesoftware.messenger;
13
14 import org.dom4j.Element;
15 import org.dom4j.io.SAXReader;
16 import org.jivesoftware.database.DbConnectionManager;
17 import org.jivesoftware.database.SequenceManager;
18 import org.jivesoftware.messenger.container.BasicModule;
19 import org.jivesoftware.util.*;
20 import org.xmpp.packet.Message;
21
22 import java.io.StringReader JavaDoc;
23 import java.sql.Connection JavaDoc;
24 import java.sql.PreparedStatement JavaDoc;
25 import java.sql.ResultSet JavaDoc;
26 import java.text.SimpleDateFormat JavaDoc;
27 import java.util.*;
28
29 /**
30  * Represents the user's offline message storage. A message store holds messages that were
31  * sent to the user while they were unavailable. The user can retrieve their messages by
32  * setting their presence to "available". The messages will then be delivered normally.
33  * Offline message storage is optional, in which case a null implementation is returned that
34  * always throws UnauthorizedException when adding messages to the store.
35  *
36  * @author Iain Shigeoka
37  */

38 public class OfflineMessageStore extends BasicModule {
39
40     private static final String JavaDoc INSERT_OFFLINE =
41         "INSERT INTO jiveOffline (username, messageID, creationDate, messageSize, message) " +
42         "VALUES (?, ?, ?, ?, ?)";
43     private static final String JavaDoc LOAD_OFFLINE =
44         "SELECT message, creationDate FROM jiveOffline WHERE username=?";
45     private static final String JavaDoc LOAD_OFFLINE_MESSAGE =
46         "SELECT message FROM jiveOffline WHERE username=? AND creationDate=?";
47     private static final String JavaDoc SELECT_SIZE_OFFLINE =
48         "SELECT SUM(messageSize) FROM jiveOffline WHERE username=?";
49     private static final String JavaDoc SELECT_SIZE_ALL_OFFLINE =
50         "SELECT SUM(messageSize) FROM jiveOffline";
51     private static final String JavaDoc DELETE_OFFLINE =
52         "DELETE FROM jiveOffline WHERE username=?";
53     private static final String JavaDoc DELETE_OFFLINE_MESSAGE =
54         "DELETE FROM jiveOffline WHERE username=? AND creationDate=?";
55
56     private Cache sizeCache;
57     private SimpleDateFormat JavaDoc dateFormat;
58
59     /**
60      * Returns the instance of <tt>OfflineMessageStore</tt> being used by the XMPPServer.
61      *
62      * @return the instance of <tt>OfflineMessageStore</tt> being used by the XMPPServer.
63      */

64     public static OfflineMessageStore getInstance() {
65         return XMPPServer.getInstance().getOfflineMessageStore();
66     }
67
68     private SAXReader saxReader = new SAXReader();
69
70     /**
71      * Constructs a new offline message store.
72      */

73     public OfflineMessageStore() {
74         super("Offline Message Store");
75         dateFormat = new SimpleDateFormat JavaDoc("yyyyMMdd'T'hh:mm:ss");
76         dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
77         sizeCache = new Cache("Offline Message Size Cache", 1024*100, JiveConstants.HOUR*12);
78     }
79
80     /**
81      * Adds a message to this message store. Messages will be stored and made
82      * available for later delivery.
83      *
84      * @param message the message to store.
85      */

86     public void addMessage(Message message) {
87         if (message == null) {
88             return;
89         }
90         String JavaDoc username = message.getTo().getNode();
91         // If the username is null (such as when an anonymous user), don't store.
92
if (username == null) {
93             return;
94         }
95         else if (!XMPPServer.getInstance().getServerInfo().getName().equals(message.getTo()
96                 .getDomain())) {
97             // Do not store messages sent to users of remote servers
98
return;
99         }
100
101         long messageID = SequenceManager.nextID(JiveConstants.OFFLINE);
102
103         // Get the message in XML format.
104
String JavaDoc msgXML = message.getElement().asXML();
105
106         Connection con = null;
107         PreparedStatement JavaDoc pstmt = null;
108         try {
109             con = DbConnectionManager.getConnection();
110             pstmt = con.prepareStatement(INSERT_OFFLINE);
111             pstmt.setString(1, username);
112             pstmt.setLong(2, messageID);
113             pstmt.setString(3, StringUtils.dateToMillis(new java.util.Date JavaDoc()));
114             pstmt.setInt(4, msgXML.length());
115             pstmt.setString(5, msgXML);
116             pstmt.executeUpdate();
117         }
118
119         catch (Exception JavaDoc e) {
120             Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
121         }
122         finally {
123             try { if (pstmt != null) { pstmt.close(); } }
124             catch (Exception JavaDoc e) { Log.error(e); }
125             try { if (con != null) { con.close(); } }
126             catch (Exception JavaDoc e) { Log.error(e); }
127         }
128
129         // Update the cached size if it exists.
130
if (sizeCache.containsKey(username)) {
131             int size = (Integer JavaDoc)sizeCache.get(username);
132             size += msgXML.length();
133             sizeCache.put(username, size);
134         }
135     }
136
137     /**
138      * Returns a Collection of all messages in the store for a user.
139      * Messages may be deleted after being selected from the database depending on
140      * the delete param.
141      *
142      * @param username the username of the user who's messages you'd like to receive.
143      * @param delete true if the offline messages should be deleted.
144      * @return An iterator of packets containing all offline messages.
145      */

146     public Collection<OfflineMessage> getMessages(String JavaDoc username, boolean delete) {
147         List<OfflineMessage> messages = new ArrayList<OfflineMessage>();
148         Connection con = null;
149         PreparedStatement JavaDoc pstmt = null;
150         try {
151             con = DbConnectionManager.getConnection();
152             pstmt = con.prepareStatement(LOAD_OFFLINE);
153             pstmt.setString(1, username);
154             ResultSet JavaDoc rs = pstmt.executeQuery();
155             while (rs.next()) {
156                 String JavaDoc msgXML = rs.getString(1);
157                 Date creationDate = new Date(Long.parseLong(rs.getString(2).trim()));
158                 OfflineMessage message = new OfflineMessage(creationDate,
159                         saxReader.read(new StringReader JavaDoc(msgXML)).getRootElement());
160                 // Add a delayed delivery (JEP-0091) element to the message.
161
Element delay = message.addChildElement("x", "jabber:x:delay");
162                 delay.addAttribute("from", XMPPServer.getInstance().getServerInfo().getName());
163                 synchronized (dateFormat) {
164                     delay.addAttribute("stamp", dateFormat.format(creationDate));
165                 }
166                 messages.add(message);
167             }
168             rs.close();
169             // Check if the offline messages loaded should be deleted
170
if (delete) {
171                 pstmt.close();
172
173                 pstmt = con.prepareStatement(DELETE_OFFLINE);
174                 pstmt.setString(1, username);
175                 pstmt.executeUpdate();
176             }
177         }
178         catch (Exception JavaDoc e) {
179             Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
180         }
181         finally {
182             try { if (pstmt != null) { pstmt.close(); } }
183             catch (Exception JavaDoc e) { Log.error(e); }
184             try { if (con != null) { con.close(); } }
185             catch (Exception JavaDoc e) { Log.error(e); }
186         }
187         return messages;
188     }
189
190     /**
191      * Returns the offline message of the specified user with the given creation date. The
192      * returned message will NOT be deleted from the database.
193      *
194      * @param username the username of the user who's message you'd like to receive.
195      * @param creationDate the date when the offline message was stored in the database.
196      * @return the offline message of the specified user with the given creation stamp.
197      */

198     public OfflineMessage getMessage(String JavaDoc username, Date creationDate) {
199         OfflineMessage message = null;
200         Connection con = null;
201         PreparedStatement JavaDoc pstmt = null;
202         try {
203             con = DbConnectionManager.getConnection();
204             pstmt = con.prepareStatement(LOAD_OFFLINE_MESSAGE);
205             pstmt.setString(1, username);
206             pstmt.setString(2, StringUtils.dateToMillis(creationDate));
207             ResultSet JavaDoc rs = pstmt.executeQuery();
208             while (rs.next()) {
209                 String JavaDoc msgXML = rs.getString(1);
210                 message =
211                         new OfflineMessage(creationDate,
212                                 saxReader.read(new StringReader JavaDoc(msgXML)).getRootElement());
213                 // Add a delayed delivery (JEP-0091) element to the message.
214
Element delay = message.addChildElement("x", "jabber:x:delay");
215                 delay.addAttribute("from", XMPPServer.getInstance().getServerInfo().getName());
216                 synchronized (dateFormat) {
217                     delay.addAttribute("stamp", dateFormat.format(creationDate));
218                 }
219             }
220             rs.close();
221         }
222         catch (Exception JavaDoc e) {
223             Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
224         }
225         finally {
226             try { if (pstmt != null) { pstmt.close(); } }
227             catch (Exception JavaDoc e) { Log.error(e); }
228             try { if (con != null) { con.close(); } }
229             catch (Exception JavaDoc e) { Log.error(e); }
230         }
231         return message;
232     }
233
234     /**
235      * Deletes all offline messages in the store for a user.
236      *
237      * @param username the username of the user who's messages are going to be deleted.
238      */

239     public void deleteMessages(String JavaDoc username) {
240         Connection con = null;
241         PreparedStatement JavaDoc pstmt = null;
242         try {
243             con = DbConnectionManager.getConnection();
244             pstmt = con.prepareStatement(DELETE_OFFLINE);
245             pstmt.setString(1, username);
246             pstmt.executeUpdate();
247         }
248         catch (Exception JavaDoc e) {
249             Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
250         }
251         finally {
252             try { if (pstmt != null) { pstmt.close(); } }
253             catch (Exception JavaDoc e) { Log.error(e); }
254             try { if (con != null) { con.close(); } }
255             catch (Exception JavaDoc e) { Log.error(e); }
256         }
257     }
258
259     /**
260      * Deletes the specified offline message in the store for a user. The way to identify the
261      * message to delete is based on the creationDate and username.
262      *
263      * @param username the username of the user who's message is going to be deleted.
264      * @param creationDate the date when the offline message was stored in the database.
265      */

266     public void deleteMessage(String JavaDoc username, Date creationDate) {
267         Connection con = null;
268         PreparedStatement JavaDoc pstmt = null;
269         try {
270             con = DbConnectionManager.getConnection();
271             pstmt = con.prepareStatement(DELETE_OFFLINE_MESSAGE);
272             pstmt.setString(1, username);
273             pstmt.setString(2, StringUtils.dateToMillis(creationDate));
274             pstmt.executeUpdate();
275         }
276         catch (Exception JavaDoc e) {
277             Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
278         }
279         finally {
280             try { if (pstmt != null) { pstmt.close(); } }
281             catch (Exception JavaDoc e) { Log.error(e); }
282             try { if (con != null) { con.close(); } }
283             catch (Exception JavaDoc e) { Log.error(e); }
284         }
285     }
286
287     /**
288      * Returns the approximate size (in bytes) of the XML messages stored for
289      * a particular user.
290      *
291      * @param username the username of the user.
292      * @return the approximate size of stored messages (in bytes).
293      */

294     public int getSize(String JavaDoc username) {
295         // See if the size is cached.
296
if (sizeCache.containsKey(username)) {
297             return (Integer JavaDoc)sizeCache.get(username);
298         }
299         int size = 0;
300         Connection con = null;
301         PreparedStatement JavaDoc pstmt = null;
302         try {
303             con = DbConnectionManager.getConnection();
304             pstmt = con.prepareStatement(SELECT_SIZE_OFFLINE);
305             pstmt.setString(1, username);
306             ResultSet JavaDoc rs = pstmt.executeQuery();
307             if (rs.next()) {
308                 size = rs.getInt(1);
309             }
310             rs.close();
311             // Add the value to cache.
312
sizeCache.put(username, size);
313         }
314         catch (Exception JavaDoc e) {
315             Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
316         }
317         finally {
318             try { if (pstmt != null) { pstmt.close(); } }
319             catch (Exception JavaDoc e) { Log.error(e); }
320             try { if (con != null) { con.close(); } }
321             catch (Exception JavaDoc e) { Log.error(e); }
322         }
323         return size;
324     }
325
326     /**
327      * Returns the approximate size (in bytes) of the XML messages stored for all
328      * users.
329      *
330      * @return the approximate size of all stored messages (in bytes).
331      */

332     public int getSize() {
333         int size = 0;
334         Connection con = null;
335         PreparedStatement JavaDoc pstmt = null;
336         try {
337             con = DbConnectionManager.getConnection();
338             pstmt = con.prepareStatement(SELECT_SIZE_ALL_OFFLINE);
339             ResultSet JavaDoc rs = pstmt.executeQuery();
340             if (rs.next()) {
341                 size = rs.getInt(1);
342             }
343             rs.close();
344         }
345         catch (Exception JavaDoc e) {
346             Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
347         }
348         finally {
349             try { if (pstmt != null) { pstmt.close(); } }
350             catch (Exception JavaDoc e) { Log.error(e); }
351             try { if (con != null) { con.close(); } }
352             catch (Exception JavaDoc e) { Log.error(e); }
353         }
354         return size;
355     }
356 }
Popular Tags