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