View Javadoc

1   /*
2    * $Id: SessionInvocationHandler.java 12181 2008-06-26 20:05:55Z dirk.olmes $
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  package org.mule.transport.jms.xa;
11  
12  import org.mule.api.transaction.Transaction;
13  import org.mule.config.i18n.CoreMessages;
14  import org.mule.transaction.IllegalTransactionStateException;
15  import org.mule.transaction.TransactionCoordination;
16  import org.mule.transaction.XaTransaction;
17  
18  import java.lang.ref.Reference;
19  import java.lang.ref.WeakReference;
20  import java.lang.reflect.InvocationHandler;
21  import java.lang.reflect.Method;
22  import java.lang.reflect.Proxy;
23  
24  import javax.jms.JMSException;
25  import javax.jms.MessageConsumer;
26  import javax.jms.MessageProducer;
27  import javax.jms.QueueReceiver;
28  import javax.jms.QueueSender;
29  import javax.jms.Session;
30  import javax.jms.TopicPublisher;
31  import javax.jms.TopicSubscriber;
32  import javax.jms.XAQueueSession;
33  import javax.jms.XASession;
34  import javax.jms.XATopicSession;
35  import javax.transaction.xa.XAResource;
36  
37  import org.apache.commons.logging.Log;
38  import org.apache.commons.logging.LogFactory;
39  
40  public class SessionInvocationHandler implements InvocationHandler
41  {
42      protected static final transient Log logger = LogFactory.getLog(SessionInvocationHandler.class);
43  
44      private XASession xaSession;
45      private XAResource xaResource;
46      private volatile boolean enlisted = false;
47      private volatile boolean reuseObject = false;
48      private final Reference underlyingObject;
49      private static final Method SESSION_CLOSE_METHOD;
50  
51      static
52      {
53          try
54          {
55              SESSION_CLOSE_METHOD = Session.class.getMethod("close", (Class[])null);
56          }
57          catch (NoSuchMethodException e)
58          {
59              throw new RuntimeException(e);
60          }
61      }
62  
63      public SessionInvocationHandler(XASession xaSession) throws JMSException
64      {
65          this.xaSession = xaSession;
66          underlyingObject = new WeakReference(xaSession.getSession());
67          this.xaResource = new XAResourceWrapper(xaSession.getXAResource(), this);
68      }
69  
70      public SessionInvocationHandler(XAQueueSession xaSession) throws JMSException
71      {
72          this.xaSession = xaSession;
73          underlyingObject = new WeakReference(xaSession.getQueueSession());
74          this.xaResource = new XAResourceWrapper(xaSession.getXAResource(), this);
75      }
76  
77      public SessionInvocationHandler(XATopicSession xaSession) throws JMSException
78      {
79          this.xaSession = xaSession;
80          underlyingObject = new WeakReference(xaSession.getTopicSession());
81          this.xaResource = new XAResourceWrapper(xaSession.getXAResource(), this);
82      }
83  
84      public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
85      {
86          if (logger.isDebugEnabled())
87          {
88              logger.debug("Invoking " + method);
89          }
90          if (underlyingObject.get() == null)
91          {
92              throw new IllegalStateException("Underlying session is null, XASession " + xaSession);
93          }
94  
95          // processing method from MuleXaObject
96          if (XaTransaction.MuleXaObject.DELIST_METHOD_NAME.equals(method.getName()))
97          {
98              return Boolean.valueOf(delist());
99          }
100         else if (XaTransaction.MuleXaObject.ENLIST_METHOD_NAME.equals(method.getName()))
101         {
102             return Boolean.valueOf(enlist());
103         }
104         else if (XaTransaction.MuleXaObject.SET_REUSE_OBJECT_METHOD_NAME.equals(method.getName()))
105         {
106             reuseObject = ((Boolean) args[0]).booleanValue();
107             return null;
108         }
109         else if (XaTransaction.MuleXaObject.IS_REUSE_OBJECT_METHOD_NAME.equals(method.getName()))
110         {
111             return Boolean.valueOf(reuseObject);
112         }
113         else if (XaTransaction.MuleXaObject.GET_TARGET_OBJECT_METHOD_NAME.equals(method.getName()))
114         {
115             return getTargetObject();
116         }
117         else if (XaTransaction.MuleXaObject.CLOSE_METHOD_NAME.equals(method.getName()))
118         {
119             return SESSION_CLOSE_METHOD.invoke(underlyingObject.get(), args);
120         }
121         //close will be directly called on session object
122 
123         Object result = method.invoke(underlyingObject.get(), args);
124 
125         if (result instanceof TopicSubscriber)
126         {
127             result = Proxy.newProxyInstance(Session.class.getClassLoader(),
128                                             new Class[]{TopicSubscriber.class}, new ConsumerProducerInvocationHandler(this, result));
129         }
130         else if (result instanceof QueueReceiver)
131         {
132             result = Proxy.newProxyInstance(Session.class.getClassLoader(),
133                                             new Class[]{QueueReceiver.class}, new ConsumerProducerInvocationHandler(this, result));
134         }
135         else if (result instanceof MessageConsumer)
136         {
137             result = Proxy.newProxyInstance(Session.class.getClassLoader(),
138                                             new Class[]{MessageConsumer.class}, new ConsumerProducerInvocationHandler(this, result));
139         }
140         else if (result instanceof TopicPublisher)
141         {
142             result = Proxy.newProxyInstance(Session.class.getClassLoader(),
143                                             new Class[]{TopicPublisher.class}, new ConsumerProducerInvocationHandler(this, result));
144         }
145         else if (result instanceof QueueSender)
146         {
147             result = Proxy.newProxyInstance(Session.class.getClassLoader(),
148                                             new Class[]{QueueSender.class}, new ConsumerProducerInvocationHandler(this, result));
149         }
150         else if (result instanceof MessageProducer)
151         {
152             result = Proxy.newProxyInstance(Session.class.getClassLoader(),
153                                             new Class[]{MessageProducer.class}, new ConsumerProducerInvocationHandler(this, result));
154         }
155         return result;
156     }
157 
158     public boolean enlist() throws Exception
159     {
160         if (isEnlisted())
161         {
162             return false;
163         }
164 
165         if (logger.isDebugEnabled())
166         {
167             logger.debug("Enlistment request: " + this);
168         }
169 
170         Transaction transaction = TransactionCoordination.getInstance().getTransaction();
171         if (transaction == null)
172         {
173             throw new IllegalTransactionStateException(CoreMessages.noMuleTransactionAvailable());
174         }
175         if (!(transaction instanceof XaTransaction))
176         {
177             throw new IllegalTransactionStateException(CoreMessages.notMuleXaTransaction(transaction));
178         }
179 
180         if (!isEnlisted())
181         {
182             if (logger.isDebugEnabled())
183             {
184                 logger.debug("Enlisting resource " + xaResource + " in xa transaction " + transaction);
185             }
186 
187             enlisted = ((XaTransaction) transaction).enlistResource(xaResource);
188         }
189         
190         return enlisted;
191     }
192 
193     public boolean delist() throws Exception
194     {
195         if (!isEnlisted())
196         {
197             return false;
198         }
199 
200         if (logger.isDebugEnabled())
201         {
202             logger.debug("Delistment request: " + this);
203         }
204 
205         Transaction transaction = TransactionCoordination.getInstance().getTransaction();
206         if (transaction == null)
207         {
208             throw new IllegalTransactionStateException(CoreMessages.noMuleTransactionAvailable());
209         }
210         if (!(transaction instanceof XaTransaction))
211         {
212             throw new IllegalTransactionStateException(CoreMessages.notMuleXaTransaction(transaction));
213         }
214 
215         if (isEnlisted())
216         {
217             if (logger.isDebugEnabled())
218             {
219                 logger.debug("Delisting resource " + xaResource + " in xa transaction " + transaction);
220             }
221 
222             enlisted = !((XaTransaction) transaction).delistResource(xaResource, XAResource.TMSUCCESS);
223         }
224         return !isEnlisted();
225     }
226 
227     public boolean isEnlisted()
228     {
229         return enlisted;
230     }
231 
232     public void setEnlisted(boolean enlisted)
233     {
234         this.enlisted = enlisted;
235     }
236 
237     public XASession getTargetObject()
238     {
239         return xaSession;
240     }
241 
242     public XAResource getXAResource()
243     {
244         return xaResource;
245     }
246 
247 }