View Javadoc

1   /***
2    * Redistribution and use of this software and associated documentation
3    * ("Software"), with or without modification, are permitted provided
4    * that the following conditions are met:
5    *
6    * 1. Redistributions of source code must retain copyright
7    *    statements and notices.  Redistributions must also contain a
8    *    copy of this document.
9    *
10   * 2. Redistributions in binary form must reproduce the
11   *    above copyright notice, this list of conditions and the
12   *    following disclaimer in the documentation and/or other
13   *    materials provided with the distribution.
14   *
15   * 3. The name "Exolab" must not be used to endorse or promote
16   *    products derived from this Software without prior written
17   *    permission of Exoffice Technologies.  For written permission,
18   *    please contact info@exolab.org.
19   *
20   * 4. Products derived from this Software may not be called "Exolab"
21   *    nor may "Exolab" appear in their names without prior written
22   *    permission of Exoffice Technologies. Exolab is a registered
23   *    trademark of Exoffice Technologies.
24   *
25   * 5. Due credit should be given to the Exolab Project
26   *    (http://www.exolab.org/).
27   *
28   * THIS SOFTWARE IS PROVIDED BY EXOFFICE TECHNOLOGIES AND CONTRIBUTORS
29   * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
30   * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
31   * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
32   * EXOFFICE TECHNOLOGIES OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
33   * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
34   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
35   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
37   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
39   * OF THE POSSIBILITY OF SUCH DAMAGE.
40   *
41   * Copyright 2001-2003 (C) Exoffice Technologies Inc. All Rights Reserved.
42   *
43   * $Id: DefaultMessageCache.java,v 1.5 2007/01/24 12:00:28 tanderson Exp $
44   *
45   * Date         Author  Changes
46   * 3/1/2001     jima    Created
47   */
48  package org.exolab.jms.messagemgr;
49  
50  import org.apache.commons.logging.Log;
51  import org.apache.commons.logging.LogFactory;
52  import org.exolab.jms.message.MessageImpl;
53  import org.exolab.jms.persistence.DatabaseService;
54  import org.exolab.jms.persistence.PersistenceAdapter;
55  import org.exolab.jms.persistence.PersistenceException;
56  
57  import javax.jms.JMSException;
58  import java.sql.Connection;
59  import java.util.HashMap;
60  import java.util.Map;
61  
62  
63  /***
64   * Default implementation of the {@link MessageCache} interface.
65   *
66   * @author <a href="mailto:jima@comware.com.au">Jim Alateras</a>
67   * @author <a href="mailto:tma@netspace.net.au">Tim Anderson</a>
68   * @version $Revision: 1.5 $ $Date: 2007/01/24 12:00:28 $
69   */
70  final class DefaultMessageCache implements MessageCache {
71  
72      /***
73       * Maintains the pool of transient messages.
74       */
75      private final Map _transient = new HashMap(1023);
76  
77      /***
78       * Maintains the pool of persistent messages.
79       */
80      private final Map _persistent = new HashMap(1023);
81  
82      /***
83       * Maintains the references to messages.
84       */
85      private final Map _references = new HashMap(1023);
86  
87      /***
88       * The logger.
89       */
90      private static final Log _log = LogFactory.getLog(
91              DefaultMessageCache.class);
92  
93  
94      /***
95       * Add a reference and its corresponding message to the cache.
96       *
97       * @param reference the reference to the message
98       * @param message   the message
99       */
100     public synchronized void addMessage(MessageRef reference,
101                                         MessageImpl message) {
102         String messageId = reference.getMessageId();
103         if (reference.isPersistent()) {
104             _persistent.put(messageId, message);
105         } else {
106             _transient.put(messageId, message);
107         }
108         addMessageRef(messageId, reference);
109     }
110 
111     /***
112      * Adds a message reference to the cache.
113      *
114      * @param reference the message reference to add
115      */
116     public synchronized void addMessageRef(MessageRef reference) {
117         addMessageRef(reference.getMessageId(), reference);
118     }
119 
120     /***
121      * Returns a message reference, given its identifier.
122      *
123      * @param messageId the message identifier
124      * @return the message reference associated with <code>messageId</code>, or
125      *         <code>null</code>  if none exists
126      */
127     public synchronized MessageRef getMessageRef(String messageId) {
128         return (MessageRef) _references.get(messageId);
129     }
130 
131     /***
132      * Returns the message corresponding to the specified reference.
133      *
134      * @param reference the message reference
135      * @return the associated message, or <code>null</code> if none exists
136      * @throws JMSException for any error
137      */
138     public synchronized MessageImpl getMessage(MessageRef reference)
139             throws JMSException {
140         MessageImpl message;
141         final String messageId = reference.getMessageId();
142 
143         if (reference.isPersistent()) {
144             message = (MessageImpl) _persistent.get(messageId);
145 
146             // if the message is not cached then try and retrieve it from the
147             // database and cache it.
148             if (message == null) {
149                 // fault in at least the next message from the database
150                 try {
151                     DatabaseService service = DatabaseService.getInstance();
152                     PersistenceAdapter adapter = service.getAdapter();
153                     Connection connection = service.getConnection();
154                     message = adapter.getMessage(connection, messageId);
155                 } catch (PersistenceException exception) {
156                     final String msg = "Failed to retrieve message";
157                     _log.error(msg, exception);
158                     throw new JMSException(msg + ": " + exception.getMessage());
159                 }
160                 // add the message to the persistent cache once it has been
161                 // retrieved from the datastore
162                 if (message != null) {
163                     _persistent.put(messageId, message);
164                 }
165             }
166         } else {
167             message = (MessageImpl) _transient.get(messageId);
168         }
169 
170         if (message != null && !message.getReadOnly()) {
171             // mark the message as read-only
172             message.setReadOnly(true);
173         }
174 
175         return message;
176     }
177 
178     /***
179      * Destroys the message corresponding to the reference.
180      *
181      * @throws JMSException for any error
182      */
183     public synchronized void destroy(MessageRef reference) throws JMSException {
184         final String messageId = reference.getMessageId();
185         if (_references.remove(messageId) != null) {
186             if (reference.isPersistent()) {
187                 try {
188                     DatabaseService service = DatabaseService.getInstance();
189                     Connection connection = service.getConnection();
190                     PersistenceAdapter adapter = service.getAdapter();
191                     adapter.removeMessage(connection, messageId);
192                 } catch (Exception exception) {
193                     _log.error("Failed to remove message", exception);
194                     throw new JMSException("Failed to remove message: "
195                             + exception.getMessage());
196                 }
197                 _persistent.remove(messageId);
198             } else {
199                 _transient.remove(messageId);
200             }
201         }
202     }
203 
204     /***
205      * Clear the persistent and non-persistent message cache.
206      */
207     public synchronized void clear() {
208         _transient.clear();
209         _persistent.clear();
210         _references.clear();
211     }
212 
213     /***
214      * Clear only the persistent messages in the cache.
215      */
216     public synchronized void clearPersistentMessages() {
217         _persistent.clear();
218     }
219 
220     /***
221      * Return the number of messages in the transient cache.
222      *
223      * @return the number of messages in the transient cache
224      */
225     public synchronized int getTransientCount() {
226         return _transient.size();
227     }
228 
229     /***
230      * Return the number of messages in the persistent cache.
231      *
232      * @return the number of messages in the persistent cache
233      */
234     public synchronized int getPersistentCount() {
235         return _persistent.size();
236     }
237 
238     /***
239      * Return the number of message references in the cache.
240      *
241      * @return the number of message references in the cache
242      */
243     public synchronized int getMessageCount() {
244         return _references.size();
245     }
246 
247     /***
248      * Add a message reference to the cache.
249      *
250      * @param messageId the message identifier
251      * @param reference the message reference
252      */
253     private void addMessageRef(String messageId, MessageRef reference) {
254         _references.put(messageId, reference);
255     }
256 
257 }
258