9239fcdce48ce47e61be4c54d7792f129adaee8c
[taxeditor.git] / eu.etaxonomy.taxeditor.cdmlib / src / main / java / eu / etaxonomy / taxeditor / remoting / cache / CdmTransientEntityCacher.java
1 // $Id$
2 /**
3 * Copyright (C) 2014 EDIT
4 * European Distributed Institute of Taxonomy
5 * http://www.e-taxonomy.eu
6 *
7 * The contents of this file are subject to the Mozilla Public License Version 1.1
8 * See LICENSE.TXT at the top of this package for the full license terms.
9 */
10 package eu.etaxonomy.taxeditor.remoting.cache;
11
12 import java.util.ArrayList;
13 import java.util.Collection;
14 import java.util.List;
15 import java.util.Map;
16
17 import net.sf.ehcache.Cache;
18 import net.sf.ehcache.CacheManager;
19 import net.sf.ehcache.Element;
20 import net.sf.ehcache.config.CacheConfiguration;
21 import net.sf.ehcache.config.SizeOfPolicyConfiguration;
22 import net.sf.ehcache.statistics.LiveCacheStatistics;
23
24 import org.apache.log4j.Logger;
25
26 import eu.etaxonomy.cdm.api.cache.CdmServiceCacher;
27 import eu.etaxonomy.cdm.model.ICdmCacher;
28 import eu.etaxonomy.cdm.model.common.CdmBase;
29 import eu.etaxonomy.taxeditor.session.ICdmEntitySessionManager;
30
31 /**
32 *
33 * This cache guarantees that
34 * - all objects put will be ancestors of CdmBase
35 * - all CdmBase objects in the cache will be already de-proxied
36 * - after any CdmBase object is put in the cache,
37 * all non-null / non-proxy CdmBase objects in the sub-graph
38 * will also be present in the cache.
39 *
40 * @author cmathew
41 * @date 14 Oct 2014
42 *
43 */
44
45 public class CdmTransientEntityCacher implements ICdmCacher {
46
47 private static final Logger logger = Logger.getLogger(CdmTransientEntityCacher.class);
48
49
50 private final ICdmEntitySessionManager cdmEntitySessionManager;
51
52 private static CdmServiceCacher cdmServiceCacher;
53
54 private final String cacheId;
55
56 private final Cache cache;
57
58 private final CacheLoader cacheLoader;
59
60
61
62 public CdmTransientEntityCacher(String cacheId, ICdmEntitySessionManager cdmEntitySessionManager) {
63 this.cacheId = cacheId;
64
65 cache = new Cache(getEntityCacheConfiguration(cacheId));
66
67 CacheManager.create().addCache(cache);
68
69 this.cdmEntitySessionManager = cdmEntitySessionManager;
70
71 cacheLoader = new CacheLoader(this);
72 }
73
74 public CdmTransientEntityCacher(Object sessionOwner, ICdmEntitySessionManager cdmEntitySessionManager) {
75 this(generateCacheId(sessionOwner), cdmEntitySessionManager);
76 }
77
78 public static String generateCacheId(Object sessionOwner) {
79 return sessionOwner.getClass().getName() + String.valueOf(sessionOwner.hashCode());
80 }
81
82 /**
83 * Returns the default cache configuration.
84 *
85 * @return
86 */
87 private CacheConfiguration getEntityCacheConfiguration(String cacheId) {
88 SizeOfPolicyConfiguration sizeOfConfig = new SizeOfPolicyConfiguration();
89 sizeOfConfig.setMaxDepth(10000);
90 sizeOfConfig.setMaxDepthExceededBehavior("abort");
91
92 return new CacheConfiguration(cacheId, 0)
93 .eternal(true)
94 .statistics(true)
95 .sizeOfPolicy(sizeOfConfig)
96 .overflowToOffHeap(false);
97
98 }
99
100 public static void setDefaultCacher(CdmServiceCacher css) {
101 cdmServiceCacher = css;
102 }
103
104 public LiveCacheStatistics getCacheStatistics() {
105 return cache.getLiveCacheStatistics();
106 }
107
108 /**
109 * Returns the cache corresponding to the cache id
110 *
111 * @param cacheId
112 * @return
113 */
114 private Cache getCache() {
115 return CacheManager.create().getCache(cacheId);
116 }
117
118 public <T extends Object> T load(T obj, boolean update) {
119 return cacheLoader.load(obj, true, update);
120 }
121
122 public <T extends Object> Map<T,T> load(Map<T,T> map, boolean update){
123 return cacheLoader.load(map, true, update);
124 }
125
126 public <T extends Object> Collection<T> load(Collection<T> collection, boolean update){
127 return cacheLoader.load(collection, true, update);
128 }
129
130 public CdmBase load(CdmBase cdmEntity, boolean update) {
131 return cacheLoader.load(cdmEntity, true, update);
132 }
133
134 public CdmModelFieldPropertyFromClass getFromCdmlibModelCache(String className) {
135 return cacheLoader.getFromCdmlibModelCache(className);
136 }
137
138
139
140
141 @Override
142 public void put(CdmBase cdmEntity) {
143
144 CdmBase cachedCdmEntity = cdmServiceCacher.load(cdmEntity);
145 if(cachedCdmEntity != null) {
146 logger.info("Cdm Entity with id : " + cdmEntity.getId() + " already exists in permanent cache. Ignoring put.");
147 return;
148 }
149 CdmEntityCacheKey id = new CdmEntityCacheKey(cdmEntity);
150
151 cachedCdmEntity = getFromCache(id);
152 if(cachedCdmEntity == null) {
153 getCache().put(new Element(id, cdmEntity));
154 logger.info(" - object of type " + cdmEntity.getClass().getName() + " with id " + cdmEntity.getId() + " put in cache");
155 return;
156 }
157 logger.info(" - object of type " + cdmEntity.getClass().getName() + " with id " + cdmEntity.getId() + " already exists");
158 }
159
160
161 private Element getCacheElement(CdmEntityCacheKey key) {
162 return getCache().get(key);
163 }
164
165
166 public CdmBase getFromCache(CdmEntityCacheKey id) {
167 Element e = getCacheElement(id);
168
169 if (e == null) {
170 return null;
171 } else {
172 return (CdmBase) e.getObjectValue();
173 }
174 }
175
176 public CdmBase getFromCache(Class<? extends CdmBase> clazz, int id) {
177 CdmEntityCacheKey cacheId = generateKey(clazz,id);
178 return getFromCache(cacheId);
179 }
180
181 @Override
182 public CdmBase getFromCache(CdmBase cdmBase) {
183
184 CdmEntityCacheKey cacheId = generateKey(cdmBase);
185 // first try this cache
186 CdmBase cachedCdmEntity = getFromCache(cacheId);
187
188 if(cachedCdmEntity == null) {
189 // ... then try the permanent cache
190 cachedCdmEntity = cdmServiceCacher.getFromCache(cdmBase.getUuid());
191 }
192
193 return cachedCdmEntity;
194 }
195
196 public CdmBase getFromCache(CdmBase cdmBase, Class<? extends CdmBase> clazz) {
197
198 cdmBase = CdmBase.deproxy(cdmBase, clazz);
199 return getFromCache(cdmBase);
200 }
201
202 public List<CdmBase> getAllEntities() {
203 List<CdmBase> entities = new ArrayList<CdmBase>();
204 Map<String, CdmBase> elementsMap = getCache().getAllWithLoader(getCache().getKeys(), null);
205 for (Map.Entry<String, CdmBase> entry : elementsMap.entrySet()) {
206 entities.add(entry.getValue());
207 }
208 return entities;
209 }
210
211 public boolean exists(CdmEntityCacheKey key) {
212 return (getCacheElement(key) != null);
213 }
214
215 public boolean existsAndIsNotNull(CdmEntityCacheKey id) {
216 return getFromCache(id) != null;
217 }
218
219 public void clear() {
220 cache.removeAll();
221 }
222
223 public void dispose() {
224 cache.dispose();
225
226 }
227
228
229 public static CdmEntityCacheKey generateKey(Class<? extends CdmBase> clazz, int id) {
230 return new CdmEntityCacheKey(clazz, id);
231 }
232
233
234 public static CdmEntityCacheKey generateKey(CdmBase cdmBase) {
235 Class<? extends CdmBase> entityClass = cdmBase.getClass();
236 int id = cdmBase.getId();
237 return new CdmEntityCacheKey(entityClass, id);
238 }
239
240 /* (non-Javadoc)
241 * @see eu.etaxonomy.cdm.model.ICdmCacher#load(eu.etaxonomy.cdm.model.common.CdmBase)
242 */
243 @Override
244 public CdmBase load(CdmBase cdmEntity) {
245 return load(cdmEntity, true);
246 }
247
248 /* (non-Javadoc)
249 * @see eu.etaxonomy.cdm.model.ICdmCacher#isCachable(eu.etaxonomy.cdm.model.common.CdmBase)
250 */
251 @Override
252 public boolean isCachable(CdmBase cdmEntity) {
253 return true;
254 }
255
256 /* (non-Javadoc)
257 * @see eu.etaxonomy.cdm.model.ICdmCacher#exists(eu.etaxonomy.cdm.model.common.CdmBase)
258 */
259 @Override
260 public boolean exists(CdmBase cdmBase) {
261 return exists(generateKey(cdmBase));
262 }
263
264
265
266 }