| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. The ASF licenses this file to You |
| * under the Apache License, Version 2.0 (the "License"); you may not |
| * use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. For additional information regarding |
| * copyright in this work, please see the NOTICE file in the top level |
| * directory of this distribution. |
| */ |
| package org.apache.roller.weblogger.util; |
| import java.util.ArrayList; |
| import java.util.LinkedHashMap; |
| import java.util.List; |
| import java.util.Map; |
| /** |
| * LRU cache with per-entry timeout logic. |
| * |
| * @author Dave Johnson |
| */ |
| public class LRUCache2 |
| { |
| private long timeout; |
| private Map<Object, CacheEntry> cache = null; |
| private Environment environment = null; |
| |
| /** |
| * Create cache. |
| * |
| * @param maxsize |
| * Maximum number of entries in cache. |
| * @param timeout |
| * Entry timeout in milli-seconds. |
| */ |
| public LRUCache2(int maxsize, long timeout) |
| { |
| this.environment = new DefaultEnvironment(); |
| this.timeout = timeout; |
| this.cache = new LRULinkedHashMap(maxsize); |
| } |
| |
| /** |
| * Create cache that uses custom environment. |
| * |
| * @param maxsize |
| * Maximum number of entries in cache. |
| * @param timeout |
| * Entry timeout in milli-seconds. |
| */ |
| public LRUCache2(Environment environment, int maxsize, long timeout) |
| { |
| this.environment = environment; |
| this.timeout = timeout; |
| this.cache = new LRULinkedHashMap(maxsize); |
| } |
| |
| public synchronized void put(Object key, Object value) |
| { |
| CacheEntry entry = new CacheEntry(value, environment |
| .getCurrentTimeInMillis()); |
| cache.put(key, entry); |
| } |
| |
| public Object get(Object key) |
| { |
| Object value = null; |
| CacheEntry entry; |
| synchronized(this) |
| { |
| entry = cache.get(key); |
| } |
| if (entry != null) |
| { |
| if (environment.getCurrentTimeInMillis() - entry.getTimeCached() < timeout) |
| { |
| value = entry.getValue(); |
| } |
| else |
| { |
| cache.remove(entry); |
| } |
| } |
| return value; |
| } |
| |
| public synchronized void purge() |
| { |
| cache.clear(); |
| } |
| |
| public synchronized void purge(String[] patterns) |
| { |
| List<String> purgeList = new ArrayList<String>(); |
| for (Object objKey : cache.keySet()) { |
| String key = (String) objKey; |
| for (String s : patterns) { |
| if (key.contains(s)) { |
| purgeList.add(key); |
| break; |
| } |
| } |
| } |
| for (String s: purgeList) { |
| cache.remove(s); |
| } |
| } |
| |
| public int size() { |
| return cache.size(); |
| } |
| |
| public interface Environment { |
| long getCurrentTimeInMillis(); |
| } |
| |
| public static class DefaultEnvironment implements Environment { |
| public long getCurrentTimeInMillis() |
| { |
| return System.currentTimeMillis(); |
| } |
| } |
| |
| private static class CacheEntry |
| { |
| private Object value; |
| private long timeCached = -1; |
| |
| public CacheEntry(Object value, long timeCached) |
| { |
| this.timeCached = timeCached; |
| this.value = value; |
| } |
| |
| public long getTimeCached() |
| { |
| return timeCached; |
| } |
| |
| public Object getValue() |
| { |
| return value; |
| } |
| } |
| |
| // David Flanaghan: http://www.davidflanagan.com/blog/000014.html |
| private static class LRULinkedHashMap extends LinkedHashMap<Object, CacheEntry> |
| { |
| protected int maxsize; |
| |
| public LRULinkedHashMap(int maxsize) |
| { |
| super(maxsize * 4 / 3 + 1, 0.75f, true); |
| this.maxsize = maxsize; |
| } |
| |
| protected boolean removeEldestEntry(Map.Entry eldest) |
| { |
| return this.size() > this.maxsize; |
| } |
| } |
| } |