1
2
3
4
5
6
7
8
9
10
11 package org.mule.tck;
12
13 import org.mule.api.transaction.TransactionCallback;
14 import org.mule.api.transaction.TransactionConfig;
15 import org.mule.api.transaction.TransactionManagerFactory;
16 import org.mule.tck.junit4.AbstractMuleContextTestCase;
17 import org.mule.transaction.MuleTransactionConfig;
18 import org.mule.transaction.TransactionTemplate;
19 import org.mule.transaction.XaTransaction;
20 import org.mule.transaction.XaTransactionFactory;
21
22 import javax.transaction.Status;
23 import javax.transaction.Transaction;
24 import javax.transaction.TransactionManager;
25
26 import org.junit.Test;
27
28 import static org.junit.Assert.assertEquals;
29 import static org.junit.Assert.assertFalse;
30 import static org.junit.Assert.assertNotNull;
31 import static org.junit.Assert.assertNull;
32 import static org.junit.Assert.assertTrue;
33 import static org.junit.Assert.fail;
34
35
36
37
38
39 public abstract class AbstractTxThreadAssociationTestCase extends AbstractMuleContextTestCase
40 {
41
42 private TransactionManager tm;
43 protected static final int TRANSACTION_TIMEOUT_SECONDS = 3;
44
45 protected void doSetUp() throws Exception
46 {
47 super.doSetUp();
48 TransactionManagerFactory factory = getTransactionManagerFactory();
49 tm = factory.create(muleContext.getConfiguration());
50 assertNotNull("Transaction Manager should be available.", tm);
51 assertNull("There should be no current transaction associated.", tm.getTransaction());
52 }
53
54 @Test
55 public void testTxHandleCommitKeepsThreadAssociation() throws Exception
56 {
57
58 tm.setTransactionTimeout(TRANSACTION_TIMEOUT_SECONDS);
59 tm.begin();
60
61 Transaction tx = tm.getTransaction();
62 assertNotNull("Transaction should have started.", tx);
63 assertEquals("TX should have been active", Status.STATUS_ACTIVE, tx.getStatus());
64
65 tx.commit();
66
67 tx = tm.getTransaction();
68 assertNotNull("Committing via TX handle should NOT disassociated TX from the current thread.",
69 tx);
70 assertEquals("TX status should have been COMMITTED.", Status.STATUS_COMMITTED, tx.getStatus());
71
72
73
74 Transaction suspended = tm.suspend();
75 assertTrue("Wrong TX suspended?.", suspended.equals(tx));
76 assertNull("TX should've been disassociated from the thread.", tm.getTransaction());
77
78
79 tm.resume(null);
80
81
82 assertNull(tm.getTransaction());
83 }
84
85 @Test
86 public void testTxManagerCommitDissassociatesThread() throws Exception
87 {
88
89 tm.setTransactionTimeout(TRANSACTION_TIMEOUT_SECONDS);
90 tm.begin();
91
92 Transaction tx = tm.getTransaction();
93 assertNotNull("Transaction should have started.", tx);
94 assertEquals("TX should have been active", Status.STATUS_ACTIVE, tx.getStatus());
95
96 tm.commit();
97
98 assertNull("Committing via TX Manager should have disassociated TX from the current thread.",
99 tm.getTransaction());
100 }
101
102 @Test
103 public void testTxManagerRollbackDissassociatesThread() throws Exception
104 {
105
106 tm.setTransactionTimeout(TRANSACTION_TIMEOUT_SECONDS);
107 tm.begin();
108
109 Transaction tx = tm.getTransaction();
110 assertNotNull("Transaction should have started.", tx);
111 assertEquals("TX should have been active", Status.STATUS_ACTIVE, tx.getStatus());
112
113 tm.rollback();
114
115 assertNull("Committing via TX Manager should have disassociated TX from the current thread.",
116 tm.getTransaction());
117 }
118
119
120
121
122
123
124 @Test
125 public void testAlwaysBeginXaTransactionSuspendResume() throws Exception
126 {
127 muleContext.setTransactionManager(tm);
128 assertNull("There should be no current transaction associated.", tm.getTransaction());
129
130
131 tm.setTransactionTimeout(TRANSACTION_TIMEOUT_SECONDS);
132
133
134 TransactionConfig config = new MuleTransactionConfig(TransactionConfig.ACTION_ALWAYS_BEGIN);
135 config.setFactory(new XaTransactionFactory());
136 TransactionTemplate template = new TransactionTemplate(config, muleContext);
137
138
139 final TransactionConfig nestedConfig = new MuleTransactionConfig(TransactionConfig.ACTION_ALWAYS_BEGIN);
140 nestedConfig.setFactory(new XaTransactionFactory());
141
142
143 template.execute(new TransactionCallback<Void>()
144 {
145 public Void doInTransaction() throws Exception
146 {
147
148
149 TransactionTemplate<Void> nestedTemplate =
150 new TransactionTemplate<Void>(nestedConfig, muleContext);
151 final Transaction firstTx = tm.getTransaction();
152 assertNotNull(firstTx);
153 assertEquals(firstTx.getStatus(), Status.STATUS_ACTIVE);
154 return nestedTemplate.execute(new TransactionCallback<Void>()
155 {
156 public Void doInTransaction() throws Exception
157 {
158 Transaction secondTx = tm.getTransaction();
159 assertNotNull(secondTx);
160 assertEquals(firstTx.getStatus(), Status.STATUS_ACTIVE);
161 assertEquals(secondTx.getStatus(), Status.STATUS_ACTIVE);
162 try
163 {
164 tm.resume(firstTx);
165 fail("Second transaction must be active");
166 }
167 catch (java.lang.IllegalStateException e)
168 {
169
170
171
172
173 }
174 try
175 {
176 Transaction currentTx = tm.suspend();
177 assertTrue(currentTx.equals(secondTx));
178 tm.resume(firstTx);
179 assertEquals(firstTx, tm.getTransaction());
180 assertEquals(firstTx.getStatus(), Status.STATUS_ACTIVE);
181 assertEquals(secondTx.getStatus(), Status.STATUS_ACTIVE);
182 Transaction a = tm.suspend();
183 assertTrue(a.equals(firstTx));
184 tm.resume(secondTx);
185 }
186 catch (Exception e)
187 {
188 fail("Error: " + e);
189 }
190
191
192 return null;
193 }
194 });
195 }
196 });
197 assertNull("Committing via TX Manager should have disassociated TX from the current thread.",
198 tm.getTransaction());
199 }
200
201
202
203
204
205
206 @Test
207 public void testNoneXaTransactionSuspendResume() throws Exception
208 {
209 muleContext.setTransactionManager(tm);
210 assertNull("There should be no current transaction associated.", tm.getTransaction());
211
212
213 tm.setTransactionTimeout(TRANSACTION_TIMEOUT_SECONDS);
214
215
216 TransactionConfig config = new MuleTransactionConfig(TransactionConfig.ACTION_ALWAYS_BEGIN);
217 config.setFactory(new XaTransactionFactory());
218 TransactionTemplate<Void> template = new TransactionTemplate<Void>(config, muleContext);
219
220
221 final TransactionConfig nestedConfig = new MuleTransactionConfig(TransactionConfig.ACTION_NONE);
222 nestedConfig.setFactory(new XaTransactionFactory());
223
224
225 template.execute(new TransactionCallback<Void>()
226 {
227 public Void doInTransaction() throws Exception
228 {
229
230
231 TransactionTemplate<Void> nestedTemplate =
232 new TransactionTemplate<Void>(nestedConfig, muleContext);
233 final Transaction firstTx = tm.getTransaction();
234 assertNotNull(firstTx);
235 assertEquals(firstTx.getStatus(), Status.STATUS_ACTIVE);
236 return nestedTemplate.execute(new TransactionCallback<Void>()
237 {
238 public Void doInTransaction() throws Exception
239 {
240 Transaction secondTx = tm.getTransaction();
241 assertNull(secondTx);
242 assertEquals(firstTx.getStatus(), Status.STATUS_ACTIVE);
243 try
244 {
245 tm.resume(firstTx);
246 assertEquals(firstTx, tm.getTransaction());
247 assertEquals(firstTx.getStatus(), Status.STATUS_ACTIVE);
248 Transaction a = tm.suspend();
249 assertTrue(a.equals(firstTx));
250 }
251 catch (Exception e)
252 {
253 fail("Error: " + e);
254 }
255
256
257 return null;
258 }
259 });
260 }
261 });
262 assertNull("Committing via TX Manager should have disassociated TX from the current thread.",
263 tm.getTransaction());
264 }
265
266
267
268
269
270
271 @Test
272 public void testXaTransactionTermination() throws Exception
273 {
274 muleContext.setTransactionManager(tm);
275 assertNull("There should be no current transaction associated.", tm.getTransaction());
276
277
278 tm.setTransactionTimeout(TRANSACTION_TIMEOUT_SECONDS);
279
280 XaTransaction muleTx = new XaTransaction(muleContext);
281 assertFalse(muleTx.isBegun());
282 assertEquals(Status.STATUS_NO_TRANSACTION, muleTx.getStatus());
283 muleTx.begin();
284
285 assertTrue(muleTx.isBegun());
286
287 muleTx.commit();
288
289 Transaction jtaTx = tm.getTransaction();
290 assertNull("Committing via TX Manager should have disassociated TX from the current thread.", jtaTx);
291 assertEquals(Status.STATUS_NO_TRANSACTION, muleTx.getStatus());
292 }
293
294
295
296
297
298
299
300 @Test
301 public void testNoNestedTxStarted() throws Exception
302 {
303 muleContext.setTransactionManager(tm);
304 assertNull("There should be no current transaction associated.", tm.getTransaction());
305
306
307 tm.setTransactionTimeout(TRANSACTION_TIMEOUT_SECONDS);
308
309
310 TransactionConfig config = new MuleTransactionConfig(TransactionConfig.ACTION_ALWAYS_BEGIN);
311 config.setFactory(new XaTransactionFactory());
312 TransactionTemplate template = new TransactionTemplate(config, muleContext);
313
314
315 final TransactionConfig nestedConfig = new MuleTransactionConfig(TransactionConfig.ACTION_BEGIN_OR_JOIN);
316 nestedConfig.setFactory(new XaTransactionFactory());
317
318
319 template.execute(new TransactionCallback<Void>()
320 {
321 public Void doInTransaction() throws Exception
322 {
323
324
325 TransactionTemplate<Void> nestedTemplate =
326 new TransactionTemplate<Void>(nestedConfig, muleContext);
327 return nestedTemplate.execute(new TransactionCallback<Void>()
328 {
329 public Void doInTransaction() throws Exception
330 {
331
332 return null;
333 }
334 });
335 }
336 });
337 }
338
339
340 protected TransactionManager getTransactionManager()
341 {
342 return tm;
343 }
344
345 protected abstract TransactionManagerFactory getTransactionManagerFactory();
346
347 }