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