View Javadoc

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