Project

General

Profile

Download (10.3 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
 * Copyright (C) 2014 EDIT
3
 * European Distributed Institute of Taxonomy
4
 * http://www.e-taxonomy.eu
5
 *
6
 * The contents of this file are subject to the Mozilla Public License Version 1.1
7
 * See LICENSE.TXT at the top of this package for the full license terms.
8
 */
9
package eu.etaxonomy.taxeditor.remoting.cache;
10

    
11
import java.util.ArrayList;
12
import java.util.Collection;
13
import java.util.HashMap;
14
import java.util.HashSet;
15
import java.util.List;
16
import java.util.Map;
17
import java.util.Set;
18
import java.util.UUID;
19

    
20
import net.sf.ehcache.Cache;
21
import net.sf.ehcache.CacheManager;
22
import net.sf.ehcache.Element;
23
import net.sf.ehcache.Status;
24
import net.sf.ehcache.config.CacheConfiguration;
25
import net.sf.ehcache.config.SizeOfPolicyConfiguration;
26
import net.sf.ehcache.statistics.LiveCacheStatistics;
27

    
28
import org.apache.log4j.Logger;
29

    
30
import eu.etaxonomy.cdm.api.application.CdmApplicationState;
31
import eu.etaxonomy.cdm.api.cache.CdmServiceCacher;
32
import eu.etaxonomy.cdm.api.service.UpdateResult;
33
import eu.etaxonomy.cdm.api.service.dto.CdmEntityIdentifier;
34
import eu.etaxonomy.cdm.model.ICdmCacher;
35
import eu.etaxonomy.cdm.model.common.CdmBase;
36
import eu.etaxonomy.cdm.persistence.dto.MergeResult;
37
import eu.etaxonomy.taxeditor.session.ICdmEntitySessionManager;
38

    
39
/**
40
 *
41
 * This cache guarantees that
42
 *  - all objects put will be ancestors of CdmBase
43
 *  - all CdmBase objects in the cache will be already de-proxied
44
 *  - after any CdmBase object is put in the cache,
45
 *  all non-null / non-proxy CdmBase objects in the sub-graph
46
 *  will also be present in the cache.
47
 *
48
 * @author cmathew
49
 * @date 14 Oct 2014
50
 *
51
 */
52

    
53
public class CdmTransientEntityCacher implements ICdmCacher {
54

    
55
    private static final Logger logger = Logger.getLogger(CdmTransientEntityCacher.class);
56

    
57

    
58
    private final ICdmEntitySessionManager cdmEntitySessionManager;
59

    
60
    private static CdmServiceCacher cdmServiceCacher;
61

    
62
    private final String cacheId;
63

    
64
    private final Cache cache;
65

    
66
    private final CacheLoader cacheLoader;
67

    
68
    private final Map<UUID, CdmBase> newEntitiesMap = new HashMap<UUID, CdmBase>();
69

    
70
    public CdmTransientEntityCacher(String cacheId, ICdmEntitySessionManager cdmEntitySessionManager) {
71
        this.cacheId = cacheId;
72

    
73
        cache = new Cache(getEntityCacheConfiguration(cacheId));
74

    
75
        CacheManager.create().removeCache(cache.getName());
76
        CacheManager.create().addCache(cache);
77

    
78
        this.cdmEntitySessionManager = cdmEntitySessionManager;
79

    
80
        cacheLoader = new CacheLoader(this);
81

    
82
    }
83

    
84
    public CdmTransientEntityCacher(Object sessionOwner, ICdmEntitySessionManager cdmEntitySessionManager) {
85
        this(generateCacheId(sessionOwner), cdmEntitySessionManager);
86
    }
87

    
88
    public static String generateCacheId(Object sessionOwner) {
89
        return sessionOwner.getClass().getName() +  String.valueOf(sessionOwner.hashCode());
90
    }
91

    
92
    /**
93
     * Returns the default cache configuration.
94
     *
95
     * @return
96
     */
97
    private CacheConfiguration getEntityCacheConfiguration(String cacheId) {
98
        SizeOfPolicyConfiguration sizeOfConfig = new SizeOfPolicyConfiguration();
99
        sizeOfConfig.setMaxDepth(100);
100
        sizeOfConfig.setMaxDepthExceededBehavior("abort");
101

    
102
        return new CacheConfiguration(cacheId, 0)
103
        .eternal(true)
104
        .statistics(true)
105
        .sizeOfPolicy(sizeOfConfig)
106
        .overflowToOffHeap(false);
107

    
108
    }
109

    
110
    public static void setDefaultCacher(CdmServiceCacher css) {
111
        cdmServiceCacher = css;
112
    }
113

    
114
    public LiveCacheStatistics getCacheStatistics() {
115
        if(cache.getStatus() == Status.STATUS_ALIVE) {
116
            return cache.getLiveCacheStatistics();
117
        }
118
        return null;
119

    
120
    }
121

    
122
    /**
123
     * Returns the cache corresponding to the cache id
124
     *
125
     * @param cacheId
126
     * @return
127
     */
128
    private Cache getCache() {
129
        return  CacheManager.create().getCache(cacheId);
130
    }
131

    
132
    public <T extends Object> T load(T obj, boolean update) {
133
        return cacheLoader.load(obj, true, update);
134
    }
135

    
136
    public <T extends Object> Map<T,T> load(Map<T,T> map, boolean update){
137
        return cacheLoader.load(map, true, update);
138
    }
139

    
140
    public <T extends Object> Collection<T> load(Collection<T> collection, boolean update){
141
        return cacheLoader.load(collection, true, update);
142
    }
143

    
144
    public CdmBase load(CdmBase cdmEntity, boolean update) {
145
        return cacheLoader.load(cdmEntity, true, update);
146
    }
147

    
148

    
149
    private CdmBase load(CdmEntityIdentifier cei, boolean update) {
150
        return CdmApplicationState.getCommonService().findWithUpdate(cei.getCdmClass(), cei.getId());
151
    }
152

    
153

    
154
    public UpdateResult load(UpdateResult result, boolean update) {
155
        // probably a good time to broadcast to other sessions
156

    
157
        Set<CdmBase> updatedObjects = result.getUpdatedObjects();
158
        Set<CdmBase> reloadedObjects = new HashSet<CdmBase>();
159
        Set<CdmEntityIdentifier> updatedCdmIds = result.getUpdatedCdmIds();
160
        boolean updatedCdmIdsIsEmpty = updatedCdmIds.isEmpty();
161

    
162
        // if the cdm identifier set contains identifiers of objects already
163
        // present in the updated objects set reomve them
164
        for(CdmBase updatedObject : updatedObjects) {
165
            if(updatedObject != null && exists(new CdmEntityCacheKey(updatedObject.getClass(), updatedObject.getId()))) {
166
                CdmEntityIdentifier cdmEntityIdentifier = new CdmEntityIdentifier(updatedObject.getId(), updatedObject.getClass());
167
                if(!updatedCdmIdsIsEmpty && updatedCdmIds.contains(cdmEntityIdentifier)) {
168
                    updatedCdmIds.remove(cdmEntityIdentifier);
169
                }
170
                reloadedObjects.add(cacheLoader.load(updatedObject, true, update));
171
            }
172
        }
173

    
174
        // remote load cdm identifiers of objects which already exist
175
        // in the cache
176

    
177
        for(CdmEntityIdentifier cei : updatedCdmIds) {
178
            if(exists(new CdmEntityCacheKey(cei.getCdmClass(), cei.getId()))) {
179
                reloadedObjects.add(load(cei, update));
180
            }
181

    
182
        }
183
        updatedObjects.clear();
184
        result.addUpdatedObjects(reloadedObjects);
185
        return result;
186
    }
187

    
188
    public MergeResult<CdmBase> load(MergeResult<CdmBase> mergeResult, boolean update) {
189
        return cacheLoader.load(mergeResult, true, update);
190
    }
191

    
192
    public CdmModelFieldPropertyFromClass getFromCdmlibModelCache(String className) {
193
        return cacheLoader.getFromCdmlibModelCache(className);
194
    }
195

    
196

    
197
    public void addNewEntity(CdmBase newEntity) {
198
        if(newEntity != null && newEntity.getId() == 0 && newEntity.getUuid() != null) {
199
            newEntitiesMap.put(newEntity.getUuid(), newEntity);
200
        }
201
    }
202

    
203
    @Override
204
    public void put(CdmBase cdmEntity) {
205

    
206
        CdmBase cachedCdmEntity = cdmServiceCacher.load(cdmEntity);
207
        if(cachedCdmEntity != null) {
208
            logger.info("Cdm Entity with id : " + cdmEntity.getId() + " already exists in permanent cache. Ignoring put.");
209
            return;
210
        }
211
        CdmEntityCacheKey id = new CdmEntityCacheKey(cdmEntity);
212

    
213
        cachedCdmEntity = getFromCache(id);
214
        if(cachedCdmEntity == null) {
215
            CdmBase cdmEntityToCache = cdmEntity;
216
            CdmBase newEntity = newEntitiesMap.get(cdmEntity.getUuid());
217
            if(newEntity != null) {
218
                newEntity.setId(cdmEntity.getId());
219
                cdmEntityToCache = newEntity;
220
            }
221
            getCache().put(new Element(id, cdmEntityToCache));
222
            cdmEntityToCache.initListener();
223
            newEntitiesMap.remove(cdmEntity.getUuid());
224
            logger.info(" - object of type " + cdmEntityToCache.getClass().getName() + " with id " + cdmEntityToCache.getId() + " put in cache");
225
            return;
226
        }
227
        logger.info(" - object of type " + cdmEntity.getClass().getName() + " with id " + cdmEntity.getId() + " already exists");
228
    }
229

    
230

    
231
    private Element getCacheElement(CdmEntityCacheKey key) {
232
        return getCache().get(key);
233
    }
234

    
235

    
236
    public CdmBase getFromCache(CdmEntityCacheKey id) {
237
        Element e = getCacheElement(id);
238

    
239
        if (e == null) {
240
            return null;
241
        } else {
242
            return (CdmBase) e.getObjectValue();
243
        }
244
    }
245

    
246
    public CdmBase getFromCache(Class<? extends CdmBase> clazz, int id) {
247
        CdmEntityCacheKey cacheId = generateKey(clazz,id);
248
        return getFromCache(cacheId);
249
    }
250

    
251
    @Override
252
    public CdmBase getFromCache(CdmBase cdmBase) {
253

    
254
        CdmEntityCacheKey cacheId = generateKey((CdmBase)ProxyUtils.deproxy(cdmBase));
255
        // first try this cache
256
        CdmBase  cachedCdmEntity = getFromCache(cacheId);
257

    
258
        if(cachedCdmEntity == null) {
259
            // ... then try the permanent cache
260
            cachedCdmEntity = cdmServiceCacher.getFromCache(cdmBase.getUuid());
261
        }
262

    
263
        return cachedCdmEntity;
264
    }
265

    
266
    public CdmBase getFromCache(CdmBase cdmBase, Class<? extends CdmBase> clazz) {
267

    
268
        cdmBase = CdmBase.deproxy(cdmBase, clazz);
269
        return getFromCache(cdmBase);
270
    }
271

    
272
    public List<CdmBase> getAllEntities() {
273
        List<CdmBase> entities = new ArrayList<CdmBase>();
274
        Map<String, CdmBase> elementsMap = getCache().getAllWithLoader(getCache().getKeys(), null);
275
        for (Map.Entry<String, CdmBase> entry : elementsMap.entrySet()) {
276
            entities.add(entry.getValue());
277
        }
278
        return entities;
279
    }
280

    
281
    public boolean exists(CdmEntityCacheKey key) {
282
        return (getCacheElement(key) != null);
283
    }
284

    
285
    public boolean existsAndIsNotNull(CdmEntityCacheKey id) {
286
        return getFromCache(id) != null;
287
    }
288

    
289
    public void clear() {
290
        cache.removeAll();
291
    }
292

    
293
    public void dispose() {
294
        CacheManager.create().removeCache(cache.getName());
295
        cache.dispose();
296
        newEntitiesMap.clear();
297

    
298
    }
299

    
300

    
301
    public static CdmEntityCacheKey generateKey(Class<? extends CdmBase> clazz, int id) {
302
        return new CdmEntityCacheKey(clazz, id);
303
    }
304

    
305

    
306
    public static CdmEntityCacheKey generateKey(CdmBase cdmBase) {
307
        Class<? extends CdmBase> entityClass = cdmBase.getClass();
308
        int id = cdmBase.getId();
309
        return new CdmEntityCacheKey(entityClass, id);
310
    }
311

    
312
    @Override
313
    public CdmBase load(CdmBase cdmEntity) {
314
        return load(cdmEntity, true);
315
    }
316

    
317
    @Override
318
    public boolean isCachable(CdmBase cdmEntity) {
319
        return true;
320
    }
321

    
322
    @Override
323
    public boolean exists(CdmBase cdmBase) {
324
        return exists(generateKey(cdmBase));
325
    }
326

    
327

    
328

    
329
}
(8-8/10)