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.hibernate.regions;
17
18 import java.util.Properties;
19
20 import net.sf.ehcache.Ehcache;
21 import net.sf.ehcache.Element;
22 import net.sf.ehcache.concurrent.CacheLockProvider;
23 import net.sf.ehcache.concurrent.LockType;
24 import net.sf.ehcache.concurrent.StripedReadWriteLockSync;
25 import net.sf.ehcache.constructs.nonstop.NonStopCacheException;
26 import net.sf.ehcache.hibernate.nonstop.HibernateNonstopCacheExceptionHandler;
27 import net.sf.ehcache.hibernate.strategy.EhcacheAccessStrategyFactory;
28
29 import org.hibernate.cache.CacheDataDescription;
30 import org.hibernate.cache.CacheException;
31 import org.hibernate.cache.TransactionalDataRegion;
32 import org.hibernate.cache.access.SoftLock;
33 import org.hibernate.cfg.Settings;
34
35 /***
36 * An Ehcache specific TransactionalDataRegion.
37 * <p>
38 * This is the common superclass entity and collection regions.
39 *
40 * @author Chris Dennis
41 * @author Greg Luck
42 * @author Emmanuel Bernard
43 * @author Abhishek Sanoujam
44 */
45 public class EhcacheTransactionalDataRegion extends EhcacheDataRegion implements TransactionalDataRegion {
46
47 private static final int LOCAL_LOCK_PROVIDER_CONCURRENCY = 128;
48
49 /***
50 * Hibernate settings associated with the persistence unit.
51 */
52 protected final Settings settings;
53
54 /***
55 * Metadata associated with the objects stored in the region.
56 */
57 protected final CacheDataDescription metadata;
58
59 private final CacheLockProvider lockProvider;
60
61 /***
62 * Construct an transactional Hibernate cache region around the given Ehcache instance.
63 */
64 EhcacheTransactionalDataRegion(EhcacheAccessStrategyFactory accessStrategyFactory, Ehcache cache, Settings settings,
65 CacheDataDescription metadata, Properties properties) {
66 super(accessStrategyFactory, cache, properties);
67 this.settings = settings;
68 this.metadata = metadata;
69
70 Object context = cache.getInternalContext();
71 if (context instanceof CacheLockProvider) {
72 this.lockProvider = (CacheLockProvider) context;
73 } else {
74 this.lockProvider = new StripedReadWriteLockSync(LOCAL_LOCK_PROVIDER_CONCURRENCY);
75 }
76 }
77
78 /***
79 * Return the hibernate settings
80 *
81 * @return settings
82 */
83 public Settings getSettings() {
84 return settings;
85 }
86
87 /***
88 * {@inheritDoc}
89 */
90 public boolean isTransactionAware() {
91 return false;
92 }
93
94 /***
95 * {@inheritDoc}
96 */
97 public CacheDataDescription getCacheDataDescription() {
98 return metadata;
99 }
100
101 /***
102 * Get the value mapped to this key, or null if no value is mapped to this key.
103 */
104 public final Object get(Object key) {
105 try {
106 Element element = cache.get(key);
107 if (element == null) {
108 return null;
109 } else {
110 return element.getObjectValue();
111 }
112 } catch (net.sf.ehcache.CacheException e) {
113 if (e instanceof NonStopCacheException) {
114 HibernateNonstopCacheExceptionHandler.getInstance().handleNonstopCacheException((NonStopCacheException) e);
115 return null;
116 } else {
117 throw new CacheException(e);
118 }
119 }
120 }
121
122 /***
123 * Map the given value to the given key, replacing any existing mapping for this key
124 */
125 public final void put(Object key, Object value) throws CacheException {
126 try {
127 Element element = new Element(key, value);
128 if (value instanceof SoftLock) {
129 element.setPinned(true);
130 element.setEternal(true);
131 }
132 cache.put(element);
133 } catch (IllegalArgumentException e) {
134 throw new CacheException(e);
135 } catch (IllegalStateException e) {
136 throw new CacheException(e);
137 } catch (net.sf.ehcache.CacheException e) {
138 if (e instanceof NonStopCacheException) {
139 HibernateNonstopCacheExceptionHandler.getInstance().handleNonstopCacheException((NonStopCacheException) e);
140 } else {
141 throw new CacheException(e);
142 }
143 }
144 }
145
146 /***
147 * Remove the mapping for this key (if any exists).
148 */
149 public final void remove(Object key) throws CacheException {
150 try {
151 cache.remove(key);
152 } catch (ClassCastException e) {
153 throw new CacheException(e);
154 } catch (IllegalStateException e) {
155 throw new CacheException(e);
156 } catch (net.sf.ehcache.CacheException e) {
157 if (e instanceof NonStopCacheException) {
158 HibernateNonstopCacheExceptionHandler.getInstance().handleNonstopCacheException((NonStopCacheException) e);
159 } else {
160 throw new CacheException(e);
161 }
162 }
163 }
164
165 /***
166 * Remove all mapping from this cache region.
167 */
168 public final void clear() throws CacheException {
169 try {
170 cache.removeAll();
171 } catch (IllegalStateException e) {
172 throw new CacheException(e);
173 } catch (net.sf.ehcache.CacheException e) {
174 if (e instanceof NonStopCacheException) {
175 HibernateNonstopCacheExceptionHandler.getInstance().handleNonstopCacheException((NonStopCacheException) e);
176 } else {
177 throw new CacheException(e);
178 }
179 }
180 }
181
182 /***
183 * Attempts to write lock the mapping for the given key.
184 */
185 public final void writeLock(Object key) {
186 try {
187 lockProvider.getSyncForKey(key).lock(LockType.WRITE);
188 } catch (net.sf.ehcache.CacheException e) {
189 if (e instanceof NonStopCacheException) {
190 HibernateNonstopCacheExceptionHandler.getInstance().handleNonstopCacheException((NonStopCacheException) e);
191 } else {
192 throw new CacheException(e);
193 }
194 }
195 }
196
197 /***
198 * Attempts to write unlock the mapping for the given key.
199 */
200 public final void writeUnlock(Object key) {
201 try {
202 lockProvider.getSyncForKey(key).unlock(LockType.WRITE);
203 } catch (net.sf.ehcache.CacheException e) {
204 if (e instanceof NonStopCacheException) {
205 HibernateNonstopCacheExceptionHandler.getInstance().handleNonstopCacheException((NonStopCacheException) e);
206 } else {
207 throw new CacheException(e);
208 }
209 }
210 }
211
212 /***
213 * Attempts to read lock the mapping for the given key.
214 */
215 public final void readLock(Object key) {
216 try {
217 lockProvider.getSyncForKey(key).lock(LockType.WRITE);
218 } catch (net.sf.ehcache.CacheException e) {
219 if (e instanceof NonStopCacheException) {
220 HibernateNonstopCacheExceptionHandler.getInstance().handleNonstopCacheException((NonStopCacheException) e);
221 } else {
222 throw new CacheException(e);
223 }
224 }
225 }
226
227 /***
228 * Attempts to read unlock the mapping for the given key.
229 */
230 public final void readUnlock(Object key) {
231 try {
232 lockProvider.getSyncForKey(key).unlock(LockType.WRITE);
233 } catch (net.sf.ehcache.CacheException e) {
234 if (e instanceof NonStopCacheException) {
235 HibernateNonstopCacheExceptionHandler.getInstance().handleNonstopCacheException((NonStopCacheException) e);
236 } else {
237 throw new CacheException(e);
238 }
239 }
240 }
241
242 /***
243 * Returns <code>true</code> if the locks used by the locking methods of this region are the independent of the cache.
244 * <p>
245 * Independent locks are not locked by the cache when the cache is accessed directly. This means that for an independent lock
246 * lock holds taken through a region method will not block direct access to the cache via other means.
247 */
248 public final boolean locksAreIndependentOfCache() {
249 return lockProvider instanceof StripedReadWriteLockSync;
250 }
251 }