151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski/*
2d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved.
351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * This code is free software; you can redistribute it and/or modify it
651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * under the terms of the GNU General Public License version 2 only, as
751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * published by the Free Software Foundation.  Oracle designates this
851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * particular file as subject to the "Classpath" exception as provided
951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * by Oracle in the LICENSE file that accompanied this code.
1051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
1151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * This code is distributed in the hope that it will be useful, but WITHOUT
1251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * version 2 for more details (a copy is included in the LICENSE file that
1551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * accompanied this code).
1651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
1751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * You should have received a copy of the GNU General Public License version
1851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 2 along with this work; if not, write to the Free Software Foundation,
1951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
2051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
2151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * or visit www.oracle.com if you need additional information or have any
2351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * questions.
2451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */
2551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
2651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskipackage sun.security.util;
2751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
2851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.util.*;
2951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.lang.ref.*;
3051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
3151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski/**
3251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Abstract base class and factory for caches. A cache is a key-value mapping.
3351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * It has properties that make it more suitable for caching than a Map.
3451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
3551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * The factory methods can be used to obtain two different implementations.
3651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * They have the following properties:
3751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
3851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *  . keys and values reside in memory
3951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
4051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *  . keys and values must be non-null
4151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
4251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *  . maximum size. Replacements are made in LRU order.
4351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
4451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *  . optional lifetime, specified in seconds.
4551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
46d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root *  . safe for concurrent use by multiple threads
4751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
4851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *  . values are held by either standard references or via SoftReferences.
4951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *    SoftReferences have the advantage that they are automatically cleared
5051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *    by the garbage collector in response to memory demand. This makes it
5151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *    possible to simple set the maximum size to a very large value and let
5251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *    the GC automatically size the cache dynamically depending on the
5351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *    amount of available memory.
5451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
5551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * However, note that because of the way SoftReferences are implemented in
5651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * HotSpot at the moment, this may not work perfectly as it clears them fairly
5751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * eagerly. Performance may be improved if the Java heap size is set to larger
5851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * value using e.g. java -ms64M -mx128M foo.Test
5951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
6051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Cache sizing: the memory cache is implemented on top of a LinkedHashMap.
6151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * In its current implementation, the number of buckets (NOT entries) in
6251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * (Linked)HashMaps is always a power of two. It is recommended to set the
6351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * maximum cache size to value that uses those buckets fully. For example,
6451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * if a cache with somewhere between 500 and 1000 entries is desired, a
6551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * maximum size of 750 would be a good choice: try 1024 buckets, with a
6651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * load factor of 0.75f, the number of entries can be calculated as
6751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * buckets / 4 * 3. As mentioned above, with a SoftReference cache, it is
6851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * generally reasonable to set the size to a fairly large value.
6951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
7051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @author Andreas Sterbenz
7151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */
72d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Rootpublic abstract class Cache<K,V> {
7351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
7451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    protected Cache() {
7551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // empty
7651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
7751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
7851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
7951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Return the number of currently valid entries in the cache.
8051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
8151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public abstract int size();
8251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
8351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
8451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Remove all entries from the cache.
8551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
8651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public abstract void clear();
8751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
8851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
8951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Add an entry to the cache.
9051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
91d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root    public abstract void put(K key, V value);
9251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
9351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
9451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Get a value from the cache.
9551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
96d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root    public abstract V get(Object key);
9751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
9851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
9951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Remove an entry from the cache.
10051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
10151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public abstract void remove(Object key);
10251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
10351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
10451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Set the maximum size.
10551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
10651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public abstract void setCapacity(int size);
10751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
10851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
10951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Set the timeout(in seconds).
11051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
11151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public abstract void setTimeout(int timeout);
11251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
11351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
11451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * accept a visitor
11551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
116d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root    public abstract void accept(CacheVisitor<K,V> visitor);
11751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
11851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
11951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Return a new memory cache with the specified maximum size, unlimited
12051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * lifetime for entries, with the values held by SoftReferences.
12151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
122d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root    public static <K,V> Cache<K,V> newSoftMemoryCache(int size) {
123d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root        return new MemoryCache<>(true, size);
12451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
12551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
12651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
12751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Return a new memory cache with the specified maximum size, the
12851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * specified maximum lifetime (in seconds), with the values held
12951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * by SoftReferences.
13051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
131d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root    public static <K,V> Cache<K,V> newSoftMemoryCache(int size, int timeout) {
132d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root        return new MemoryCache<>(true, size, timeout);
13351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
13451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
13551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
13651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Return a new memory cache with the specified maximum size, unlimited
13751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * lifetime for entries, with the values held by standard references.
13851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
139d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root    public static <K,V> Cache<K,V> newHardMemoryCache(int size) {
140d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root        return new MemoryCache<>(false, size);
14151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
14251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
14351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
14451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Return a dummy cache that does nothing.
14551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
146d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root    @SuppressWarnings("unchecked")
147d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root    public static <K,V> Cache<K,V> newNullCache() {
148d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root        return (Cache<K,V>) NullCache.INSTANCE;
14951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
15051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
15151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
15251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Return a new memory cache with the specified maximum size, the
15351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * specified maximum lifetime (in seconds), with the values held
15451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * by standard references.
15551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
156d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root    public static <K,V> Cache<K,V> newHardMemoryCache(int size, int timeout) {
157d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root        return new MemoryCache<>(false, size, timeout);
15851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
15951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
16051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
16151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Utility class that wraps a byte array and implements the equals()
16251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * and hashCode() contract in a way suitable for Maps and caches.
16351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
16451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public static class EqualByteArray {
16551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
16651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        private final byte[] b;
16751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        private volatile int hash;
16851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
16951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        public EqualByteArray(byte[] b) {
17051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            this.b = b;
17151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
17251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
17351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        public int hashCode() {
17451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            int h = hash;
17551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (h == 0) {
17651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                h = b.length + 1;
17751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                for (int i = 0; i < b.length; i++) {
17851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    h += (b[i] & 0xff) * 37;
17951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
18051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                hash = h;
18151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
18251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return h;
18351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
18451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
18551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        public boolean equals(Object obj) {
18651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (this == obj) {
18751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                return true;
18851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
18951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (obj instanceof EqualByteArray == false) {
19051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                return false;
19151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
19251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            EqualByteArray other = (EqualByteArray)obj;
19351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return Arrays.equals(this.b, other.b);
19451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
19551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
19651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
197d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root    public interface CacheVisitor<K,V> {
198d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root        public void visit(Map<K,V> map);
19951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
20051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
20151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski}
20251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
203d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Rootclass NullCache<K,V> extends Cache<K,V> {
20451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
205d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root    final static Cache<Object,Object> INSTANCE = new NullCache<>();
20651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
20751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private NullCache() {
20851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // empty
20951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
21051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
21151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public int size() {
21251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return 0;
21351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
21451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
21551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public void clear() {
21651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // empty
21751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
21851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
219d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root    public void put(K key, V value) {
22051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // empty
22151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
22251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
223d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root    public V get(Object key) {
22451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return null;
22551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
22651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
22751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public void remove(Object key) {
22851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // empty
22951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
23051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
23151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public void setCapacity(int size) {
23251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // empty
23351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
23451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
23551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public void setTimeout(int timeout) {
23651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // empty
23751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
23851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
239d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root    public void accept(CacheVisitor<K,V> visitor) {
24051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // empty
24151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
24251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
24351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski}
24451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
245d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Rootclass MemoryCache<K,V> extends Cache<K,V> {
24651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
24751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private final static float LOAD_FACTOR = 0.75f;
24851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
24951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // XXXX
25051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private final static boolean DEBUG = false;
25151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
252d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root    private final Map<K, CacheEntry<K,V>> cacheMap;
25351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private int maxSize;
25451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private long lifetime;
255d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root
256d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root    // ReferenceQueue is of type V instead of Cache<K,V>
257d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root    // to allow SoftCacheEntry to extend SoftReference<V>
258d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root    private final ReferenceQueue<V> queue;
25951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
26051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public MemoryCache(boolean soft, int maxSize) {
26151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        this(soft, maxSize, 0);
26251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
26351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
26451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public MemoryCache(boolean soft, int maxSize, int lifetime) {
26551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        this.maxSize = maxSize;
26651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        this.lifetime = lifetime * 1000;
267d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root        if (soft)
268d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root            this.queue = new ReferenceQueue<>();
269d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root        else
270d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root            this.queue = null;
271d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root
27251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int buckets = (int)(maxSize / LOAD_FACTOR) + 1;
273d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root        cacheMap = new LinkedHashMap<>(buckets, LOAD_FACTOR, true);
27451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
27551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
27651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
27751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Empty the reference queue and remove all corresponding entries
27851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * from the cache.
27951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
28051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * This method should be called at the beginning of each public
28151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * method.
28251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
28351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private void emptyQueue() {
28451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (queue == null) {
28551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return;
28651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
28751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int startSize = cacheMap.size();
28851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        while (true) {
289d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root            @SuppressWarnings("unchecked")
290d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root            CacheEntry<K,V> entry = (CacheEntry<K,V>)queue.poll();
29151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (entry == null) {
29251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                break;
29351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
294d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root            K key = entry.getKey();
29551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (key == null) {
29651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                // key is null, entry has already been removed
29751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                continue;
29851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
299d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root            CacheEntry<K,V> currentEntry = cacheMap.remove(key);
30051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            // check if the entry in the map corresponds to the expired
30151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            // entry. If not, readd the entry
30251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if ((currentEntry != null) && (entry != currentEntry)) {
30351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                cacheMap.put(key, currentEntry);
30451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
30551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
30651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (DEBUG) {
30751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            int endSize = cacheMap.size();
30851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (startSize != endSize) {
30951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                System.out.println("*** Expunged " + (startSize - endSize)
31051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        + " entries, " + endSize + " entries left");
31151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
31251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
31351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
31451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
31551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
31651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Scan all entries and remove all expired ones.
31751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
31851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private void expungeExpiredEntries() {
31951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        emptyQueue();
32051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (lifetime == 0) {
32151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return;
32251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
32351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int cnt = 0;
32451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        long time = System.currentTimeMillis();
325d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root        for (Iterator<CacheEntry<K,V>> t = cacheMap.values().iterator();
32651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                t.hasNext(); ) {
327d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root            CacheEntry<K,V> entry = t.next();
32851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (entry.isValid(time) == false) {
32951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                t.remove();
33051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                cnt++;
33151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
33251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
33351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (DEBUG) {
33451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (cnt != 0) {
33551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                System.out.println("Removed " + cnt
33651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        + " expired entries, remaining " + cacheMap.size());
33751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
33851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
33951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
34051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
34151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public synchronized int size() {
34251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        expungeExpiredEntries();
34351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return cacheMap.size();
34451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
34551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
34651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public synchronized void clear() {
34751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (queue != null) {
34851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            // if this is a SoftReference cache, first invalidate() all
34951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            // entries so that GC does not have to enqueue them
350d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root            for (CacheEntry<K,V> entry : cacheMap.values()) {
35151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                entry.invalidate();
35251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
35351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            while (queue.poll() != null) {
35451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                // empty
35551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
35651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
35751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        cacheMap.clear();
35851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
35951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
360d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root    public synchronized void put(K key, V value) {
36151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        emptyQueue();
36251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        long expirationTime = (lifetime == 0) ? 0 :
36351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                        System.currentTimeMillis() + lifetime;
364d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root        CacheEntry<K,V> newEntry = newEntry(key, value, expirationTime, queue);
365d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root        CacheEntry<K,V> oldEntry = cacheMap.put(key, newEntry);
36651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (oldEntry != null) {
36751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            oldEntry.invalidate();
36851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return;
36951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
37051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (maxSize > 0 && cacheMap.size() > maxSize) {
37151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            expungeExpiredEntries();
37251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (cacheMap.size() > maxSize) { // still too large?
373d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root                Iterator<CacheEntry<K,V>> t = cacheMap.values().iterator();
374d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root                CacheEntry<K,V> lruEntry = t.next();
37551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if (DEBUG) {
37651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    System.out.println("** Overflow removal "
37751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        + lruEntry.getKey() + " | " + lruEntry.getValue());
37851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
37951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                t.remove();
38051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                lruEntry.invalidate();
38151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
38251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
38351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
38451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
385d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root    public synchronized V get(Object key) {
38651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        emptyQueue();
387d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root        CacheEntry<K,V> entry = cacheMap.get(key);
38851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (entry == null) {
38951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return null;
39051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
39151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        long time = (lifetime == 0) ? 0 : System.currentTimeMillis();
39251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (entry.isValid(time) == false) {
39351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (DEBUG) {
39451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                System.out.println("Ignoring expired entry");
39551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
39651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            cacheMap.remove(key);
39751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return null;
39851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
39951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return entry.getValue();
40051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
40151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
40251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public synchronized void remove(Object key) {
40351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        emptyQueue();
404d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root        CacheEntry<K,V> entry = cacheMap.remove(key);
40551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (entry != null) {
40651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            entry.invalidate();
40751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
40851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
40951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
41051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public synchronized void setCapacity(int size) {
41151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        expungeExpiredEntries();
41251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (size > 0 && cacheMap.size() > size) {
413d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root            Iterator<CacheEntry<K,V>> t = cacheMap.values().iterator();
41451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            for (int i = cacheMap.size() - size; i > 0; i--) {
415d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root                CacheEntry<K,V> lruEntry = t.next();
41651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if (DEBUG) {
41751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    System.out.println("** capacity reset removal "
41851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        + lruEntry.getKey() + " | " + lruEntry.getValue());
41951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
42051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                t.remove();
42151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                lruEntry.invalidate();
42251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
42351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
42451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
42551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        maxSize = size > 0 ? size : 0;
42651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
42751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (DEBUG) {
42851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            System.out.println("** capacity reset to " + size);
42951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
43051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
43151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
43251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public synchronized void setTimeout(int timeout) {
43351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        emptyQueue();
43451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        lifetime = timeout > 0 ? timeout * 1000L : 0L;
43551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
43651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (DEBUG) {
43751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            System.out.println("** lifetime reset to " + timeout);
43851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
43951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
44051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
44151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // it is a heavyweight method.
442d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root    public synchronized void accept(CacheVisitor<K,V> visitor) {
44351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        expungeExpiredEntries();
444d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root        Map<K,V> cached = getCachedEntries();
44551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
44651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        visitor.visit(cached);
44751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
44851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
449d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root    private Map<K,V> getCachedEntries() {
450d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root        Map<K,V> kvmap = new HashMap<>(cacheMap.size());
45151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
452d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root        for (CacheEntry<K,V> entry : cacheMap.values()) {
45351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            kvmap.put(entry.getKey(), entry.getValue());
45451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
45551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
45651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return kvmap;
45751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
45851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
459d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root    protected CacheEntry<K,V> newEntry(K key, V value,
460d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root            long expirationTime, ReferenceQueue<V> queue) {
46151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (queue != null) {
462d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root            return new SoftCacheEntry<>(key, value, expirationTime, queue);
46351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        } else {
464d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root            return new HardCacheEntry<>(key, value, expirationTime);
46551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
46651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
46751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
468d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root    private static interface CacheEntry<K,V> {
46951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
47051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        boolean isValid(long currentTime);
47151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
47251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        void invalidate();
47351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
474d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root        K getKey();
47551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
476d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root        V getValue();
47751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
47851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
47951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
480d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root    private static class HardCacheEntry<K,V> implements CacheEntry<K,V> {
48151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
482d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root        private K key;
483d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root        private V value;
48451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        private long expirationTime;
48551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
486d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root        HardCacheEntry(K key, V value, long expirationTime) {
48751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            this.key = key;
48851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            this.value = value;
48951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            this.expirationTime = expirationTime;
49051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
49151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
492d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root        public K getKey() {
49351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return key;
49451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
49551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
496d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root        public V getValue() {
49751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return value;
49851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
49951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
50051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        public boolean isValid(long currentTime) {
50151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            boolean valid = (currentTime <= expirationTime);
50251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (valid == false) {
50351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                invalidate();
50451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
50551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return valid;
50651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
50751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
50851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        public void invalidate() {
50951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            key = null;
51051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            value = null;
51151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            expirationTime = -1;
51251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
51351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
51451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
515d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root    private static class SoftCacheEntry<K,V>
516d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root            extends SoftReference<V>
517d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root            implements CacheEntry<K,V> {
51851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
519d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root        private K key;
52051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        private long expirationTime;
52151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
522d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root        SoftCacheEntry(K key, V value, long expirationTime,
523d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root                ReferenceQueue<V> queue) {
52451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            super(value, queue);
52551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            this.key = key;
52651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            this.expirationTime = expirationTime;
52751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
52851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
529d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root        public K getKey() {
53051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return key;
53151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
53251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
533d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root        public V getValue() {
53451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return get();
53551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
53651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
53751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        public boolean isValid(long currentTime) {
53851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            boolean valid = (currentTime <= expirationTime) && (get() != null);
53951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (valid == false) {
54051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                invalidate();
54151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
54251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return valid;
54351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
54451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
54551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        public void invalidate() {
54651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            clear();
54751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            key = null;
54851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            expirationTime = -1;
54951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
55051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
55151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
55251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski}
553