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.vm.functional.transactions;
8   
9   import org.mule.api.MuleContext;
10  import org.mule.api.transaction.TransactionConfig;
11  import org.mule.api.transaction.TransactionException;
12  import org.mule.tck.junit4.FunctionalTestCase;
13  import org.mule.transaction.MuleTransactionConfig;
14  import org.mule.transaction.TransactionCoordination;
15  import org.mule.transaction.TransactionTemplate;
16  import org.mule.transaction.XaTransactionFactory;
17  
18  import java.io.PrintWriter;
19  import java.io.StringWriter;
20  import java.util.HashMap;
21  import java.util.Map;
22  
23  import javax.transaction.SystemException;
24  import javax.transaction.Transaction;
25  import javax.transaction.TransactionManager;
26  import javax.transaction.xa.XAException;
27  import javax.transaction.xa.XAResource;
28  import javax.transaction.xa.Xid;
29  
30  import org.apache.commons.logging.Log;
31  import org.apache.commons.logging.LogFactory;
32  
33  
34  public abstract class AbstractExternalTransactionTestCase extends FunctionalTestCase
35  {
36      protected static final Log logger = LogFactory.getLog(AbstractExternalTransactionTestCase.class);
37      protected MuleContext context;
38      protected TransactionManager tm;
39  
40      @Override
41      protected void doSetUp() throws Exception
42      {
43          cleanupTransactionState();
44      }
45  
46      @Override
47      protected void doTearDown() throws Exception
48      {
49          cleanupTransactionState();
50      }
51  
52      private void cleanupTransactionState()
53      {
54          try
55          {
56              if (tm != null && tm.getTransaction() != null)
57              {
58                  tm.rollback();
59              }
60          }
61          catch (Exception ex)
62          {
63              logger.debug(ex);
64          }
65          try
66          {
67              org.mule.api.transaction.Transaction tx = TransactionCoordination.getInstance().getTransaction();
68              if (tx != null)
69              {
70                  TransactionCoordination.getInstance().unbindTransaction(tx);
71              }
72          }
73          catch (TransactionException ex)
74          {
75              logger.debug(ex);
76          }
77      }
78  
79      protected void init() throws Exception
80      {
81          context = createMuleContext();
82          tm = context.getTransactionManager();
83      }
84  
85      protected <T> TransactionTemplate<T> createTransactionTemplate(byte action, boolean considerExternal)
86      {
87          TransactionConfig tc = new MuleTransactionConfig();
88          tc.setAction(action);
89          tc.setFactory(new XaTransactionFactory());
90          tc.setInteractWithExternal(considerExternal);
91          TransactionTemplate<T> tt = new TransactionTemplate<T>(tc, context);
92          return tt;
93      }
94  
95      /** An XA resource that allows setting, committing, and rolling back the value of one resource */
96      public static class TestResource implements XAResource
97      {
98          private Map<Transaction, Integer> transientValue = new HashMap<Transaction, Integer>();
99          private int persistentValue;
100         private TransactionManager tm;
101 
102         public TestResource(TransactionManager tm)
103         {
104             this.tm = tm;
105         }
106 
107         public void setValue(int val)
108         {
109             Transaction tx = getCurrentTransaction();
110             transientValue.put(tx, val);
111         }
112 
113         private Transaction getCurrentTransaction()
114         {
115             Transaction tx = null;
116             Exception ex = null;
117             try
118             {
119                 tx = tm.getTransaction();
120             }
121             catch (SystemException e)
122             {
123                 tx = null;
124                 ex = e;
125             }
126             if (tx == null)
127             {
128                 throw new IllegalStateException("Unable to access resource value outside transaction", ex);
129             }
130             return tx;
131         }
132 
133         public int getPersistentValue()
134         {
135             return persistentValue;
136         }
137 
138         public int getValue()
139         {
140             Transaction tx = null;
141             try
142             {
143                 tx = getCurrentTransaction();
144             }
145             catch (Exception ex)
146             {
147                 // return persistent value
148             }
149             Integer val = transientValue.get(tx);
150             return val == null ? persistentValue : val;
151         }
152 
153         public void commit(Xid id, boolean onePhase) throws XAException
154         {
155             logger.debug("XA_COMMIT[" + id + "]");
156             dumpStackTrace();
157             Transaction tx = getCurrentTransaction();
158             persistentValue = transientValue.get(tx);
159         }
160 
161         public void end(Xid xid, int flags) throws XAException
162         {
163             logger.debug("XA_END[" + xid + "] Flags=" + flags);
164             dumpStackTrace();
165         }
166 
167         public void forget(Xid xid) throws XAException
168         {
169             logger.debug("XA_FORGET[" + xid + "]");
170             dumpStackTrace();
171         }
172 
173         public int getTransactionTimeout() throws XAException
174         {
175             return (_timeout);
176         }
177 
178         public boolean isSameRM(XAResource xares) throws XAException
179         {
180             return (xares.equals(this));
181         }
182 
183         public int prepare(Xid xid) throws XAException
184         {
185             logger.debug("XA_PREPARE[" + xid + "]");
186             dumpStackTrace();
187 
188             return (XA_OK);
189         }
190 
191         public Xid[] recover(int flag) throws XAException
192         {
193             logger.debug("RECOVER[" + flag + "]");
194             dumpStackTrace();
195             return (null);
196         }
197 
198         public void rollback(Xid xid) throws XAException
199         {
200             logger.debug("XA_ROLLBACK[" + xid + "]");
201             dumpStackTrace();
202 
203             Transaction tx = getCurrentTransaction();
204             transientValue.remove(tx);
205         }
206 
207         public boolean setTransactionTimeout(int seconds) throws XAException
208         {
209             _timeout = seconds;
210             return (true);
211         }
212 
213         public void start(Xid xid, int flags) throws XAException
214         {
215             logger.debug("XA_START[" + xid + "] Flags=" + flags);
216             dumpStackTrace();
217         }
218 
219         protected int _timeout = 0;
220 
221         private void dumpStackTrace()
222         {
223             if (logger.isDebugEnabled() && false)
224             {
225                 final StringWriter sw = new StringWriter();
226                 PrintWriter pw = new PrintWriter(sw);
227                 new Exception().printStackTrace(pw);
228                 pw.flush();
229                 logger.debug(sw.toString());
230             }
231         }
232     }
233 }