001    /**
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.camel.util;
018    
019    import java.io.Serializable;
020    import java.util.Collection;
021    import java.util.Map;
022    import java.util.Set;
023    import java.util.concurrent.atomic.AtomicLong;
024    
025    import com.googlecode.concurrentlinkedhashmap.ConcurrentLinkedHashMap;
026    
027    /**
028     * A Least Recently Used Cache
029     *
030     * @version 
031     */
032    public class LRUCache<K, V> implements Map<K, V>, Serializable {
033        private static final long serialVersionUID = -342098639681884414L;
034        
035        private int maxCacheSize = 10000;
036        private final AtomicLong hits = new AtomicLong();
037        private final AtomicLong misses = new AtomicLong();
038        private ConcurrentLinkedHashMap<K, V> map;
039    
040        public LRUCache(int maximumCacheSize) {
041            this(maximumCacheSize, maximumCacheSize);
042        }
043    
044        /**
045         * Constructs an empty <tt>LRUCache</tt> instance with the
046         * specified initial capacity, maximumCacheSize,load factor and ordering mode.
047         *
048         * @param initialCapacity  the initial capacity.
049         * @param maximumCacheSize the max capacity.
050         * @throws IllegalArgumentException if the initial capacity is negative
051         *                                  or the load factor is non positive.
052         */
053        public LRUCache(int initialCapacity, int maximumCacheSize) {
054            map = new ConcurrentLinkedHashMap.Builder<K, V>()
055                .initialCapacity(initialCapacity)
056                .maximumWeightedCapacity(maximumCacheSize).build();
057            this.maxCacheSize = maximumCacheSize;
058        }
059    
060        @Override
061        public V get(Object o) {
062            V answer = map.get(o);
063            if (answer != null) {
064                hits.incrementAndGet();
065            } else {
066                misses.incrementAndGet();
067            }
068            return answer;
069        }
070    
071        @Override
072        public int size() {
073            return map.size();
074        }
075    
076        @Override
077        public boolean isEmpty() {
078            return map.isEmpty();
079        }
080    
081        @Override
082        public boolean containsKey(Object o) {
083            return map.containsKey(o);
084        }
085    
086        @Override
087        public boolean containsValue(Object o) {
088            return map.containsValue(0);
089        }
090    
091        @Override
092        public V put(K k, V v) {
093            return map.put(k, v);
094        }
095    
096        @Override
097        public V remove(Object o) {
098            return map.remove(o);
099        }
100    
101        public void putAll(Map<? extends K, ? extends V> map) {
102            this.map.putAll(map);
103        }
104    
105        @Override
106        public void clear() {
107            map.clear();
108            resetStatistics();
109        }
110    
111        @Override
112        public Set<K> keySet() {
113            return map.ascendingKeySet();
114        }
115    
116        @Override
117        public Collection<V> values() {
118            return map.ascendingMap().values();
119        }
120    
121        @Override
122        public Set<Entry<K, V>> entrySet() {
123            return map.ascendingMap().entrySet();
124        }
125    
126        /**
127         * Gets the number of cache hits
128         */
129        public long getHits() {
130            return hits.get();
131        }
132    
133        /**
134         * Gets the number of cache misses.
135         */
136        public long getMisses() {
137            return misses.get();
138        }
139    
140        /**
141         * Returns the maxCacheSize.
142         */
143        public int getMaxCacheSize() {
144            return maxCacheSize;
145        }
146    
147        /**
148         * Rest the cache statistics such as hits and misses.
149         */
150        public void resetStatistics() {
151            hits.set(0);
152            misses.set(0);
153        }
154    
155        @Override
156        public String toString() {
157            return "LRUCache@" + ObjectHelper.getIdentityHashCode(this);
158        }
159    }