Project

General

Profile

Download (9.7 KB) Statistics
| Branch: | Tag: | Revision:
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.HashSet;
15
import java.util.List;
16
import java.util.Map;
17
import java.util.Set;
18

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

    
27
import org.apache.log4j.Logger;
28

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

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

    
51
public class CdmTransientEntityCacher implements ICdmCacher {
52

    
53
    private static final Logger logger = Logger.getLogger(CdmTransientEntityCacher.class);
54

    
55

    
56
    private final ICdmEntitySessionManager cdmEntitySessionManager;
57

    
58
    private static CdmServiceCacher cdmServiceCacher;
59

    
60
    private final String cacheId;
61

    
62
    private final Cache cache;
63

    
64
    private final CacheLoader cacheLoader;
65

    
66

    
67

    
68
    public CdmTransientEntityCacher(String cacheId, ICdmEntitySessionManager cdmEntitySessionManager) {
69
        this.cacheId = cacheId;
70

    
71
        cache = new Cache(getEntityCacheConfiguration(cacheId));
72

    
73
        CacheManager.create().addCache(cache);
74

    
75
        this.cdmEntitySessionManager = cdmEntitySessionManager;
76

    
77
        cacheLoader = new CacheLoader(this);
78
    }
79

    
80
    public CdmTransientEntityCacher(Object sessionOwner, ICdmEntitySessionManager cdmEntitySessionManager) {
81
        this(generateCacheId(sessionOwner), cdmEntitySessionManager);
82
    }
83

    
84
    public static String generateCacheId(Object sessionOwner) {
85
        return sessionOwner.getClass().getName() +  String.valueOf(sessionOwner.hashCode());
86
    }
87

    
88
    /**
89
     * Returns the default cache configuration.
90
     *
91
     * @return
92
     */
93
    private CacheConfiguration getEntityCacheConfiguration(String cacheId) {
94
        SizeOfPolicyConfiguration sizeOfConfig = new SizeOfPolicyConfiguration();
95
        sizeOfConfig.setMaxDepth(10000);
96
        sizeOfConfig.setMaxDepthExceededBehavior("abort");
97

    
98
        return new CacheConfiguration(cacheId, 0)
99
        .eternal(true)
100
        .statistics(true)
101
        .sizeOfPolicy(sizeOfConfig)
102
        .overflowToOffHeap(false);
103

    
104
    }
105

    
106
    public static void setDefaultCacher(CdmServiceCacher css) {
107
        cdmServiceCacher = css;
108
    }
109

    
110
    public LiveCacheStatistics getCacheStatistics() {
111
        if(cache.getStatus() == Status.STATUS_ALIVE) {
112
            return cache.getLiveCacheStatistics();
113
        }
114
        return null;
115

    
116
    }
117

    
118
    /**
119
     * Returns the cache corresponding to the cache id
120
     *
121
     * @param cacheId
122
     * @return
123
     */
124
    private Cache getCache() {
125
        return  CacheManager.create().getCache(cacheId);
126
    }
127

    
128
    public <T extends Object> T load(T obj, boolean update) {
129
        return cacheLoader.load(obj, true, update);
130
    }
131

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

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

    
140
    public CdmBase load(CdmBase cdmEntity, boolean update) {
141
        return cacheLoader.load(cdmEntity, true, update);
142
    }
143

    
144

    
145
    private CdmBase load(CdmEntityIdentifier cei, boolean update) {
146
        return CdmApplicationState.getCommonService().findWithUpdate(cei.getCdmClass(), cei.getId());
147
    }
148

    
149

    
150
    public UpdateResult load(UpdateResult result, boolean update) {
151
        // probably a good time to broadcast to other sessions
152

    
153
        Set<CdmBase> updatedObjects = result.getUpdatedObjects();
154
        Set<CdmBase> reloadedObjects = new HashSet<CdmBase>();
155
        Set<CdmEntityIdentifier> updatedCdmIds = result.getUpdatedCdmIds();
156
        boolean updatedCdmIdsIsEmpty = updatedCdmIds.isEmpty();
157

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

    
170
        // remote load cdm identifiers of objects which already exist
171
        // in the cache
172

    
173
        for(CdmEntityIdentifier cei : updatedCdmIds) {
174
            if(exists(new CdmEntityCacheKey(cei.getCdmClass(), cei.getId()))) {
175
                reloadedObjects.add(load(cei, update));
176
            }
177

    
178
        }
179
        updatedObjects.clear();
180
        result.addUpdatedObjects(reloadedObjects);
181
        return result;
182
    }
183

    
184
    public CdmModelFieldPropertyFromClass getFromCdmlibModelCache(String className) {
185
        return cacheLoader.getFromCdmlibModelCache(className);
186
    }
187

    
188

    
189

    
190

    
191
    @Override
192
    public void put(CdmBase cdmEntity) {
193

    
194
        CdmBase cachedCdmEntity = cdmServiceCacher.load(cdmEntity);
195
        if(cachedCdmEntity != null) {
196
            logger.info("Cdm Entity with id : " + cdmEntity.getId() + " already exists in permanent cache. Ignoring put.");
197
            return;
198
        }
199
        CdmEntityCacheKey id = new CdmEntityCacheKey(cdmEntity);
200

    
201
        cachedCdmEntity = getFromCache(id);
202
        if(cachedCdmEntity == null) {
203
            getCache().put(new Element(id, cdmEntity));
204
            cdmEntity.initListener();
205
            logger.info(" - object of type " + cdmEntity.getClass().getName() + " with id " + cdmEntity.getId() + " put in cache");
206
            return;
207
        }
208
        logger.info(" - object of type " + cdmEntity.getClass().getName() + " with id " + cdmEntity.getId() + " already exists");
209
    }
210

    
211

    
212
    private Element getCacheElement(CdmEntityCacheKey key) {
213
        return getCache().get(key);
214
    }
215

    
216

    
217
    public CdmBase getFromCache(CdmEntityCacheKey id) {
218
        Element e = getCacheElement(id);
219

    
220
        if (e == null) {
221
            return null;
222
        } else {
223
            return (CdmBase) e.getObjectValue();
224
        }
225
    }
226

    
227
    public CdmBase getFromCache(Class<? extends CdmBase> clazz, int id) {
228
        CdmEntityCacheKey cacheId = generateKey(clazz,id);
229
        return getFromCache(cacheId);
230
    }
231

    
232
    @Override
233
    public CdmBase getFromCache(CdmBase cdmBase) {
234

    
235
        CdmEntityCacheKey cacheId = generateKey((CdmBase)ProxyUtils.deproxy(cdmBase));
236
        // first try this cache
237
        CdmBase  cachedCdmEntity = getFromCache(cacheId);
238

    
239
        if(cachedCdmEntity == null) {
240
            // ... then try the permanent cache
241
            cachedCdmEntity = cdmServiceCacher.getFromCache(cdmBase.getUuid());
242
        }
243

    
244
        return cachedCdmEntity;
245
    }
246

    
247
    public CdmBase getFromCache(CdmBase cdmBase, Class<? extends CdmBase> clazz) {
248

    
249
        cdmBase = CdmBase.deproxy(cdmBase, clazz);
250
        return getFromCache(cdmBase);
251
    }
252

    
253
    public List<CdmBase> getAllEntities() {
254
        List<CdmBase> entities = new ArrayList<CdmBase>();
255
        Map<String, CdmBase> elementsMap = getCache().getAllWithLoader(getCache().getKeys(), null);
256
        for (Map.Entry<String, CdmBase> entry : elementsMap.entrySet()) {
257
            entities.add(entry.getValue());
258
        }
259
        return entities;
260
    }
261

    
262
    public boolean exists(CdmEntityCacheKey key) {
263
        return (getCacheElement(key) != null);
264
    }
265

    
266
    public boolean existsAndIsNotNull(CdmEntityCacheKey id) {
267
        return getFromCache(id) != null;
268
    }
269

    
270
    public void clear() {
271
        cache.removeAll();
272
    }
273

    
274
    public void dispose() {
275
        CacheManager.create().removeCache(cache.getName());
276
        cache.dispose();
277

    
278
    }
279

    
280

    
281
    public static CdmEntityCacheKey generateKey(Class<? extends CdmBase> clazz, int id) {
282
        return new CdmEntityCacheKey(clazz, id);
283
    }
284

    
285

    
286
    public static CdmEntityCacheKey generateKey(CdmBase cdmBase) {
287
        Class<? extends CdmBase> entityClass = cdmBase.getClass();
288
        int id = cdmBase.getId();
289
        return new CdmEntityCacheKey(entityClass, id);
290
    }
291

    
292
    /* (non-Javadoc)
293
     * @see eu.etaxonomy.cdm.model.ICdmCacher#load(eu.etaxonomy.cdm.model.common.CdmBase)
294
     */
295
    @Override
296
    public CdmBase load(CdmBase cdmEntity) {
297
        return load(cdmEntity, true);
298
    }
299

    
300
    /* (non-Javadoc)
301
     * @see eu.etaxonomy.cdm.model.ICdmCacher#isCachable(eu.etaxonomy.cdm.model.common.CdmBase)
302
     */
303
    @Override
304
    public boolean isCachable(CdmBase cdmEntity) {
305
        return true;
306
    }
307

    
308
    /* (non-Javadoc)
309
     * @see eu.etaxonomy.cdm.model.ICdmCacher#exists(eu.etaxonomy.cdm.model.common.CdmBase)
310
     */
311
    @Override
312
    public boolean exists(CdmBase cdmBase) {
313
        return exists(generateKey(cdmBase));
314
    }
315

    
316

    
317

    
318
}
(7-7/9)