View Javadoc
1   /*
2    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
3    * The software in this package is published under the terms of the CPAL v1.0
4    * license, a copy of which has been included with this distribution in the
5    * LICENSE.txt file.
6    */
7   package org.mule.transport.jms.xa;
8   
9   import org.mule.api.transaction.Transaction;
10  import org.mule.config.i18n.CoreMessages;
11  import org.mule.transaction.IllegalTransactionStateException;
12  import org.mule.transaction.TransactionCoordination;
13  import org.mule.transaction.XaTransaction;
14  
15  import java.lang.reflect.Method;
16  import java.lang.reflect.Proxy;
17  
18  import javax.jms.JMSException;
19  import javax.jms.MessageConsumer;
20  import javax.jms.MessageProducer;
21  import javax.jms.QueueReceiver;
22  import javax.jms.QueueSender;
23  import javax.jms.Session;
24  import javax.jms.TopicPublisher;
25  import javax.jms.TopicSubscriber;
26  import javax.jms.XAQueueSession;
27  import javax.jms.XASession;
28  import javax.jms.XATopicSession;
29  import javax.transaction.xa.XAResource;
30  
31  import org.apache.commons.logging.Log;
32  import org.apache.commons.logging.LogFactory;
33  
34  public class SessionInvocationHandler implements TargetInvocationHandler
35  {
36      protected static final transient Log logger = LogFactory.getLog(SessionInvocationHandler.class);
37  
38      private XASession xaSession;
39      private XAResource xaResource;
40      private volatile boolean enlisted = false;
41      private volatile boolean reuseObject = false;
42      private final Session session;
43  
44      private SessionInvocationHandler(XASession xaSession, Session session, Boolean sameRMOverrideValue)
45      {
46          super();
47          this.xaSession = xaSession;
48          this.session = session;
49          this.xaResource = new XAResourceWrapper(xaSession.getXAResource(), this, sameRMOverrideValue);
50      }
51      
52      public SessionInvocationHandler(XASession xaSession, Boolean sameRMOverrideValue) throws JMSException
53      {
54          this(xaSession, xaSession.getSession(), sameRMOverrideValue);
55      }
56  
57      public SessionInvocationHandler(XAQueueSession xaSession, Boolean sameRMOverrideValue) throws JMSException
58      {
59          this(xaSession, xaSession.getQueueSession(), sameRMOverrideValue);
60      }
61  
62      public SessionInvocationHandler(XATopicSession xaSession, Boolean sameRMOverrideValue) throws JMSException
63      {
64          this(xaSession, xaSession.getTopicSession(), sameRMOverrideValue);
65      }
66  
67      public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
68      {
69          if (logger.isDebugEnabled())
70          {
71              logger.debug(this + " Invoking " + method);
72          }
73  
74          // processing method from MuleXaObject
75          if (XaTransaction.MuleXaObject.DELIST_METHOD_NAME.equals(method.getName()))
76          {
77              return delist();
78          }
79          else if (XaTransaction.MuleXaObject.ENLIST_METHOD_NAME.equals(method.getName()))
80          {
81              return enlist();
82          }
83          else if (XaTransaction.MuleXaObject.SET_REUSE_OBJECT_METHOD_NAME.equals(method.getName()))
84          {
85              reuseObject = (Boolean) args[0];
86              return null;
87          }
88          else if (XaTransaction.MuleXaObject.IS_REUSE_OBJECT_METHOD_NAME.equals(method.getName()))
89          {
90              return reuseObject;
91          }
92          else if (XaTransaction.MuleXaObject.GET_TARGET_OBJECT_METHOD_NAME.equals(method.getName()))
93          {
94              return getTargetObject();
95          }
96          else if (XaTransaction.MuleXaObject.CLOSE_METHOD_NAME.equals(method.getName()))
97          {
98              // some jms implementation need both sessions closed, some not
99              try
100             {
101                 session.close();
102                 xaSession.close();
103             }
104             catch (Exception ex)
105             {
106                 if (logger.isDebugEnabled())
107                 {
108                     logger.debug("Closing the session and the xaSession failed", ex);
109                 }
110             }
111             return null;
112         }
113         
114         Object result = method.invoke(session, args);
115 
116         if (result instanceof TopicSubscriber)
117         {
118             result = Proxy.newProxyInstance(Session.class.getClassLoader(),
119                                             new Class[]{TopicSubscriber.class}, new ConsumerProducerInvocationHandler(this, result));
120         }
121         else if (result instanceof QueueReceiver)
122         {
123             result = Proxy.newProxyInstance(Session.class.getClassLoader(),
124                                             new Class[]{QueueReceiver.class}, new ConsumerProducerInvocationHandler(this, result));
125         }
126         else if (result instanceof MessageConsumer)
127         {
128             result = Proxy.newProxyInstance(Session.class.getClassLoader(),
129                                             new Class[]{MessageConsumer.class}, new ConsumerProducerInvocationHandler(this, result));
130         }
131         else if (result instanceof TopicPublisher)
132         {
133             result = Proxy.newProxyInstance(Session.class.getClassLoader(),
134                                             new Class[]{TopicPublisher.class}, new ConsumerProducerInvocationHandler(this, result));
135         }
136         else if (result instanceof QueueSender)
137         {
138             result = Proxy.newProxyInstance(Session.class.getClassLoader(),
139                                             new Class[]{QueueSender.class}, new ConsumerProducerInvocationHandler(this, result));
140         }
141         else if (result instanceof MessageProducer)
142         {
143             result = Proxy.newProxyInstance(Session.class.getClassLoader(),
144                                             new Class[]{MessageProducer.class}, new ConsumerProducerInvocationHandler(this, result));
145         }
146         return result;
147     }
148 
149     public boolean enlist() throws Exception
150     {
151         if (isEnlisted())
152         {
153             return false;
154         }
155 
156         if (logger.isDebugEnabled())
157         {
158             logger.debug("Enlistment request: " + this);
159         }
160 
161         Transaction transaction = TransactionCoordination.getInstance().getTransaction();
162         if (transaction == null)
163         {
164             throw new IllegalTransactionStateException(CoreMessages.noMuleTransactionAvailable());
165         }
166         if (!(transaction instanceof XaTransaction))
167         {
168             throw new IllegalTransactionStateException(CoreMessages.notMuleXaTransaction(transaction));
169         }
170 
171         if (!isEnlisted())
172         {
173             if (logger.isDebugEnabled())
174             {
175                 logger.debug("Enlisting resource " + xaResource + " in xa transaction " + transaction);
176             }
177 
178             enlisted = ((XaTransaction) transaction).enlistResource(xaResource);
179         }
180         
181         return enlisted;
182     }
183 
184     public boolean delist() throws Exception
185     {
186         if (!isEnlisted())
187         {
188             return false;
189         }
190 
191         if (logger.isDebugEnabled())
192         {
193             logger.debug("Delistment request: " + this);
194         }
195 
196         Transaction transaction = TransactionCoordination.getInstance().getTransaction();
197         if (transaction == null)
198         {
199             throw new IllegalTransactionStateException(CoreMessages.noMuleTransactionAvailable());
200         }
201         if (!(transaction instanceof XaTransaction))
202         {
203             throw new IllegalTransactionStateException(CoreMessages.notMuleXaTransaction(transaction));
204         }
205 
206         if (isEnlisted())
207         {
208             if (logger.isDebugEnabled())
209             {
210                 logger.debug("Delisting resource " + xaResource + " in xa transaction " + transaction);
211             }
212 
213             enlisted = !((XaTransaction) transaction).delistResource(xaResource, XAResource.TMSUCCESS);
214         }
215         return !isEnlisted();
216     }
217 
218     public boolean isEnlisted()
219     {
220         return enlisted;
221     }
222 
223     public void setEnlisted(boolean enlisted)
224     {
225         this.enlisted = enlisted;
226     }
227 
228     public Object getTargetObject()
229     {
230         return xaSession;
231     }
232 
233     public XAResource getXAResource()
234     {
235         return xaResource;
236     }
237 
238 }