View Javadoc

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 }