1
2
3
4
5
6
7
8
9
10
11 package org.mule.providers.jms.xa;
12
13 import java.lang.reflect.InvocationHandler;
14 import java.lang.reflect.InvocationTargetException;
15 import java.lang.reflect.Method;
16 import java.lang.reflect.Proxy;
17
18 import javax.jms.Connection;
19 import javax.jms.ConnectionFactory;
20 import javax.jms.JMSException;
21 import javax.jms.MessageConsumer;
22 import javax.jms.MessageProducer;
23 import javax.jms.QueueConnection;
24 import javax.jms.QueueConnectionFactory;
25 import javax.jms.QueueReceiver;
26 import javax.jms.QueueSender;
27 import javax.jms.QueueSession;
28 import javax.jms.Session;
29 import javax.jms.TopicConnection;
30 import javax.jms.TopicConnectionFactory;
31 import javax.jms.TopicPublisher;
32 import javax.jms.TopicSession;
33 import javax.jms.TopicSubscriber;
34 import javax.jms.XAConnection;
35 import javax.jms.XAConnectionFactory;
36 import javax.jms.XAQueueConnection;
37 import javax.jms.XAQueueConnectionFactory;
38 import javax.jms.XAQueueSession;
39 import javax.jms.XASession;
40 import javax.jms.XATopicConnection;
41 import javax.jms.XATopicConnectionFactory;
42 import javax.jms.XATopicSession;
43 import javax.transaction.Transaction;
44 import javax.transaction.TransactionManager;
45 import javax.transaction.xa.XAResource;
46
47 import org.apache.commons.logging.Log;
48 import org.apache.commons.logging.LogFactory;
49
50 public class ConnectionFactoryWrapper
51 implements ConnectionFactory, QueueConnectionFactory, TopicConnectionFactory
52 {
53
54
55
56 protected static final Log logger = LogFactory.getLog(ConnectionFactoryWrapper.class);
57
58 protected final Object factory;
59 protected final TransactionManager tm;
60
61 public ConnectionFactoryWrapper(Object factory, TransactionManager tm)
62 {
63 this.factory = factory;
64 this.tm = tm;
65 }
66
67
68
69
70
71
72 public Connection createConnection() throws JMSException
73 {
74 XAConnection xac = ((XAConnectionFactory)factory).createXAConnection();
75 Connection proxy = (Connection)Proxy.newProxyInstance(Connection.class.getClassLoader(),
76 new Class[]{Connection.class}, new ConnectionInvocationHandler(xac));
77 return proxy;
78 }
79
80
81
82
83
84
85
86 public Connection createConnection(String username, String password) throws JMSException
87 {
88 XAConnection xac = ((XAConnectionFactory)factory).createXAConnection(username, password);
89 Connection proxy = (Connection)Proxy.newProxyInstance(Connection.class.getClassLoader(),
90 new Class[]{Connection.class}, new ConnectionInvocationHandler(xac));
91 return proxy;
92 }
93
94
95
96
97
98
99 public QueueConnection createQueueConnection() throws JMSException
100 {
101 XAQueueConnection xaqc = ((XAQueueConnectionFactory)factory).createXAQueueConnection();
102 QueueConnection proxy = (QueueConnection)Proxy.newProxyInstance(Connection.class.getClassLoader(),
103 new Class[]{QueueConnection.class}, new ConnectionInvocationHandler(xaqc));
104 return proxy;
105 }
106
107
108
109
110
111
112
113 public QueueConnection createQueueConnection(String username, String password) throws JMSException
114 {
115 XAQueueConnection xaqc = ((XAQueueConnectionFactory)factory).createXAQueueConnection(username,
116 password);
117 QueueConnection proxy = (QueueConnection)Proxy.newProxyInstance(Connection.class.getClassLoader(),
118 new Class[]{QueueConnection.class}, new ConnectionInvocationHandler(xaqc));
119 return proxy;
120 }
121
122
123
124
125
126
127 public TopicConnection createTopicConnection() throws JMSException
128 {
129 XATopicConnection xatc = ((XATopicConnectionFactory)factory).createXATopicConnection();
130 TopicConnection proxy = (TopicConnection)Proxy.newProxyInstance(Connection.class.getClassLoader(),
131 new Class[]{TopicConnection.class}, new ConnectionInvocationHandler(xatc));
132 return proxy;
133 }
134
135
136
137
138
139
140
141 public TopicConnection createTopicConnection(String username, String password) throws JMSException
142 {
143 XATopicConnection xatc = ((XATopicConnectionFactory)factory).createXATopicConnection(username,
144 password);
145 TopicConnection proxy = (TopicConnection)Proxy.newProxyInstance(Connection.class.getClassLoader(),
146 new Class[]{TopicConnection.class}, new ConnectionInvocationHandler(xatc));
147 return proxy;
148 }
149
150 public class ConnectionInvocationHandler implements InvocationHandler
151 {
152
153 private Object xac;
154
155 public ConnectionInvocationHandler(Object xac)
156 {
157 this.xac = xac;
158 }
159
160
161
162
163
164
165 public Object getTargetObject()
166 {
167 return xac;
168 }
169
170
171
172
173
174
175
176 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
177 {
178 if (logger.isDebugEnabled())
179 {
180 logger.debug("Invoking " + method);
181 }
182 if (method.getName().equals("createSession"))
183 {
184 XASession xas = ((XAConnection)xac).createXASession();
185 return Proxy.newProxyInstance(Session.class.getClassLoader(), new Class[]{Session.class},
186 new SessionInvocationHandler(xas.getSession(), xas.getXAResource()));
187 }
188 else if (method.getName().equals("createQueueSession"))
189 {
190 XAQueueSession xaqs = ((XAQueueConnection)xac).createXAQueueSession();
191 return Proxy.newProxyInstance(Session.class.getClassLoader(),
192 new Class[]{QueueSession.class}, new SessionInvocationHandler(xaqs.getQueueSession(),
193 xaqs.getXAResource()));
194 }
195 else if (method.getName().equals("createTopicSession"))
196 {
197 XATopicSession xats = ((XATopicConnection)xac).createXATopicSession();
198 return Proxy.newProxyInstance(Session.class.getClassLoader(),
199 new Class[]{TopicSession.class}, new SessionInvocationHandler(xats.getTopicSession(),
200 xats.getXAResource()));
201 }
202 else
203 {
204 return method.invoke(xac, args);
205 }
206 }
207
208 protected class SessionInvocationHandler implements InvocationHandler
209 {
210
211 private Object session;
212 private Object xares;
213 private Transaction tx;
214
215 public SessionInvocationHandler(Object session, Object xares)
216 {
217 this.session = session;
218 this.xares = xares;
219 }
220
221
222
223
224
225
226
227 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
228 {
229 if (logger.isDebugEnabled())
230 {
231 logger.debug("Invoking " + method);
232 }
233 Object result = method.invoke(session, args);
234
235 if (result instanceof TopicSubscriber)
236 {
237 result = Proxy.newProxyInstance(Session.class.getClassLoader(),
238 new Class[]{TopicSubscriber.class}, new ConsumerProducerInvocationHandler(result));
239 }
240 else if (result instanceof QueueReceiver)
241 {
242 result = Proxy.newProxyInstance(Session.class.getClassLoader(),
243 new Class[]{QueueReceiver.class}, new ConsumerProducerInvocationHandler(result));
244 }
245 else if (result instanceof MessageConsumer)
246 {
247 result = Proxy.newProxyInstance(Session.class.getClassLoader(),
248 new Class[]{MessageConsumer.class}, new ConsumerProducerInvocationHandler(result));
249 }
250 else if (result instanceof TopicPublisher)
251 {
252 result = Proxy.newProxyInstance(Session.class.getClassLoader(),
253 new Class[]{TopicPublisher.class}, new ConsumerProducerInvocationHandler(result));
254 }
255 else if (result instanceof QueueSender)
256 {
257 result = Proxy.newProxyInstance(Session.class.getClassLoader(),
258 new Class[]{QueueSender.class}, new ConsumerProducerInvocationHandler(result));
259 }
260 else if (result instanceof MessageProducer)
261 {
262 result = Proxy.newProxyInstance(Session.class.getClassLoader(),
263 new Class[]{MessageProducer.class}, new ConsumerProducerInvocationHandler(result));
264 }
265 return result;
266 }
267
268 protected void enlist() throws Exception
269 {
270 if (logger.isDebugEnabled())
271 {
272 logger.debug("Enlistment request: " + this);
273 }
274 if (tx == null && tm != null)
275 {
276 tx = tm.getTransaction();
277 if (tx != null)
278 {
279 if (logger.isDebugEnabled())
280 {
281 logger.debug("Enlisting resource in xa transaction: " + xares);
282 }
283 XAResource xares = (XAResource)Proxy.newProxyInstance(XAResource.class
284 .getClassLoader(), new Class[]{XAResource.class},
285 new XAResourceInvocationHandler());
286 tx.enlistResource(xares);
287 }
288 }
289 }
290
291 protected class XAResourceInvocationHandler implements InvocationHandler
292 {
293
294
295
296
297
298
299
300 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
301 {
302 try
303 {
304 if (logger.isDebugEnabled())
305 {
306 logger.debug("Invoking " + method);
307 }
308 if (method.getName().equals("end"))
309 {
310 tx = null;
311 }
312
313
314
315
316
317
318
319
320
321
322
323
324 if (method.getName().equals("equals"))
325 {
326 if (Proxy.isProxyClass(args[0].getClass()))
327 {
328 return new Boolean(args[0].equals(this));
329 }
330 else
331 {
332 return new Boolean(this.equals(args[0]));
333 }
334 }
335
336 return method.invoke(xares, args);
337 }
338 catch (InvocationTargetException e)
339 {
340 throw e.getCause();
341 }
342 }
343
344 }
345
346 protected class ConsumerProducerInvocationHandler implements InvocationHandler
347 {
348
349 private Object target;
350
351 public ConsumerProducerInvocationHandler(Object target)
352 {
353 this.target = target;
354 }
355
356
357
358
359
360
361
362 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
363 {
364 if (logger.isDebugEnabled())
365 {
366 logger.debug("Invoking " + method);
367 }
368 if (!method.getName().equals("close"))
369 {
370 enlist();
371 }
372 return method.invoke(target, args);
373 }
374 }
375
376 }
377 }
378
379 }