View Javadoc

1   /**
2    *  Copyright 2003-2007 Greg Luck
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.hibernate;
17  
18  
19  import net.sf.ehcache.Element;
20  import org.apache.commons.logging.Log;
21  import org.apache.commons.logging.LogFactory;
22  import org.hibernate.cache.Cache;
23  import org.hibernate.cache.CacheException;
24  import org.hibernate.cache.Timestamper;
25  
26  import java.util.HashMap;
27  import java.util.Iterator;
28  import java.util.Map;
29  
30  /**
31   * EHCache plugin for Hibernate.
32   * <p/>
33   * EHCache uses a {@link net.sf.ehcache.store.MemoryStore} and a
34   * {@link net.sf.ehcache.store.DiskStore}.
35   * <p/>
36   * The {@link net.sf.ehcache.store.DiskStore} requires that both keys and values be {@link java.io.Serializable}.
37   * However the MemoryStore does not and in ehcache-1.2 nonSerializable Objects are permitted. They are discarded
38   * if an attempt it made to overflow them to Disk or to replicate them to remote cache peers.
39   * <p/>
40   *
41   * @author Greg Luck
42   * @author Emmanuel Bernard
43   * @version $Id: EhCache.java 512 2007-07-10 09:18:45Z gregluck $
44   */
45  public final class EhCache implements Cache {
46  
47      private static final Log LOG = LogFactory.getLog(EhCache.class);
48  
49      private static final int SIXTY_THOUSAND_MS = 60000;
50  
51      private final net.sf.ehcache.Ehcache cache;
52  
53      /**
54       * Creates a new Hibernate pluggable cache by name.
55       * <p/>
56       * ehcache will look in ehcache.xml to load the configuration for the cache.
57       * If the cache is not there, it will use the defaultCache settings. It is
58       * always a good idea to specifically configure each cache.
59       *
60       * @param cache The backing ehcache cache.
61       */
62      public EhCache(net.sf.ehcache.Ehcache cache) {
63          this.cache = cache;
64      }
65  
66      /**
67       * Gets a value of an element which matches the given key.
68       *
69       * @param key the key of the element to return.
70       * @return The value placed into the cache with an earlier put, or null if not found or expired
71       * @throws org.hibernate.cache.CacheException
72       *
73       */
74      public final Object get(Object key) throws CacheException {
75          try {
76              if (LOG.isDebugEnabled()) {
77                  LOG.debug("key: " + key);
78              }
79              if (key == null) {
80                  return null;
81              } else {
82                  Element element = cache.get(key);
83                  if (element == null) {
84                      if (LOG.isDebugEnabled()) {
85                          LOG.debug("Element for " + key + " is null");
86                      }
87                      return null;
88                  } else {
89                      return element.getObjectValue();
90                  }
91              }
92          } catch (net.sf.ehcache.CacheException e) {
93              throw new CacheException(e);
94          }
95      }
96  
97      /**
98       * Gets an object from the cache.
99       *
100      * @param key an Object value
101      * @return the Object, or null if not found
102      * @throws CacheException
103      */
104     public final Object read(Object key) throws CacheException {
105         return get(key);
106     }
107 
108 
109     /**
110      * Updates an object in the cache, or if it does not exist, inserts it.
111      *
112      * @param key   an Object key
113      * @param value an Object value
114      * @throws CacheException if the {@link net.sf.ehcache.CacheManager} is shutdown or another {@link Exception} occurs.
115      */
116     public final void update(Object key, Object value) throws CacheException {
117         put(key, value);
118     }
119 
120     /**
121      * Puts an object into the cache.
122      *
123      * @param key   an Object key
124      * @param value an Object value
125      * @throws CacheException if the {@link net.sf.ehcache.CacheManager} is shutdown or another {@link Exception} occurs.
126      */
127     public final void put(Object key, Object value) throws CacheException {
128         try {
129             Element element = new Element(key, value);
130             cache.put(element);
131         } catch (IllegalArgumentException e) {
132             throw new CacheException(e);
133         } catch (IllegalStateException e) {
134             throw new CacheException(e);
135         }
136 
137     }
138 
139     /**
140      * Removes the element which matches the key.
141      * <p/>
142      * If no element matches, nothing is removed and no Exception is thrown.
143      *
144      * @param key the key of the element to remove
145      * @throws CacheException
146      */
147     public final void remove(Object key) throws CacheException {
148         try {
149             cache.remove(key);
150         } catch (ClassCastException e) {
151             throw new CacheException(e);
152         } catch (IllegalStateException e) {
153             throw new CacheException(e);
154         }
155     }
156 
157     /**
158      * Remove all elements in the cache, but leave the cache in a useable state.
159      *
160      * @throws CacheException
161      */
162     public final void clear() throws CacheException {
163         try {
164             cache.removeAll();
165         } catch (IllegalStateException e) {
166             throw new CacheException(e);
167         }
168     }
169 
170     /**
171      * Remove the cache and make it unuseable.
172      *
173      * @throws CacheException
174      */
175     public final void destroy() throws CacheException {
176         try {
177             cache.getCacheManager().removeCache(cache.getName());
178         } catch (IllegalStateException e) {
179             throw new CacheException(e);
180         } catch (net.sf.ehcache.CacheException e) {
181             throw new CacheException(e);
182         }
183     }
184 
185     /**
186      * Calls to this method should perform their own synchronization.
187      * It is provided for distributed caches.
188      * <p/>
189      * ehcache does not support distributed locking and therefore this method does nothing.
190      */
191     public final void lock(Object key) throws CacheException {
192         //noop
193     }
194 
195     /**
196      * Calls to this method should perform their own synchronization.
197      * <p/>
198      * ehcache does not support distributed locking and therefore this method does nothing.
199      */
200     public final void unlock(Object key) throws CacheException {
201         //noop
202     }
203 
204     /**
205      * Gets the next timestamp;
206      */
207     public final long nextTimestamp() {
208         return Timestamper.next();
209     }
210 
211     /**
212      * Returns the lock timeout for this cache, which is 60s
213      */
214     public final int getTimeout() {
215         // 60 second lock timeout
216         return Timestamper.ONE_MS * SIXTY_THOUSAND_MS;
217     }
218 
219     /**
220      * @return the region name of the cache, which is the cache name in ehcache
221      */
222     public final String getRegionName() {
223         return cache.getName();
224     }
225 
226     /**
227      * Warning: This method can be very expensive to run. Allow approximately 1 second
228      * per 1MB of entries. Running this method could create liveness problems
229      * because the object lock is held for a long period
230      * <p/>
231      *
232      * @return the approximate size of memory ehcache is using for the MemoryStore for this cache
233      */
234     public final long getSizeInMemory() {
235         try {
236             return cache.calculateInMemorySize();
237         } catch (Throwable t) {
238             return -1;
239         }
240     }
241 
242     /**
243      * @return the number of elements in ehcache's MemoryStore
244      */
245     public final long getElementCountInMemory() {
246         try {
247             return cache.getMemoryStoreSize();
248         } catch (net.sf.ehcache.CacheException ce) {
249             throw new CacheException(ce);
250         }
251     }
252 
253     /**
254      * @return the number of elements in ehcache's DiskStore. 0 is there is no DiskStore
255      */
256     public final long getElementCountOnDisk() {
257         return cache.getDiskStoreSize();
258     }
259 
260 
261     /**
262      * @return a copy of the cache Elements as a Map
263      */
264     public final Map toMap() {
265         try {
266             Map result = new HashMap();
267             Iterator iter = cache.getKeys().iterator();
268             while (iter.hasNext()) {
269                 Object key = iter.next();
270                 result.put(key, cache.get(key).getObjectValue());
271             }
272             return result;
273         } catch (Exception e) {
274             throw new CacheException(e);
275         }
276     }
277 
278     /**
279      * @return the region name, which is the cache name in ehcache
280      */
281     public final String toString() {
282         return "EHCache(" + getRegionName() + ')';
283     }
284 
285     /**
286      * Package protected method used for testing
287      */
288     final net.sf.ehcache.Ehcache getBackingCache() {
289         return cache;
290     }
291 
292 }