View Javadoc

1   /*
2    * $Id: TransactionalQueueManager.java 11709 2008-05-09 02:16:54Z aguenther $
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  public class TransactionalQueueManager extends AbstractXAResourceManager implements QueueManager
39  {
40  
41      private static Log logger = LogFactory.getLog(TransactionalQueueManager.class);
42  
43      private Map queues = new HashMap();
44  
45      private QueuePersistenceStrategy memoryPersistenceStrategy = new MemoryPersistenceStrategy();
46      private QueuePersistenceStrategy persistenceStrategy;
47  
48      private QueueConfiguration defaultQueueConfiguration = new QueueConfiguration(false);
49      
50      public synchronized QueueSession getQueueSession()
51      {
52          return new TransactionalQueueSession(this, this);
53      }
54  
55      public synchronized void setDefaultQueueConfiguration(QueueConfiguration config)
56      {
57          this.defaultQueueConfiguration = config;
58      }
59  
60      public synchronized void setQueueConfiguration(String queueName, QueueConfiguration config)
61      {
62          getQueue(queueName).config = config;
63      }
64  
65      protected synchronized QueueInfo getQueue(String name)
66      {
67          QueueInfo q = (QueueInfo) queues.get(name);
68          if (q == null)
69          {
70              q = new QueueInfo();
71              q.name = name;
72              q.list = new LinkedList();
73              q.config = defaultQueueConfiguration;
74              queues.put(name, q);
75          }
76          return q;
77      }
78  
79      /*
80       * (non-Javadoc)
81       * 
82       * @see org.mule.transaction.xa.AbstractResourceManager#getLogger()
83       */
84      protected Log getLogger()
85      {
86          return logger;
87      }
88  
89      protected void doStart() throws ResourceManagerSystemException
90      {
91          if (persistenceStrategy != null)
92          {
93              try
94              {
95                  persistenceStrategy.open();
96              }
97              catch (IOException e)
98              {
99                  throw new ResourceManagerSystemException(e);
100             }
101         }
102     }
103 
104     protected boolean shutdown(int mode, long timeoutMSecs)
105     {
106         try
107         {
108             if (persistenceStrategy != null)
109             {
110                 persistenceStrategy.close();
111             }
112         }
113         catch (IOException e)
114         {
115             // TODO MULE-863: What should we really do?
116             logger.error("Error closing persistent store", e);
117         }
118         return super.shutdown(mode, timeoutMSecs);
119     }
120 
121     protected void recover() throws ResourceManagerSystemException
122     {
123         if (persistenceStrategy != null)
124         {
125             try
126             {
127                 List msgs = persistenceStrategy.restore();
128                 for (Iterator it = msgs.iterator(); it.hasNext();)
129                 {
130                     Holder h = (Holder) it.next();
131                     getQueue(h.getQueue()).putNow(h.getId());
132                 }
133             }
134             catch (Exception e)
135             {
136                 throw new ResourceManagerSystemException(e);
137             }
138         }
139     }
140 
141     /*
142      * (non-Javadoc)
143      * 
144      * @see org.mule.transaction.xa.AbstractResourceManager#createTransactionContext()
145      */
146     protected AbstractTransactionContext createTransactionContext(Object session)
147     {
148         return new QueueTransactionContext();
149     }
150 
151     /*
152      * (non-Javadoc)
153      * 
154      * @see org.mule.transaction.xa.AbstractResourceManager#doBegin(org.mule.transaction.xa.AbstractTransactionContext)
155      */
156     protected void doBegin(AbstractTransactionContext context)
157     {
158         // Nothing special to do
159     }
160 
161     /*
162      * (non-Javadoc)
163      * 
164      * @see org.mule.transaction.xa.AbstractResourceManager#doPrepare(org.mule.transaction.xa.AbstractTransactionContext)
165      */
166     protected int doPrepare(AbstractTransactionContext context)
167     {
168         return XAResource.XA_OK;
169     }
170 
171     /*
172      * (non-Javadoc)
173      * 
174      * @see org.mule.transaction.xa.AbstractResourceManager#doCommit(org.mule.transaction.xa.AbstractTransactionContext)
175      */
176     protected void doCommit(AbstractTransactionContext context) throws ResourceManagerException
177     {
178         QueueTransactionContext ctx = (QueueTransactionContext) context;
179         try
180         {
181             if (ctx.added != null)
182             {
183                 for (Iterator it = ctx.added.entrySet().iterator(); it.hasNext();)
184                 {
185                     Map.Entry entry = (Map.Entry) it.next();
186                     QueueInfo queue = (QueueInfo) entry.getKey();
187                     List queueAdded = (List) entry.getValue();
188                     if (queueAdded != null && queueAdded.size() > 0)
189                     {
190                         for (Iterator itAdded = queueAdded.iterator(); itAdded.hasNext();)
191                         {
192                             Object object = itAdded.next();
193                             Object id = doStore(queue, object);
194                             queue.putNow(id);
195                         }
196                     }
197                 }
198             }
199             if (ctx.removed != null)
200             {
201                 for (Iterator it = ctx.removed.entrySet().iterator(); it.hasNext();)
202                 {
203                     Map.Entry entry = (Map.Entry) it.next();
204                     QueueInfo queue = (QueueInfo) entry.getKey();
205                     List queueRemoved = (List) entry.getValue();
206                     if (queueRemoved != null && queueRemoved.size() > 0)
207                     {
208                         for (Iterator itRemoved = queueRemoved.iterator(); itRemoved.hasNext();)
209                         {
210                             Object id = itRemoved.next();
211                             doRemove(queue, id);
212                         }
213                     }
214                 }
215             }
216         }
217         catch (Exception e)
218         {
219             // throw new ResourceManagerException("Could not commit
220             // transaction", e);
221             // TODO: add an i18n Message
222             throw new ResourceManagerException(e);
223         }
224         finally
225         {
226             ctx.added = null;
227             ctx.removed = null;
228         }
229     }
230 
231     protected Object doStore(QueueInfo queue, Object object) throws IOException
232     {
233         QueuePersistenceStrategy ps = (queue.config.persistent)
234                         ? persistenceStrategy : memoryPersistenceStrategy;
235         Object id = ps.store(queue.name, object);
236         return id;
237     }
238 
239     protected void doRemove(QueueInfo queue, Object id) throws IOException
240     {
241         QueuePersistenceStrategy ps = (queue.config.persistent)
242                         ? persistenceStrategy : memoryPersistenceStrategy;
243         ps.remove(queue.name, id);
244     }
245 
246     protected Object doLoad(QueueInfo queue, Object id) throws IOException
247     {
248         QueuePersistenceStrategy ps = (queue.config.persistent)
249                         ? persistenceStrategy : memoryPersistenceStrategy;
250         Object obj = ps.load(queue.name, id);
251         return obj;
252     }
253 
254     /*
255      * (non-Javadoc)
256      * 
257      * @see org.mule.transaction.xa.AbstractResourceManager#doRollback(org.mule.transaction.xa.AbstractTransactionContext)
258      */
259     protected void doRollback(AbstractTransactionContext context) throws ResourceManagerException
260     {
261         QueueTransactionContext ctx = (QueueTransactionContext) context;
262         if (ctx.removed != null)
263         {
264             for (Iterator it = ctx.removed.entrySet().iterator(); it.hasNext();)
265             {
266                 Map.Entry entry = (Map.Entry) it.next();
267                 QueueInfo queue = (QueueInfo) entry.getKey();
268                 List queueRemoved = (List) entry.getValue();
269                 if (queueRemoved != null && queueRemoved.size() > 0)
270                 {
271                     for (Iterator itRemoved = queueRemoved.iterator(); itRemoved.hasNext();)
272                     {
273                         Object id = itRemoved.next();
274                         queue.putNow(id);
275                     }
276                 }
277             }
278         }
279         ctx.added = null;
280         ctx.removed = null;
281     }
282 
283     protected class QueueTransactionContext extends AbstractTransactionContext
284     {
285         protected Map added;
286         protected Map removed;
287 
288         public boolean offer(QueueInfo queue, Object item, long timeout) throws InterruptedException
289         {
290             readOnly = false;
291             if (added == null)
292             {
293                 added = new HashMap();
294             }
295             List queueAdded = (List) added.get(queue);
296             if (queueAdded == null)
297             {
298                 queueAdded = new ArrayList();
299                 added.put(queue, queueAdded);
300             }
301             // wait for enough room
302             if (queue.offer(null, queueAdded.size(), timeout))
303             {
304                 queueAdded.add(item);
305                 return true;
306             }
307             else
308             {
309                 return false;
310             }
311         }
312 
313         public Object poll(QueueInfo queue, long timeout) throws IOException, InterruptedException
314         {
315             readOnly = false;
316             if (added != null)
317             {
318                 List queueAdded = (List)added.get(queue);
319                 if (queueAdded != null)
320                 {
321                     return queueAdded.remove(queueAdded.size() - 1);
322                 }
323             }
324             Object o = queue.poll(timeout);
325             if (o != null)
326             {
327                 if (removed == null)
328                 {
329                     removed = new HashMap();
330                 }
331                 List queueRemoved = (List) removed.get(queue);
332                 if (queueRemoved == null)
333                 {
334                     queueRemoved = new ArrayList();
335                     removed.put(queue, queueRemoved);
336                 }
337                 queueRemoved.add(o);
338                 o = doLoad(queue, o);
339             }
340             return o;
341         }
342 
343         public Object peek(QueueInfo queue) throws IOException, InterruptedException
344         {
345             readOnly = false;
346             if (added != null)
347             {
348                 List queueAdded = (List) added.get(queue);
349                 if (queueAdded != null)
350                 {
351                     return queueAdded.get(queueAdded.size() - 1);
352                 }
353             }
354             Object o = queue.peek();
355             if (o != null)
356             {
357                 o = doLoad(queue, o);
358             }
359             return o;
360         }
361 
362         public int size(QueueInfo queue)
363         {
364             int sz = queue.list.size();
365             if (added != null)
366             {
367                 List queueAdded = (List) added.get(queue);
368                 if (queueAdded != null)
369                 {
370                     sz += queueAdded.size();
371                 }
372             }
373             return sz;
374         }
375 
376     }
377 
378     /**
379      * @return Returns the persistenceStrategy.
380      */
381     public QueuePersistenceStrategy getPersistenceStrategy()
382     {
383         return persistenceStrategy;
384     }
385 
386     /**
387      * @param persistenceStrategy The persistenceStrategy to set.
388      */
389     public void setPersistenceStrategy(QueuePersistenceStrategy persistenceStrategy)
390     {
391         if (operationMode != OPERATION_MODE_STOPPED)
392         {
393             throw new IllegalStateException();
394         }
395         this.persistenceStrategy = persistenceStrategy;
396     }
397 
398     public QueuePersistenceStrategy getMemoryPersistenceStrategy()
399     {
400         return memoryPersistenceStrategy;
401     }
402 
403     public void setMemoryPersistenceStrategy(QueuePersistenceStrategy memoryPersistenceStrategy)
404     {
405         if (operationMode != OPERATION_MODE_STOPPED)
406         {
407             throw new IllegalStateException();
408         }
409         this.memoryPersistenceStrategy = memoryPersistenceStrategy;
410     }
411 }