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.search;
18  
19  import static org.junit.Assert.assertEquals;
20  import static org.junit.Assert.assertFalse;
21  import static org.junit.Assert.assertTrue;
22  import static org.junit.Assert.fail;
23  
24  import java.util.Arrays;
25  import java.util.Collection;
26  import java.util.HashSet;
27  import java.util.Set;
28  
29  import javax.transaction.TransactionManager;
30  
31  import net.sf.ehcache.Cache;
32  import net.sf.ehcache.CacheException;
33  import net.sf.ehcache.CacheManager;
34  import net.sf.ehcache.Ehcache;
35  import net.sf.ehcache.Element;
36  import net.sf.ehcache.config.CacheConfiguration;
37  import net.sf.ehcache.config.SearchAttribute;
38  import net.sf.ehcache.config.Searchable;
39  import net.sf.ehcache.config.CacheConfiguration.TransactionalMode;
40  import net.sf.ehcache.search.Person.Gender;
41  
42  import org.junit.After;
43  import org.junit.Before;
44  import org.junit.Test;
45  import org.junit.runner.RunWith;
46  import org.junit.runners.Parameterized;
47  import org.junit.runners.Parameterized.Parameters;
48  
49  import bitronix.tm.TransactionManagerServices;
50  
51  @RunWith(Parameterized.class)
52  public class TransactionalSearchTest {
53  
54      @Parameters
55      public static Collection<Object[]> data() {
56          return Arrays.asList(new Object[][]{
57                  {TransactionalMode.LOCAL}, {TransactionalMode.XA}, {TransactionalMode.XA_STRICT}
58          });
59      }
60  
61      @Before
62      public void setupTransactionManager() {
63          switch (txnMode) {
64              case XA:
65              case XA_STRICT:
66                  TransactionManagerServices.getConfiguration().setJournal("null").setGracefulShutdownInterval(0).setBackgroundRecoveryIntervalSeconds(1);
67                  txnManager = TransactionManagerServices.getTransactionManager();
68                  break;
69              default:
70                  txnManager = null;
71                  break;
72          }
73      }
74  
75      @After
76      public void shutdownTransactionManager() throws Exception {
77          switch (txnMode) {
78              case XA:
79              case XA_STRICT:
80                  if (txnManager.getTransaction() != null) {
81                      txnManager.rollback();
82                  }
83                  TransactionManagerServices.getTransactionManager().shutdown();
84                  txnManager = null;
85                  break;
86              default:
87                  txnManager = null;
88                  break;
89          }
90      }
91  
92      private void beginTransaction(CacheManager manager) throws Exception {
93          switch (txnMode) {
94              case XA:
95              case XA_STRICT:
96                  txnManager.begin();
97                  break;
98              case LOCAL:
99                  manager.getTransactionController().begin();
100                 break;
101         }
102     }
103 
104     private void commitTransaction(CacheManager manager) throws Exception {
105         switch (txnMode) {
106             case XA:
107             case XA_STRICT:
108                 txnManager.commit();
109                 break;
110             case LOCAL:
111                 manager.getTransactionController().commit();
112                 break;
113         }
114     }
115 
116     private final TransactionalMode txnMode;
117 
118     private TransactionManager txnManager;
119 
120     public TransactionalSearchTest(TransactionalMode txnMode) {
121         this.txnMode = txnMode;
122     }
123 
124     private CacheConfiguration getBaseCacheConfiguration() {
125         return new CacheConfiguration("jta-search", 0).transactionalMode(txnMode);
126     }
127 
128     @Test
129     public void testExpressionAttributeExtractorCache() throws Exception {
130         CacheConfiguration config = getBaseCacheConfiguration();
131         config.searchable(new Searchable().
132                 searchAttribute(new SearchAttribute().name("age").expression("value.getAge()")).
133                 searchAttribute(new SearchAttribute().name("gender").expression("value.getGender()")).
134                 searchAttribute(new SearchAttribute().name("name").expression("value.getName()")));
135         testCacheWithConfiguration(config);
136     }
137 
138     @Test
139     public void testCustomAttributeExtractorCache() throws Exception {
140         CacheConfiguration config = getBaseCacheConfiguration();
141         config.searchable(new Searchable().
142                 searchAttribute(new SearchAttribute().name("age").className("net.sf.ehcache.search.TestAttributeExtractor")).
143                 searchAttribute(new SearchAttribute().name("gender").expression("value.getGender()")).
144                 searchAttribute(new SearchAttribute().name("name").expression("value.getName()")));
145         testCacheWithConfiguration(config);
146     }
147 
148     @Test
149     public void testBeanAttributeExtractorCache() throws Exception {
150         CacheConfiguration config = getBaseCacheConfiguration();
151         config.searchable(new Searchable().
152                 searchAttribute(new SearchAttribute().name("age")).
153                 searchAttribute(new SearchAttribute().name("gender")).
154                 searchAttribute(new SearchAttribute().name("name")));
155         testCacheWithConfiguration(config);
156     }
157 
158     private void testCacheWithConfiguration(CacheConfiguration config) throws Exception {
159         CacheManager cacheManager = new CacheManager();
160         Ehcache cache = new Cache(config);
161         cacheManager.addCache(cache);
162 
163         assertTrue(cache.isSearchable());
164 
165         beginTransaction(cacheManager);
166         try {
167             //This data should appear in the search results
168             SearchTestUtil.populateData(cache);
169         } finally {
170             commitTransaction(cacheManager);
171         }
172 
173         beginTransaction(cacheManager);
174         try {
175             //This data shouldn't appear in the search results
176             cache.put(new Element(-1, new Person("Chris Dennis", 29, Gender.MALE)));
177             cache.put(new Element(-2, new Person("Cassie (Dog)", 1, Gender.FEMALE)));
178             basicQueries(cache);
179         } finally {
180             commitTransaction(cacheManager);
181         }
182     }
183 
184     private void basicQueries(Ehcache cache) {
185         Query query;
186         Attribute<Integer> age = cache.getSearchAttribute("age");
187 
188         query = cache.createQuery();
189         query.includeKeys();
190         query.addCriteria(age.ne(35));
191         query.end();
192         verify(cache, query, 2, 4);
193 
194         query = cache.createQuery();
195         query.includeKeys();
196         query.addCriteria(cache.getSearchAttribute("age").lt(30));
197         query.end();
198         query.execute();
199         verify(cache, query, 2);
200 
201         query = cache.createQuery();
202         query.includeKeys();
203         query.addCriteria(cache.getSearchAttribute("age").le(30));
204         query.end();
205         query.execute();
206         verify(cache, query, 2, 4);
207 
208         query = cache.createQuery();
209         query.includeKeys();
210         query.addCriteria(cache.getSearchAttribute("age").in(new HashSet(Arrays.asList(23, 35))));
211         query.end();
212         query.execute();
213         verify(cache, query, 1, 2, 3);
214 
215         query = cache.createQuery();
216         query.includeKeys();
217         query.addCriteria(cache.getSearchAttribute("age").gt(30));
218         query.end();
219         query.execute();
220         verify(cache, query, 1, 3);
221 
222         query = cache.createQuery();
223         query.includeKeys();
224         query.addCriteria(cache.getSearchAttribute("age").between(23, 35, true, false));
225         query.end();
226         query.execute();
227         verify(cache, query, 2, 4);
228 
229         query = cache.createQuery();
230         query.includeKeys();
231         query.addCriteria(cache.getSearchAttribute("age").ge(30));
232         query.end();
233         query.execute();
234         verify(cache, query, 1, 3, 4);
235 
236         query = cache.createQuery();
237         query.includeKeys();
238         query.addCriteria(cache.getSearchAttribute("age").eq(35).or(cache.getSearchAttribute("gender").eq(Gender.FEMALE)));
239         query.end();
240         verify(cache, query, 1, 2, 3);
241 
242         query = cache.createQuery();
243         query.includeKeys();
244         query.addCriteria(cache.getSearchAttribute("age").eq(35).and(cache.getSearchAttribute("gender").eq(Gender.MALE)));
245         query.end();
246         verify(cache, query, 1, 3);
247 
248         query = cache.createQuery();
249         query.includeKeys();
250         query.addCriteria(cache.getSearchAttribute("age").eq(35).and(cache.getSearchAttribute("gender").eq(Gender.FEMALE)));
251         query.end();
252         verify(cache, query);
253 
254         query = cache.createQuery();
255         query.includeKeys();
256         query.addCriteria(cache.getSearchAttribute("gender").eq(Gender.MALE).not());
257         query.end();
258         verify(cache, query, 2);
259 
260         try {
261             cache.getSearchAttribute("DOES_NOT_EXIST_PLEASE_DO_NOT_CREATE_ME");
262             fail();
263         } catch (CacheException ce) {
264             // expected
265         }
266     }
267 
268     private void verify(Ehcache cache, Query query, Integer... expectedKeys) {
269         Results results = query.execute();
270         assertEquals(expectedKeys.length, results.size());
271         assertTrue(results.hasKeys());
272         assertFalse(results.hasAttributes());
273 
274         Set<Integer> keys = new HashSet<Integer>(Arrays.asList(expectedKeys));
275 
276         for (Result result : results.all()) {
277             int key = (Integer) result.getKey();
278             if (!keys.remove(key)) {
279                 throw new AssertionError("unexpected key: " + key);
280             }
281         }
282     }
283 }