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
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
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
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 }