View Javadoc

1   /*
2    * $Id: TransactionalQueueManager.java 7976 2007-08-21 14:26:13Z dirk.olmes $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSource, Inc.  All rights reserved.  http://www.mulesource.com
5    *
6    * The software in this package is published under the terms of the CPAL v1.0
7    * license, a copy of which has been included with this distribution in the
8    * LICENSE.txt file.
9    */
10  
11  package org.mule.util.queue;
12  
13  import org.mule.util.queue.QueuePersistenceStrategy.Holder;
14  import org.mule.util.xa.AbstractTransactionContext;
15  import org.mule.util.xa.AbstractXAResourceManager;
16  import org.mule.util.xa.ResourceManagerException;
17  import org.mule.util.xa.ResourceManagerSystemException;
18  
19  import java.io.IOException;
20  import java.util.ArrayList;
21  import java.util.HashMap;
22  import java.util.Iterator;
23  import java.util.LinkedList;
24  import java.util.List;
25  import java.util.Map;
26  
27  import javax.transaction.xa.XAResource;
28  
29  import org.apache.commons.logging.Log;
30  import org.apache.commons.logging.LogFactory;
31  
32  /**
33   * The Transactional Queue Manager is responsible for creating and Managing
34   * transactional Queues. Queues can also be persistent by setting a persistence
35   * strategy on the manager. Default straties are provided for Memory, Jounaling,
36   * Cache and File.
37   * 
38   * @author <a href="mailto:gnt@codehaus.org">Guillaume Nodet</a>
39   * @author <a href="mailto:ross.mason@symphonysoft.com">Ross Mason</a>
40   * @version $Revision: 7976 $
41   */
42  public class TransactionalQueueManager extends AbstractXAResourceManager implements QueueManager
43  {
44  
45      private static Log logger = LogFactory.getLog(TransactionalQueueManager.class);
46  
47      private Map queues = new HashMap();
48  
49      private QueuePersistenceStrategy memoryPersistenceStrategy = new MemoryPersistenceStrategy();
50      private QueuePersistenceStrategy persistenceStrategy;
51  
52      private QueueConfiguration defaultQueueConfiguration = new QueueConfiguration(false);
53  
54      public synchronized QueueSession getQueueSession()
55      {
56          return new TransactionalQueueSession(this, this);
57      }
58  
59      public synchronized void setDefaultQueueConfiguration(QueueConfiguration config)
60      {
61          this.defaultQueueConfiguration = config;
62      }
63  
64      public synchronized void setQueueConfiguration(String queueName, QueueConfiguration config)
65      {
66          getQueue(queueName).config = config;
67      }
68  
69      protected synchronized QueueInfo getQueue(String name)
70      {
71          QueueInfo q = (QueueInfo) queues.get(name);
72          if (q == null)
73          {
74              q = new QueueInfo();
75              q.name = name;
76              q.list = new LinkedList();
77              q.config = defaultQueueConfiguration;
78              queues.put(name, q);
79          }
80          return q;
81      }
82  
83      /*
84       * (non-Javadoc)
85       * 
86       * @see org.mule.transaction.xa.AbstractResourceManager#getLogger()
87       */
88      protected Log getLogger()
89      {
90          return logger;
91      }
92  
93      public void close()
94      {
95          try
96          {
97              stop(SHUTDOWN_MODE_NORMAL);
98          }
99          catch (ResourceManagerException e)
100         {
101             // TODO MULE-863: What should we really do?
102             logger.error("Error disposing manager", e);
103         }
104     }
105 
106     protected void doStart() throws ResourceManagerSystemException
107     {
108         if (persistenceStrategy != null)
109         {
110             try
111             {
112                 persistenceStrategy.open();
113             }
114             catch (IOException e)
115             {
116                 throw new ResourceManagerSystemException(e);
117             }
118         }
119     }
120 
121     protected boolean shutdown(int mode, long timeoutMSecs)
122     {
123         try
124         {
125             if (persistenceStrategy != null)
126             {
127                 persistenceStrategy.close();
128             }
129         }
130         catch (IOException e)
131         {
132             // TODO MULE-863: What should we really do?
133             logger.error("Error closing persistent store", e);
134         }
135         return super.shutdown(mode, timeoutMSecs);
136     }
137 
138     protected void recover() throws ResourceManagerSystemException
139     {
140         if (persistenceStrategy != null)
141         {
142             try
143             {
144                 List msgs = persistenceStrategy.restore();
145                 for (Iterator it = msgs.iterator(); it.hasNext();)
146                 {
147                     Holder h = (Holder) it.next();
148                     getQueue(h.getQueue()).putNow(h.getId());
149                 }
150             }
151             catch (Exception e)
152             {
153                 throw new ResourceManagerSystemException(e);
154             }
155         }
156     }
157 
158     /*
159      * (non-Javadoc)
160      * 
161      * @see org.mule.transaction.xa.AbstractResourceManager#createTransactionContext()
162      */
163     protected AbstractTransactionContext createTransactionContext(Object session)
164     {
165         return new QueueTransactionContext();
166     }
167 
168     /*
169      * (non-Javadoc)
170      * 
171      * @see org.mule.transaction.xa.AbstractResourceManager#doBegin(org.mule.transaction.xa.AbstractTransactionContext)
172      */
173     protected void doBegin(AbstractTransactionContext context)
174     {
175         // Nothing special to do
176     }
177 
178     /*
179      * (non-Javadoc)
180      * 
181      * @see org.mule.transaction.xa.AbstractResourceManager#doPrepare(org.mule.transaction.xa.AbstractTransactionContext)
182      */
183     protected int doPrepare(AbstractTransactionContext context)
184     {
185         return XAResource.XA_OK;
186     }
187 
188     /*
189      * (non-Javadoc)
190      * 
191      * @see org.mule.transaction.xa.AbstractResourceManager#doCommit(org.mule.transaction.xa.AbstractTransactionContext)
192      */
193     protected void doCommit(AbstractTransactionContext context) throws ResourceManagerException
194     {
195         QueueTransactionContext ctx = (QueueTransactionContext) context;
196         try
197         {
198             if (ctx.added != null)
199             {
200                 for (Iterator it = ctx.added.entrySet().iterator(); it.hasNext();)
201                 {
202                     Map.Entry entry = (Map.Entry) it.next();
203                     QueueInfo queue = (QueueInfo) entry.getKey();
204                     List queueAdded = (List) entry.getValue();
205                     if (queueAdded != null && queueAdded.size() > 0)
206                     {
207                         for (Iterator itAdded = queueAdded.iterator(); itAdded.hasNext();)
208                         {
209                             Object object = itAdded.next();
210                             Object id = doStore(queue, object);
211                             queue.putNow(id);
212                         }
213                     }
214                 }
215             }
216             if (ctx.removed != null)
217             {
218                 for (Iterator it = ctx.removed.entrySet().iterator(); it.hasNext();)
219                 {
220                     Map.Entry entry = (Map.Entry) it.next();
221                     QueueInfo queue = (QueueInfo) entry.getKey();
222                     List queueRemoved = (List) entry.getValue();
223                     if (queueRemoved != null && queueRemoved.size() > 0)
224                     {
225                         for (Iterator itRemoved = queueRemoved.iterator(); itRemoved.hasNext();)
226                         {
227                             Object id = itRemoved.next();
228                             doRemove(queue, id);
229                         }
230                     }
231                 }
232             }
233         }
234         catch (Exception e)
235         {
236             // throw new ResourceManagerException("Could not commit
237             // transaction", e);
238             // TODO: add an i18n Message
239             throw new ResourceManagerException(e);
240         }
241         finally
242         {
243             ctx.added = null;
244             ctx.removed = null;
245         }
246     }
247 
248     protected Object doStore(QueueInfo queue, Object object) throws IOException
249     {
250         QueuePersistenceStrategy ps = (queue.config.persistent)
251                         ? persistenceStrategy : memoryPersistenceStrategy;
252         Object id = ps.store(queue.name, object);
253         return id;
254     }
255 
256     protected void doRemove(QueueInfo queue, Object id) throws IOException
257     {
258         QueuePersistenceStrategy ps = (queue.config.persistent)
259                         ? persistenceStrategy : memoryPersistenceStrategy;
260         ps.remove(queue.name, id);
261     }
262 
263     protected Object doLoad(QueueInfo queue, Object id) throws IOException
264     {
265         QueuePersistenceStrategy ps = (queue.config.persistent)
266                         ? persistenceStrategy : memoryPersistenceStrategy;
267         Object obj = ps.load(queue.name, id);
268         return obj;
269     }
270 
271     /*
272      * (non-Javadoc)
273      * 
274      * @see org.mule.transaction.xa.AbstractResourceManager#doRollback(org.mule.transaction.xa.AbstractTransactionContext)
275      */
276     protected void doRollback(AbstractTransactionContext context) throws ResourceManagerException
277     {
278         QueueTransactionContext ctx = (QueueTransactionContext) context;
279         if (ctx.removed != null)
280         {
281             for (Iterator it = ctx.removed.entrySet().iterator(); it.hasNext();)
282             {
283                 Map.Entry entry = (Map.Entry) it.next();
284                 QueueInfo queue = (QueueInfo) entry.getKey();
285                 List queueRemoved = (List) entry.getValue();
286                 if (queueRemoved != null && queueRemoved.size() > 0)
287                 {
288                     for (Iterator itRemoved = queueRemoved.iterator(); itRemoved.hasNext();)
289                     {
290                         Object id = itRemoved.next();
291                         queue.putNow(id);
292                     }
293                 }
294             }
295         }
296         ctx.added = null;
297         ctx.removed = null;
298     }
299 
300     protected class QueueTransactionContext extends AbstractTransactionContext
301     {
302         protected Map added;
303         protected Map removed;
304 
305         public boolean offer(QueueInfo queue, Object item, long timeout) throws InterruptedException
306         {
307             readOnly = false;
308             if (added == null)
309             {
310                 added = new HashMap();
311             }
312             List queueAdded = (List) added.get(queue);
313             if (queueAdded == null)
314             {
315                 queueAdded = new ArrayList();
316                 added.put(queue, queueAdded);
317             }
318             // wait for enough room
319             if (queue.offer(null, queueAdded.size(), Long.MAX_VALUE))
320             {
321                 queueAdded.add(item);
322                 return true;
323             }
324             else
325             {
326                 return false;
327             }
328         }
329 
330         public Object poll(QueueInfo queue, long timeout) throws IOException, InterruptedException
331         {
332             readOnly = false;
333             if (added != null)
334             {
335                 List queueAdded = (List)added.get(queue);
336                 if (queueAdded != null)
337                 {
338                     return queueAdded.remove(queueAdded.size() - 1);
339                 }
340             }
341             Object o = queue.poll(Long.MAX_VALUE);
342             if (o != null)
343             {
344                 if (removed == null)
345                 {
346                     removed = new HashMap();
347                 }
348                 List queueRemoved = (List) removed.get(queue);
349                 if (queueRemoved == null)
350                 {
351                     queueRemoved = new ArrayList();
352                     removed.put(queue, queueRemoved);
353                 }
354                 queueRemoved.add(o);
355                 o = doLoad(queue, o);
356             }
357             return o;
358         }
359 
360         public Object peek(QueueInfo queue) throws IOException, InterruptedException
361         {
362             readOnly = false;
363             if (added != null)
364             {
365                 List queueAdded = (List) added.get(queue);
366                 if (queueAdded != null)
367                 {
368                     return queueAdded.get(queueAdded.size() - 1);
369                 }
370             }
371             Object o = queue.peek();
372             if (o != null)
373             {
374                 o = doLoad(queue, o);
375             }
376             return o;
377         }
378 
379         public int size(QueueInfo queue)
380         {
381             int sz = queue.list.size();
382             if (added != null)
383             {
384                 List queueAdded = (List) added.get(queue);
385                 if (queueAdded != null)
386                 {
387                     sz += queueAdded.size();
388                 }
389             }
390             return sz;
391         }
392 
393     }
394 
395     /**
396      * @return Returns the persistenceStrategy.
397      */
398     public QueuePersistenceStrategy getPersistenceStrategy()
399     {
400         return persistenceStrategy;
401     }
402 
403     /**
404      * @param persistenceStrategy The persistenceStrategy to set.
405      */
406     public void setPersistenceStrategy(QueuePersistenceStrategy persistenceStrategy)
407     {
408         if (operationMode != OPERATION_MODE_STOPPED)
409         {
410             throw new IllegalStateException();
411         }
412         this.persistenceStrategy = persistenceStrategy;
413     }
414 
415     public QueuePersistenceStrategy getMemoryPersistenceStrategy()
416     {
417         return memoryPersistenceStrategy;
418     }
419 
420     public void setMemoryPersistenceStrategy(QueuePersistenceStrategy memoryPersistenceStrategy)
421     {
422         if (operationMode != OPERATION_MODE_STOPPED)
423         {
424             throw new IllegalStateException();
425         }
426         this.memoryPersistenceStrategy = memoryPersistenceStrategy;
427     }
428 }