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 }