View Javadoc

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