1 /***
2 * Copyright 2003-2010 Terracotta, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package net.sf.ehcache;
18
19 import bitronix.tm.TransactionManagerServices;
20 import net.sf.ehcache.config.CacheConfiguration;
21
22 import java.util.concurrent.CyclicBarrier;
23
24 import javax.transaction.*;
25
26 import junit.framework.TestCase;
27 import net.sf.ehcache.transaction.manager.DefaultTransactionManagerLookup;
28
29 public class XACacheTest extends TestCase {
30
31 private Cache cache;
32 private DefaultTransactionManagerLookup transactionManagerLookup;
33
34 private DefaultTransactionManagerLookup getTransactionManagerLookup() {
35 if (transactionManagerLookup == null) {
36 this.transactionManagerLookup = new DefaultTransactionManagerLookup();
37 TransactionManagerServices.getConfiguration().setJournal("null");
38 }
39 return this.transactionManagerLookup;
40 }
41
42 public void testXACache() throws Throwable {
43 TransactionManager txnManager = getTransactionManagerLookup().getTransactionManager();
44 Element element1 = new Element("key1", "value1");
45 Element element2 = new Element("key2", "value2");
46 CyclicBarrier barrier = new CyclicBarrier(2);
47
48 Transaction1Thread thread1 = new Transaction1Thread(cache, element1, element2, txnManager, barrier);
49 Transaction2Thread thread2 = new Transaction2Thread(cache, element1, element2, txnManager, barrier);
50 thread1.start();
51 thread2.start();
52 try {
53 thread1.join(10000);
54 thread2.join(10000);
55 } catch (InterruptedException e) {
56 fail("Interrupted!");
57 }
58
59 thread1.check();
60 thread2.check();
61 }
62
63 private static class Transaction1Thread extends AbstractTxnThread {
64
65 public Transaction1Thread(Cache cache, Element element1, Element element2, TransactionManager txnManager, CyclicBarrier barrier) {
66 super(cache, element1, element2, txnManager, barrier);
67 }
68
69 @Override
70 public void run() {
71 try {
72 txnManager.begin();
73 cache.put(element1);
74 barrier.await();
75 barrier.await();
76 txnManager.commit();
77 barrier.await();
78 } catch (Throwable e) {
79 exception = e;
80 barrier.reset();
81 rollbackQuietly();
82 }
83 }
84 }
85
86 private static class Transaction2Thread extends AbstractTxnThread {
87
88 public Transaction2Thread(Cache cache, Element element1, Element element2, TransactionManager txnManager, CyclicBarrier barrier) {
89 super(cache, element1, element2, txnManager, barrier);
90 }
91
92 @Override
93 public void run() {
94 try {
95 txnManager.begin();
96 barrier.await();
97 Element newElement = cache.get(element1.getKey());
98 assertNull(newElement);
99 barrier.await();
100 barrier.await();
101 newElement = cache.get(element1.getKey());
102 assertNotNull(newElement);
103 txnManager.commit();
104 } catch (Throwable e) {
105 exception = e;
106 barrier.reset();
107 rollbackQuietly();
108 }
109 }
110 }
111
112 private static abstract class AbstractTxnThread extends Thread {
113
114 protected volatile Throwable exception;
115
116 final Element element1;
117 final Element element2;
118 final TransactionManager txnManager;
119 final CyclicBarrier barrier;
120 final Cache cache;
121
122 public AbstractTxnThread(Cache cache, Element element1, Element element2, TransactionManager txnManager, CyclicBarrier barrier) {
123 this.element1 = element1;
124 this.element2 = element2;
125 this.txnManager = txnManager;
126 this.barrier = barrier;
127 this.cache = cache;
128 }
129
130 void rollbackQuietly() {
131 try {
132 if (txnManager.getStatus() != javax.transaction.Status.STATUS_NO_TRANSACTION) {
133 txnManager.rollback();
134 }
135 } catch (Exception e1) {
136 e1.printStackTrace();
137 }
138 }
139
140 public void check() throws Throwable {
141 if(exception != null) {
142 throw exception;
143 }
144 }
145 }
146
147 @Override
148 protected void setUp() throws Exception {
149 final CacheManager manager = CacheManager.create();
150 cache = new Cache(new CacheConfiguration("sampleCache", 1000).transactionalMode(CacheConfiguration.TransactionalMode.XA_STRICT));
151 cache.setTransactionManagerLookup(getTransactionManagerLookup());
152 manager.addCache(cache);
153 }
154 }