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  package net.sf.ehcache.transaction;
17  
18  import java.io.IOException;
19  import java.util.Collection;
20  import java.util.Iterator;
21  import java.util.List;
22  import java.util.ListIterator;
23  import java.util.Map;
24  import java.util.Set;
25  
26  import net.sf.ehcache.CacheException;
27  import net.sf.ehcache.Element;
28  import net.sf.ehcache.Status;
29  import net.sf.ehcache.config.InvalidConfigurationException;
30  import net.sf.ehcache.search.Attribute;
31  import net.sf.ehcache.search.Result;
32  import net.sf.ehcache.search.Results;
33  import net.sf.ehcache.search.SearchException;
34  import net.sf.ehcache.search.attribute.AttributeExtractor;
35  import net.sf.ehcache.store.AbstractStore;
36  import net.sf.ehcache.store.Policy;
37  import net.sf.ehcache.store.Store;
38  import net.sf.ehcache.store.StoreQuery;
39  import net.sf.ehcache.store.TerracottaStore;
40  import net.sf.ehcache.store.compound.ReadWriteCopyStrategy;
41  import net.sf.ehcache.terracotta.TerracottaNotRunningException;
42  
43  /***
44   * Abstract transactional store which provides implementation of all non-transactional methods
45   *
46   * @author Ludovic Orban
47   */
48  public abstract class AbstractTransactionStore extends AbstractStore implements TerracottaStore {
49  
50      /***
51       * The underlying store wrapped by this store
52       */
53      protected final Store underlyingStore;
54  
55      /***
56       * The copy strategy for this store
57       */
58      protected final ReadWriteCopyStrategy<Element> copyStrategy;
59  
60      /***
61       * Constructor
62       * @param underlyingStore the underlying store
63       */
64      protected AbstractTransactionStore(Store underlyingStore, ReadWriteCopyStrategy<Element> copyStrategy) {
65          this.underlyingStore = underlyingStore;
66          this.copyStrategy = copyStrategy;
67      }
68  
69      /***
70       * Copy element for read operation
71       *
72       * @param element
73       * @return copied element
74       */
75      protected Element copyElementForRead(Element element) {
76          return copyStrategy.copyForRead(element);
77      }
78  
79      /***
80       * Copy element for write operation
81       *
82       * @param element
83       * @return copied element
84       */
85      protected Element copyElementForWrite(Element element) {
86          return copyStrategy.copyForWrite(element);
87      }
88  
89      /***
90       * {@inheritDoc}
91       */
92      @Override
93      public Results executeQuery(StoreQuery query) {
94          Results results = underlyingStore.executeQuery(query);
95          if (results instanceof TxSearchResults) {
96              // don't re-wrap needlessly
97              return results;
98          }
99          return new TxSearchResults(underlyingStore.executeQuery(query));
100     }
101 
102     /* non-transactional methods */
103 
104     /***
105      * {@inheritDoc}
106      */
107     public int getInMemorySize() {
108         return underlyingStore.getInMemorySize();
109     }
110 
111     /***
112      * {@inheritDoc}
113      */
114     public int getOffHeapSize() {
115         return underlyingStore.getOffHeapSize();
116     }
117 
118     /***
119      * {@inheritDoc}
120      */
121     public int getOnDiskSize() {
122         return underlyingStore.getOnDiskSize();
123     }
124 
125     /***
126      * {@inheritDoc}
127      */
128     public long getInMemorySizeInBytes() {
129         return underlyingStore.getInMemorySizeInBytes();
130     }
131 
132     /***
133      * {@inheritDoc}
134      */
135     public long getOffHeapSizeInBytes() {
136         return underlyingStore.getOffHeapSizeInBytes();
137     }
138 
139     /***
140      * {@inheritDoc}
141      */
142     public long getOnDiskSizeInBytes() {
143         return underlyingStore.getOnDiskSizeInBytes();
144     }
145 
146     /***
147      * {@inheritDoc}
148      */
149     public boolean containsKeyOnDisk(Object key) {
150         return underlyingStore.containsKeyOnDisk(key);
151     }
152 
153     /***
154      * {@inheritDoc}
155      */
156     public boolean containsKeyOffHeap(Object key) {
157         return underlyingStore.containsKeyOffHeap(key);
158     }
159 
160     /***
161      * {@inheritDoc}
162      */
163     public boolean containsKeyInMemory(Object key) {
164         return underlyingStore.containsKeyInMemory(key);
165     }
166 
167     /***
168      * {@inheritDoc}
169      */
170     public void dispose() {
171         underlyingStore.dispose();
172     }
173 
174     /***
175      * {@inheritDoc}
176      */
177     public Status getStatus() {
178         return underlyingStore.getStatus();
179     }
180 
181     /***
182      * {@inheritDoc}
183      */
184     public void expireElements() {
185         underlyingStore.expireElements();
186     }
187 
188     /***
189      * {@inheritDoc}
190      */
191     public void flush() throws IOException {
192         underlyingStore.flush();
193     }
194 
195     /***
196      * {@inheritDoc}
197      */
198     public boolean bufferFull() {
199         return underlyingStore.bufferFull();
200     }
201 
202     /***
203      * {@inheritDoc}
204      */
205     public Policy getInMemoryEvictionPolicy() {
206         return underlyingStore.getInMemoryEvictionPolicy();
207     }
208 
209     /***
210      * {@inheritDoc}
211      */
212     public void setInMemoryEvictionPolicy(Policy policy) {
213         underlyingStore.setInMemoryEvictionPolicy(policy);
214     }
215 
216     /***
217      * {@inheritDoc}
218      */
219     public Object getInternalContext() {
220         return underlyingStore.getInternalContext();
221     }
222 
223     /***
224      * {@inheritDoc}
225      */
226     public Object getMBean() {
227         return underlyingStore.getMBean();
228     }
229 
230     /***
231      * {@inheritDoc}
232      */
233     @Override
234     public void setNodeCoherent(boolean coherent) {
235         if (!coherent) {
236             throw new InvalidConfigurationException("a transactional cache cannot be incoherent");
237         }
238         underlyingStore.setNodeCoherent(coherent);
239     }
240 
241     /***
242      * {@inheritDoc}
243      *
244      * @see net.sf.ehcache.store.Store#isNodeCoherent()
245      */
246     @Override
247     public boolean isNodeCoherent() {
248         return underlyingStore.isNodeCoherent();
249     }
250 
251     /***
252      * {@inheritDoc}
253      *
254      * @see net.sf.ehcache.store.Store#isCacheCoherent()
255      */
256     @Override
257     public boolean isCacheCoherent() {
258         return underlyingStore.isCacheCoherent();
259     }
260 
261     /***
262      * {@inheritDoc}
263      *
264      * @see net.sf.ehcache.store.Store#isClusterCoherent()
265      */
266     @Override
267     public boolean isClusterCoherent() {
268         return underlyingStore.isClusterCoherent();
269     }
270 
271     /***
272      * {@inheritDoc}
273      * @throws InterruptedException
274      * @throws UnsupportedOperationException
275      * @throws TerracottaNotRunningException
276      */
277     @Override
278     public void waitUntilClusterCoherent() throws TerracottaNotRunningException, UnsupportedOperationException, InterruptedException {
279         underlyingStore.waitUntilClusterCoherent();
280     }
281 
282     /***
283      * {@inheritDoc}
284      */
285     @Override
286     public void setAttributeExtractors(Map<String, AttributeExtractor> extractors) {
287         underlyingStore.setAttributeExtractors(extractors);
288     }
289 
290     /***
291      * {@inheritDoc}
292      */
293     @Override
294     public <T> Attribute<T> getSearchAttribute(String attributeName) throws CacheException {
295         return underlyingStore.getSearchAttribute(attributeName);
296     }
297 
298     /* TerracottaStore methods */
299 
300     /***
301      * {@inheritDoc}
302      */
303     public Element unsafeGet(Object key) {
304         if (underlyingStore instanceof TerracottaStore) {
305             return ((TerracottaStore) underlyingStore).unsafeGet(key);
306         }
307         throw new CacheException("underlying store is not an instance of TerracottaStore");
308     }
309 
310     /***
311      * {@inheritDoc}
312      */
313     public Element unsafeGetQuiet(Object key) {
314         if (underlyingStore instanceof TerracottaStore) {
315             return ((TerracottaStore) underlyingStore).unsafeGetQuiet(key);
316         }
317         throw new CacheException("underlying store is not an instance of TerracottaStore");
318     }
319 
320     /***
321      * {@inheritDoc}
322      */
323     public Element unlockedGet(Object key) {
324         if (underlyingStore instanceof TerracottaStore) {
325             return ((TerracottaStore) underlyingStore).unlockedGet(key);
326         }
327         throw new CacheException("underlying store is not an instance of TerracottaStore");
328     }
329 
330     /***
331      * {@inheritDoc}
332      */
333     public Element unlockedGetQuiet(Object key) {
334         if (underlyingStore instanceof TerracottaStore) {
335             return ((TerracottaStore) underlyingStore).unlockedGetQuiet(key);
336         }
337         throw new CacheException("underlying store is not an instance of TerracottaStore");
338     }
339 
340     /***
341      * {@inheritDoc}
342      */
343     public Set getLocalKeys() {
344         if (underlyingStore instanceof TerracottaStore) {
345             return ((TerracottaStore) underlyingStore).getLocalKeys();
346         }
347         throw new CacheException("underlying store is not an instance of TerracottaStore");
348     }
349 
350     /***
351      * Wrap search results so that Result.getValue() can use copy strategy
352      *
353      * @author teck
354      */
355     private class TxSearchResults implements Results {
356 
357         private final Results results;
358 
359         TxSearchResults(Results results) {
360             this.results = results;
361         }
362 
363         public void discard() {
364             results.discard();
365         }
366 
367         public List<Result> all() throws SearchException {
368             return new TxResultsList(results.all());
369         }
370 
371         public List<Result> range(int start, int count) throws SearchException, IndexOutOfBoundsException {
372             return new TxResultsList(results.range(start, count));
373         }
374 
375         public int size() {
376             return results.size();
377         }
378 
379         public boolean hasKeys() {
380             return results.hasKeys();
381         }
382 
383         public boolean hasValues() {
384             return results.hasValues();
385         }
386 
387         public boolean hasAttributes() {
388             return results.hasAttributes();
389         }
390 
391         public boolean hasAggregators() {
392             return results.hasAggregators();
393         }
394     }
395 
396     /***
397      * Wrap search results so that Result.getValue() can use copy strategy
398      *
399      * @author teck
400      */
401     private class TxResultsList implements List<Result> {
402 
403         private final List<Result> results;
404 
405         TxResultsList(List<Result> results) {
406             this.results = results;
407         }
408 
409         public int size() {
410             return results.size();
411         }
412 
413         public boolean isEmpty() {
414             return results.isEmpty();
415         }
416 
417         public boolean contains(Object o) {
418             return results.contains(unwrapIfNeeded(o));
419         }
420 
421         public Iterator<Result> iterator() {
422             return new TxResultsIterator(results.iterator());
423         }
424 
425         public Object[] toArray() {
426             return wrapResultArray(results.toArray());
427         }
428 
429         public <T> T[] toArray(T[] a) {
430             return wrapResultArray(results.toArray(a));
431         }
432 
433         private <T> T[] wrapResultArray(T[] array) {
434             for (int i = 0; i < array.length; i++) {
435                 array[i] = (T) new TxResult((Result) array[i]);
436             }
437             return array;
438         }
439 
440         public boolean add(Result o) {
441             throw new UnsupportedOperationException();
442         }
443 
444         public boolean remove(Object o) {
445             throw new UnsupportedOperationException();
446         }
447 
448         public boolean containsAll(Collection<?> c) {
449             for (Object o : c) {
450                 if (!contains(o)) {
451                     return false;
452                 }
453             }
454             return true;
455         }
456 
457         public boolean addAll(Collection<? extends Result> c) {
458             throw new UnsupportedOperationException();
459         }
460 
461         public boolean addAll(int index, Collection<? extends Result> c) {
462             throw new UnsupportedOperationException();
463         }
464 
465         public boolean removeAll(Collection<?> c) {
466             throw new UnsupportedOperationException();
467         }
468 
469         public boolean retainAll(Collection<?> c) {
470             throw new UnsupportedOperationException();
471         }
472 
473         public void clear() {
474             throw new UnsupportedOperationException();
475         }
476 
477         @Override
478         public boolean equals(Object o) {
479             if (o == this) {
480                 return true;
481             }
482             if (o == null) {
483                 return false;
484             }
485 
486             if (o instanceof List) {
487                 List other = (List) o;
488                 if (size() != other.size()) {
489                     return false;
490                 }
491 
492                 Iterator thisIter = results.iterator();
493                 Iterator otherIter = other.iterator();
494                 while (thisIter.hasNext()) {
495                     Object otherItem = unwrapIfNeeded(otherIter.next());
496                     Object thisItem = thisIter.next();
497                     if (otherItem == null && thisItem == null) {
498                         continue;
499                     }
500                     if (otherItem != null && thisItem == null) {
501                         return false;
502                     }
503                     if (thisItem != null && otherItem == null) {
504                         return false;
505                     }
506 
507                     if (!thisItem.equals(otherItem)) {
508                         return false;
509                     }
510                 }
511 
512                 return true;
513             }
514 
515             return false;
516         }
517 
518         @Override
519         public int hashCode() {
520             return results.hashCode();
521         }
522 
523         public Result get(int index) {
524             return new TxResult(results.get(index));
525         }
526 
527         public Result set(int index, Result element) {
528             throw new UnsupportedOperationException();
529         }
530 
531         public void add(int index, Result element) {
532             throw new UnsupportedOperationException();
533         }
534 
535         public Result remove(int index) {
536             throw new UnsupportedOperationException();
537         }
538 
539         public int indexOf(Object o) {
540             return results.indexOf(unwrapIfNeeded(o));
541         }
542 
543         public int lastIndexOf(Object o) {
544             return results.lastIndexOf(unwrapIfNeeded(o));
545         }
546 
547         public ListIterator<Result> listIterator() {
548             return new TxResultsListIterator(results.listIterator());
549         }
550 
551         public ListIterator<Result> listIterator(int index) {
552             return new TxResultsListIterator(results.listIterator(index));
553         }
554 
555         public List<Result> subList(int fromIndex, int toIndex) {
556             return new TxResultsList(results.subList(fromIndex, toIndex));
557         }
558 
559         private Object unwrapIfNeeded(Object o) {
560             if (o instanceof TxResult) {
561                 return ((TxResult) o).getUnderylingResult();
562             }
563             return o;
564         }
565 
566     }
567 
568     /***
569      * Wrap search results so that Result.getValue() can use copy strategy
570      *
571      * @author teck
572      */
573     private class TxResult implements Result {
574         private final Result result;
575 
576         TxResult(Result result) {
577             this.result = result;
578         }
579 
580         Result getUnderylingResult() {
581             return result;
582         }
583 
584         public Object getKey() throws SearchException {
585             return result.getKey();
586         }
587 
588         public Object getValue() throws SearchException {
589             return copyElementForRead(new Element(result.getKey(), result.getValue())).getObjectValue();
590         }
591 
592         public <T> T getAttribute(Attribute<T> attribute) throws SearchException {
593             return result.getAttribute(attribute);
594         }
595 
596         public List<Object> getAggregatorResults() throws SearchException {
597             return result.getAggregatorResults();
598         }
599     }
600 
601     /***
602      * Wrap search results so that Result.getValue() can use copy strategy
603      *
604      * @author teck
605      */
606     private class TxResultsIterator implements Iterator<Result> {
607 
608         private final Iterator<Result> iterator;
609 
610         TxResultsIterator(Iterator<Result> iterator) {
611             this.iterator = iterator;
612         }
613 
614         public boolean hasNext() {
615             return iterator.hasNext();
616         }
617 
618         public Result next() {
619             return new TxResult(iterator.next());
620         }
621 
622         public void remove() {
623             throw new UnsupportedOperationException();
624         }
625     }
626 
627     /***
628      * Wrap search results so that Result.getValue() can use copy strategy
629      *
630      * @author teck
631      */
632     private class TxResultsListIterator implements ListIterator<Result> {
633 
634         private final ListIterator<Result> listIterator;
635 
636         TxResultsListIterator(ListIterator<Result> listIterator) {
637             this.listIterator = listIterator;
638         }
639 
640         public boolean hasNext() {
641             return listIterator.hasNext();
642         }
643 
644         public Result next() {
645             return new TxResult(listIterator.next());
646         }
647 
648         public boolean hasPrevious() {
649             return listIterator.hasPrevious();
650         }
651 
652         public Result previous() {
653             return new TxResult(listIterator.previous());
654         }
655 
656         public int nextIndex() {
657             return listIterator.nextIndex();
658         }
659 
660         public int previousIndex() {
661             return listIterator.previousIndex();
662         }
663 
664         public void remove() {
665             throw new UnsupportedOperationException();
666         }
667 
668         public void set(Result o) {
669             throw new UnsupportedOperationException();
670         }
671 
672         public void add(Result o) {
673             throw new UnsupportedOperationException();
674         }
675     }
676 
677 }