All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.cesecore.internal.CommonCacheBase Maven / Gradle / Ivy

/*************************************************************************
 *                                                                       *
 *  CESeCore: CE Security Core                                           *
 *                                                                       *
 *  This software is free software; you can redistribute it and/or       *
 *  modify it under the terms of the GNU Lesser General Public           *
 *  License as published by the Free Software Foundation; either         *
 *  version 2.1 of the License, or any later version.                    *
 *                                                                       *
 *  See terms of license at gnu.org.                                     *
 *                                                                       *
 *************************************************************************/
package org.cesecore.internal;

import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.apache.log4j.Logger;

/**
 * Object and name to id lookup cache base implementation.
 * 
 * Note that this type of cache is not optimized for short-lived objects, but
 * will prevent memory leaks to some extent through checking for stale data
 * during updates.
 * 
 * @version $Id: CommonCacheBase.java 28332 2018-02-20 14:40:52Z anatom $
 */
public abstract class CommonCacheBase implements CommonCache {
    
    private class CacheEntry {
        long lastUpdate;
        final int digest;
        final String name;
        final T object;
        CacheEntry(long lastUpdate, int digest, String name, T object) {
            this.lastUpdate = lastUpdate;
            this.digest = digest;
            this.name = name;
            this.object = object;
        }
    }
    
    private final Logger log = Logger.getLogger(CommonCacheBase.class);
    private Map cache = new HashMap();
    private Map nameToIdMap = new HashMap();

    /** @return how long to cache objects in milliseconds. */
    protected abstract long getCacheTime();
    
    /** @return the maximum allowed time an object may reside in the cache before it is purged. 0 means live forever. */
    protected abstract long getMaxCacheLifeTime();

    @Override
    public T getEntry(final Integer id) {
        final CacheEntry cacheEntry = getCacheEntry(id);
        if (cacheEntry == null) {
            return null;
        }
        return cacheEntry.object;
    }

    @Override
    public T getEntry(final int id) {
        return getEntry(Integer.valueOf(id));
    }

    public Set getAllEntries() {
        Set result = new HashSet();
        for(CacheEntry cacheEntry : cache.values()) {
            result.add(cacheEntry.object);
        }
        return result;
    }

    @Override
    public boolean shouldCheckForUpdates(final int id) {
        final long now = System.currentTimeMillis();
        final long cacheTime = getCacheTime();
        if (cacheTime<0) {
            // Cache is disabled, caller should check db
            return true;
        }
        final Integer key = Integer.valueOf(id);
        final CacheEntry cacheEntry = cache.get(key);
        if (cacheEntry == null) {
            // No such object in cache, caller should check db
            return true;
        }
        if (cacheEntry.lastUpdate+cacheTime cacheStage = new HashMap();
        final Map nameToIdMapStage = new HashMap();
        final long maxCacheLifeTime = getMaxCacheLifeTime();
        final long staleCutOffTime = System.currentTimeMillis()-maxCacheLifeTime;
        synchronized (this) {
            // Process all entries except for the one that will change
            for (final Entry entry : cache.entrySet()) {
                final Integer currentId = entry.getKey();
                if (!key.equals(currentId)) {
                    final CacheEntry currentCacheEntry = entry.getValue();
                    // By flushing older entries we at least limit how much
                    // this registry will grow when used for short-lived objects
                    // in a clustered environment.
                    if (maxCacheLifeTime<1 || currentCacheEntry.lastUpdate >= staleCutOffTime) {
                        // Keep using the current entry in the new cache
                        cacheStage.put(entry.getKey(), currentCacheEntry);
                        nameToIdMapStage.put(currentCacheEntry.name, entry.getKey());
                    }
                }
            }
            // Process the one that will change
            if (cacheEntry == null) {
                // Don't add if to the new version of the cache if it existed (e.g. remove it)
            } else {
                cacheStage.put(key, cacheEntry);
                nameToIdMapStage.put(cacheEntry.name, key);
            }
            cache = cacheStage;
            nameToIdMap = Collections.unmodifiableMap(nameToIdMapStage);
        }
    }

    @Override
    public Map getNameToIdMap() {
        return nameToIdMap;
    }

    @Override
    public void flush() {
        final Map cacheStage = new HashMap();
        final Map nameToIdMapStage = new HashMap();
        replaceCache(cacheStage, nameToIdMapStage);
    }
    
    @Override
    public void replaceCacheWith(List keys) {
        Map cacheStage = new HashMap();
        Map nameToIdMapStage = new HashMap();
        
        for(Integer key : keys) {
            CacheEntry entry = cache.get(key);
            cacheStage.put(key, entry);
            
            String name = entry.name;
            nameToIdMapStage.put(name, nameToIdMap.get(name));
        }
        
        replaceCache(cacheStage, nameToIdMapStage);
    }
    
    private void replaceCache(Map cacheStage, Map nameToIdMapStage) {
        synchronized (this) {
            cache = cacheStage;
            nameToIdMap = nameToIdMapStage;
        }
    }
    
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy