View Javadoc

1   /*
2    * $Id: TransactionalQueueManager.java 23211 2011-10-18 17:23:03Z mike.schilling $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.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.api.MuleContext;
14  import org.mule.api.context.MuleContextAware;
15  import org.mule.api.store.ListableObjectStore;
16  import org.mule.api.store.ObjectStore;
17  import org.mule.api.store.ObjectStoreException;
18  import org.mule.util.UUID;
19  import org.mule.util.xa.AbstractTransactionContext;
20  import org.mule.util.xa.AbstractXAResourceManager;
21  import org.mule.util.xa.ResourceManagerException;
22  import org.mule.util.xa.ResourceManagerSystemException;
23  
24  import java.io.Serializable;
25  import java.util.HashMap;
26  import java.util.HashSet;
27  import java.util.List;
28  import java.util.Map;
29  import java.util.Set;
30  
31  import javax.transaction.xa.XAResource;
32  
33  /**
34   * The Transactional Queue Manager is responsible for creating and Managing
35   * transactional Queues. Queues can also be persistent by setting a persistence
36   * strategy on the manager. Default straties are provided for Memory, Jounaling,
37   * Cache and File.
38   */
39  public class TransactionalQueueManager extends AbstractXAResourceManager implements QueueManager, MuleContextAware
40  {
41      private Map<String, QueueInfo> queues = new HashMap<String, QueueInfo>();
42  
43      private QueueConfiguration defaultQueueConfiguration;
44      private MuleContext muleContext;
45      private Set<ListableObjectStore> stores = new HashSet<ListableObjectStore>();
46  
47      @Override
48      public synchronized QueueSession getQueueSession()
49      {
50          return new TransactionalQueueSession(this, this);
51      }
52  
53      @Override
54      public synchronized void setDefaultQueueConfiguration(QueueConfiguration config)
55      {
56          this.defaultQueueConfiguration = config;
57          addStore(config.objectStore);
58      }
59  
60      @Override
61      public synchronized void setQueueConfiguration(String queueName, QueueConfiguration config)
62      {
63          getQueue(queueName).setConfig(config);
64          addStore(config.objectStore);
65      }
66  
67      protected synchronized QueueInfo getQueue(String name)
68      {
69          QueueInfo q = queues.get(name);
70          if (q == null)
71          {
72              q = new QueueInfo(name, muleContext, defaultQueueConfiguration);
73              queues.put(name, q);
74          }
75          return q;
76      }
77  
78      public synchronized QueueInfo getQueueInfo(String name)
79      {
80          QueueInfo q = queues.get(name);
81          return q == null ? q : new QueueInfo(q);
82      }
83  
84      @Override
85      protected void doStart() throws ResourceManagerSystemException
86      {
87          findAllStores();
88          for (ListableObjectStore store: stores)
89          {
90              try
91              {
92                  store.open();
93              }
94              catch (ObjectStoreException e)
95              {
96                  throw new ResourceManagerSystemException(e);
97              }
98          }
99      }
100 
101     @Override
102     protected boolean shutdown(int mode, long timeoutMSecs)
103     {
104         findAllStores();
105         for (ListableObjectStore store: stores)
106         {
107             try
108             {
109                 store.close();
110             }
111             catch (ObjectStoreException e)
112             {
113                 // TODO BL-405 what to do with this exception? Looking at the call graph of this method it seems that it's never called from any production code (i.e. when shutting down MuleContext)
114                 logger.error("Error closing persistent store", e);
115             }
116         }
117 
118         // Clear queues on shutdown to avoid duplicate entries on warm restarts (MULE-3678)
119         synchronized (this)
120         {
121             queues.clear();
122         }
123         return super.shutdown(mode, timeoutMSecs);
124     }
125 
126     @Override
127     protected void recover() throws ResourceManagerSystemException
128     {
129         findAllStores();
130         for (ListableObjectStore store: stores)
131         {
132             try
133             {
134                 List<Serializable> keys = store.allKeys();
135                 for (Serializable key : keys)
136                 {
137                     QueueKey queueKey = (QueueKey) key;
138                     getQueue(queueKey.queueName).putNow(queueKey.id);
139                 }
140             }
141             catch (Exception e)
142             {
143                 throw new ResourceManagerSystemException(e);
144             }
145         }
146     }
147 
148     @Override
149     protected AbstractTransactionContext createTransactionContext(Object session)
150     {
151         return new QueueTransactionContext(this);
152     }
153 
154     @Override
155     protected void doBegin(AbstractTransactionContext context)
156     {
157         // Nothing special to do
158     }
159 
160     @Override
161     protected int doPrepare(AbstractTransactionContext context)
162     {
163         return XAResource.XA_OK;
164     }
165 
166     @Override
167     protected void doCommit(AbstractTransactionContext context) throws ResourceManagerException
168     {
169         context.doCommit();
170     }
171 
172     protected Serializable doStore(QueueInfo queue, Serializable object) throws ObjectStoreException
173     {
174         ObjectStore<Serializable> store = queue.getStore();
175 
176         String id = muleContext == null ? UUID.getUUID() : muleContext.getUniqueIdString();
177         Serializable key = new QueueKey(queue.getName(), id);
178         store.store(key, object);
179         return id;
180     }
181 
182     protected void doRemove(QueueInfo queue, Serializable id) throws ObjectStoreException
183     {
184         ObjectStore<Serializable> store = queue.getStore();
185 
186         Serializable key = new QueueKey(queue.getName(), id);
187         store.remove(key);
188     }
189 
190     protected Serializable doLoad(QueueInfo queue, Serializable id) throws ObjectStoreException
191     {
192         ObjectStore<Serializable> store = queue.getStore();
193 
194         Serializable key = new QueueKey(queue.getName(), id);
195         return store.retrieve(key);
196     }
197 
198     @Override
199     protected void doRollback(AbstractTransactionContext context) throws ResourceManagerException
200     {
201         context.doRollback();
202     }
203 
204     protected synchronized void findAllStores()
205     {
206         if (muleContext != null)
207         {
208             for (ListableObjectStore store: muleContext.getRegistry().lookupByType(ListableObjectStore.class).values())
209             {
210                 addStore(store);
211             }
212         }
213     }
214 
215     @Override
216     public void setMuleContext(MuleContext context)
217     {
218         this.muleContext = context;
219     }
220 
221     public MuleContext getMuleContext()
222     {
223         return muleContext;
224     }
225 
226     private void addStore(ListableObjectStore<?> store)
227     {
228         stores.add(store);
229     }
230 }