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 }