1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.mybatis.caches.ehcache;
17
18 import java.io.Serializable;
19 import java.nio.file.Path;
20 import java.time.Duration;
21 import java.util.concurrent.locks.ReadWriteLock;
22
23 import org.apache.ibatis.cache.Cache;
24 import org.ehcache.Cache.Entry;
25 import org.ehcache.PersistentCacheManager;
26 import org.ehcache.config.builders.CacheConfigurationBuilder;
27 import org.ehcache.config.builders.CacheManagerBuilder;
28 import org.ehcache.config.builders.ExpiryPolicyBuilder;
29 import org.ehcache.config.builders.ResourcePoolsBuilder;
30 import org.ehcache.config.units.EntryUnit;
31 import org.ehcache.config.units.MemoryUnit;
32
33
34
35
36
37
38 public abstract class AbstractEhcacheCache implements Cache {
39
40
41 private static final Object NULL_VALUE = new NullValue();
42
43
44
45
46
47 protected static PersistentCacheManager CACHE_MANAGER = CacheManagerBuilder.newCacheManagerBuilder()
48 .with(
49 CacheManagerBuilder.persistence(Path.of(System.getProperty("java.io.tmpdir"), "ehcache-mybatis").toString()))
50 .build(true);
51
52
53
54
55 protected final String id;
56
57
58
59
60 protected org.ehcache.Cache<Object, Object> cache;
61
62 protected long timeToIdleSeconds;
63 protected long timeToLiveSeconds;
64 protected long maxEntriesLocalHeap;
65 protected long maxEntriesLocalDisk;
66 protected long maxBytesLocalDisk;
67 protected String memoryStoreEvictionPolicy;
68
69
70
71
72
73
74
75 protected AbstractEhcacheCache(final String id) {
76 if (id == null) {
77 throw new IllegalArgumentException("Cache instances require an ID");
78 }
79 this.id = id;
80
81 if (CACHE_MANAGER.getCache(id, Object.class, Object.class) != null) {
82 CACHE_MANAGER.removeCache(id);
83 }
84 }
85
86
87
88
89 protected synchronized org.ehcache.Cache<Object, Object> getOrCreateCache() {
90 if (cache == null) {
91 cache = buildAndRegisterCache();
92 }
93 return cache;
94 }
95
96
97
98
99 protected org.ehcache.Cache<Object, Object> buildAndRegisterCache() {
100 if (CACHE_MANAGER.getCache(id, Object.class, Object.class) != null) {
101 CACHE_MANAGER.removeCache(id);
102 }
103 long heapEntries = maxEntriesLocalHeap > 0 ? maxEntriesLocalHeap : Long.MAX_VALUE / 2;
104 ResourcePoolsBuilder poolsBuilder = ResourcePoolsBuilder.newResourcePoolsBuilder().heap(heapEntries,
105 EntryUnit.ENTRIES);
106 if (maxBytesLocalDisk > 0) {
107 poolsBuilder = poolsBuilder.disk(maxBytesLocalDisk, MemoryUnit.B);
108 }
109 CacheConfigurationBuilder<Object, Object> builder = CacheConfigurationBuilder
110 .newCacheConfigurationBuilder(Object.class, Object.class, poolsBuilder).withExpiry(buildExpiryPolicy());
111 if (maxBytesLocalDisk > 0) {
112
113
114 builder = builder.withKeySerializer(ObjectSerializer.class).withValueSerializer(ObjectSerializer.class);
115 }
116 CACHE_MANAGER.createCache(id, builder.build());
117 return CACHE_MANAGER.getCache(id, Object.class, Object.class);
118 }
119
120 private org.ehcache.expiry.ExpiryPolicy<Object, Object> buildExpiryPolicy() {
121 if (timeToLiveSeconds > 0) {
122 return ExpiryPolicyBuilder.timeToLiveExpiration(Duration.ofSeconds(timeToLiveSeconds));
123 }
124 if (timeToIdleSeconds > 0) {
125 return ExpiryPolicyBuilder.timeToIdleExpiration(Duration.ofSeconds(timeToIdleSeconds));
126 }
127 return ExpiryPolicyBuilder.noExpiration();
128 }
129
130 @Override
131 public void clear() {
132 getOrCreateCache().clear();
133 }
134
135 @Override
136 public String getId() {
137 return id;
138 }
139
140 @Override
141 public Object getObject(Object key) {
142 Object value = getOrCreateCache().get(new HashKeyWrapper(key));
143 return value instanceof NullValue ? null : value;
144 }
145
146 @Override
147 public int getSize() {
148 int size = 0;
149 for (@SuppressWarnings("unused")
150 Entry<Object, Object> entry : getOrCreateCache()) {
151 size++;
152 }
153 return size;
154 }
155
156 @Override
157 public void putObject(Object key, Object value) {
158 getOrCreateCache().put(new HashKeyWrapper(key), value == null ? NULL_VALUE : value);
159 }
160
161 @Override
162 public Object removeObject(Object key) {
163 Object obj = getObject(key);
164 getOrCreateCache().remove(new HashKeyWrapper(key));
165 return obj;
166 }
167
168 @Override
169 public boolean equals(Object obj) {
170 if (this == obj) {
171 return true;
172 }
173 if (obj == null) {
174 return false;
175 }
176 if (!(obj instanceof Cache)) {
177 return false;
178 }
179
180 Cache otherCache = (Cache) obj;
181 return id.equals(otherCache.getId());
182 }
183
184 @Override
185 public int hashCode() {
186 return id.hashCode();
187 }
188
189 @Override
190 public ReadWriteLock getReadWriteLock() {
191 return null;
192 }
193
194 @Override
195 public String toString() {
196 return "EHCache {" + id + "}";
197 }
198
199
200
201
202
203
204
205
206
207
208 public void setTimeToIdleSeconds(long timeToIdleSeconds) {
209 this.timeToIdleSeconds = timeToIdleSeconds;
210 recreateCacheIfInitialized();
211 }
212
213
214
215
216
217
218
219
220 public void setTimeToLiveSeconds(long timeToLiveSeconds) {
221 this.timeToLiveSeconds = timeToLiveSeconds;
222 recreateCacheIfInitialized();
223 }
224
225
226
227
228
229
230
231
232 public void setMaxEntriesLocalHeap(long maxEntriesLocalHeap) {
233 this.maxEntriesLocalHeap = maxEntriesLocalHeap;
234 recreateCacheIfInitialized();
235 }
236
237
238
239
240
241
242
243
244
245
246
247 public void setMaxEntriesLocalDisk(long maxEntriesLocalDisk) {
248 this.maxEntriesLocalDisk = maxEntriesLocalDisk;
249 recreateCacheIfInitialized();
250 }
251
252
253
254
255
256
257
258
259
260 public void setMaxBytesLocalDisk(long maxBytesLocalDisk) {
261 this.maxBytesLocalDisk = maxBytesLocalDisk;
262 recreateCacheIfInitialized();
263 }
264
265
266
267
268
269
270
271 public void setMemoryStoreEvictionPolicy(String memoryStoreEvictionPolicy) {
272 this.memoryStoreEvictionPolicy = memoryStoreEvictionPolicy;
273 recreateCacheIfInitialized();
274 }
275
276
277
278
279
280 protected synchronized void recreateCacheIfInitialized() {
281 if (cache != null) {
282 cache = buildAndRegisterCache();
283 }
284 }
285
286
287
288
289
290 private static final class NullValue implements Serializable {
291 private static final long serialVersionUID = 1L;
292 }
293
294 }