com.guang.eunormia.common.cache.DefaultLocalCache.java Source code

Java tutorial

Introduction

Here is the source code for com.guang.eunormia.common.cache.DefaultLocalCache.java

Source

/*
 * Copyright (C) 2013 ferdi
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or any later version.
 *
 */

package com.guang.eunormia.common.cache;

import java.lang.ref.SoftReference;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 *
 * @author ferdi email:ferdi@blueferdi.com
 * @since Jul 1, 2013 5:15:35 PM
 * @version 0.0.1
*/
public class DefaultLocalCache<K, V> implements LocalCache<K, V> {
    private static final Log Logger = LogFactory.getLog(DefaultLocalCache.class);

    ConcurrentHashMap<K, SoftReference<V>>[] caches;
    ConcurrentHashMap<K, Long> expiryCache;

    private ScheduledExecutorService scheduleService;

    private int expiryInterval = 10;

    private int moduleSize = 10;

    public DefaultLocalCache() {
        init();
    }

    public DefaultLocalCache(int expiryInterval, int moduleSize) {
        this.expiryInterval = expiryInterval;
        this.moduleSize = moduleSize;
        init();
    }

    @SuppressWarnings("unchecked")
    private void init() {
        caches = new ConcurrentHashMap[moduleSize];

        for (int i = 0; i < moduleSize; i++) {
            caches[i] = new ConcurrentHashMap<K, SoftReference<V>>();
        }

        expiryCache = new ConcurrentHashMap<K, Long>();

        scheduleService = Executors.newScheduledThreadPool(1);

        scheduleService.scheduleAtFixedRate(new CheckOutOfDateSchedule(caches, expiryCache), 0, expiryInterval * 60,
                TimeUnit.SECONDS);

        if (Logger.isInfoEnabled()) {
            Logger.info("DefaultCache CheckService is start!");
        }
    }

    @Override
    public boolean clear() {
        if (caches != null)
            for (ConcurrentHashMap<K, SoftReference<V>> cache : caches) {
                cache.clear();
            }

        if (expiryCache != null) {
            expiryCache.clear();
        }

        return true;
    }

    @Override
    public boolean containsKey(K key) {
        checkValidate(key);
        return getCache(key).containsKey(key);
    }

    @Override
    public V get(K key) {
        checkValidate(key);
        SoftReference<V> sr = getCache(key).get(key);
        if (sr == null) {
            expiryCache.remove(key);
            return null;
        } else {
            return sr.get();
        }
    }

    @Override
    public Set<K> keySet() {
        checkAll();
        return expiryCache.keySet();
    }

    @Override
    public V put(K key, V value) {
        SoftReference<V> result = getCache(key).put(key, new SoftReference<V>(value));
        expiryCache.put(key, -1L);

        return result == null ? null : result.get();
    }

    @Override
    public V put(K key, V value, Date expiry) {
        SoftReference<V> result = getCache(key).put(key, new SoftReference<V>(value));
        expiryCache.put(key, expiry.getTime());

        return result == null ? null : result.get();
    }

    @Override
    public V remove(K key) {
        SoftReference<V> result = getCache(key).remove(key);
        expiryCache.remove(key);
        return result == null ? null : result.get();
    }

    @Override
    public int size() {
        checkAll();

        return expiryCache.size();
    }

    @Override
    public Collection<V> values() {
        checkAll();

        Collection<V> values = new ArrayList<V>();

        for (ConcurrentHashMap<K, SoftReference<V>> cache : caches) {
            for (SoftReference<V> sr : cache.values()) {
                values.add(sr.get());
            }
        }

        return values;
    }

    private ConcurrentHashMap<K, SoftReference<V>> getCache(K key) {
        long hashCode = (long) key.hashCode();

        if (hashCode < 0)
            hashCode = -hashCode;

        int moudleNum = (int) hashCode % moduleSize;

        return caches[moudleNum];
    }

    private void checkValidate(K key) {
        if (key != null && expiryCache.get(key) != null && expiryCache.get(key) != -1
                && new Date(expiryCache.get(key)).before(new Date())) {
            getCache(key).remove(key);
            expiryCache.remove(key);
        }
    }

    private void checkAll() {
        Iterator<K> iter = expiryCache.keySet().iterator();

        while (iter.hasNext()) {
            K key = iter.next();
            checkValidate(key);
        }
    }

    class CheckOutOfDateSchedule implements Runnable {
        ConcurrentHashMap<K, SoftReference<V>>[] caches;
        ConcurrentHashMap<K, Long> expiryCache;

        public CheckOutOfDateSchedule(ConcurrentHashMap<K, SoftReference<V>>[] caches,
                ConcurrentHashMap<K, Long> expiryCache) {
            this.caches = caches;
            this.expiryCache = expiryCache;
        }

        @Override
        public void run() {
            check();
        }

        public void check() {
            try {
                for (ConcurrentHashMap<K, SoftReference<V>> cache : caches) {
                    Iterator<K> keys = cache.keySet().iterator();

                    while (keys.hasNext()) {
                        K key = keys.next();

                        if (expiryCache.get(key) == null)
                            continue;

                        long date = expiryCache.get(key);

                        if ((date > 0) && (new Date(date).before(new Date()))) {
                            expiryCache.remove(key);
                            cache.remove(key);
                        }

                    }

                }
            } catch (Exception ex) {
                Logger.info("DefaultCache CheckService is start!");
            }
        }

    }

    @Override
    public V put(K key, V value, int TTL) {
        SoftReference<V> result = getCache(key).put(key, new SoftReference<V>(value));

        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.SECOND, TTL);
        expiryCache.put(key, calendar.getTime().getTime());

        return result == null ? null : result.get();
    }

    @Override
    public void destroy() {
        try {
            clear();

            if (scheduleService != null)
                scheduleService.shutdown();

            scheduleService = null;
        } catch (Exception ex) {
            Logger.error(ex);
        }
    }
}