001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. The ASF licenses this file to You
004: * under the Apache License, Version 2.0 (the "License"); you may not
005: * use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License. For additional information regarding
015: * copyright in this work, please see the NOTICE file in the top level
016: * directory of this distribution.
017: */
018: package org.apache.roller.util;
019:
020: import java.util.ArrayList;
021: import java.util.Collections;
022: import java.util.Iterator;
023: import java.util.LinkedHashMap;
024: import java.util.List;
025: import java.util.Map;
026:
027: /**
028: * LRU cache with per-entry timeout logic.
029: *
030: * @author Dave Johnson
031: */
032: public class LRUCache2 {
033: private long timeout;
034: private Map cache = null;
035: private Environment environment = null;
036:
037: /**
038: * Create cache.
039: *
040: * @param maxsize
041: * Maximum number of entries in cache.
042: * @param timeout
043: * Entry timeout in milli-seconds.
044: */
045: public LRUCache2(int maxsize, long timeout) {
046: this .environment = new DefaultEnvironment();
047: this .timeout = timeout;
048: this .cache = new LRULinkedHashMap(maxsize);
049: }
050:
051: /**
052: * Create cache that uses custom environment.
053: *
054: * @param maxsize
055: * Maximum number of entries in cache.
056: * @param timeout
057: * Entry timeout in milli-seconds.
058: */
059: public LRUCache2(Environment environment, int maxsize, long timeout) {
060: this .environment = environment;
061: this .timeout = timeout;
062: this .cache = new LRULinkedHashMap(maxsize);
063: }
064:
065: public synchronized void put(Object key, Object value) {
066: CacheEntry entry = new CacheEntry(value, environment
067: .getCurrentTimeInMillis());
068: cache.put(key, entry);
069: }
070:
071: public Object get(Object key) {
072: Object value = null;
073: CacheEntry entry = null;
074: synchronized (this ) {
075: entry = (CacheEntry) cache.get(key);
076: }
077: if (entry != null) {
078: if (environment.getCurrentTimeInMillis()
079: - entry.getTimeCached() < timeout) {
080: value = entry.getValue();
081: } else {
082: cache.remove(entry);
083: }
084: }
085: return value;
086: }
087:
088: public synchronized void purge() {
089: cache.clear();
090: }
091:
092: public synchronized void purge(String[] patterns) {
093: List purgeList = new ArrayList();
094: Iterator keys = cache.keySet().iterator();
095: while (keys.hasNext()) {
096: String key = (String) keys.next();
097: for (int i = 0; i < patterns.length; i++) {
098: if (key.indexOf(patterns[i]) != -1) {
099: purgeList.add(key);
100: break;
101: }
102: }
103: }
104: Iterator purgeIter = purgeList.iterator();
105: while (purgeIter.hasNext()) {
106: String key = (String) purgeIter.next();
107: cache.remove(key);
108: }
109: }
110:
111: public int size() {
112: return cache.size();
113: }
114:
115: public interface Environment {
116: public long getCurrentTimeInMillis();
117: }
118:
119: public static class DefaultEnvironment implements Environment {
120: public long getCurrentTimeInMillis() {
121: return System.currentTimeMillis();
122: }
123: }
124:
125: private static class CacheEntry {
126: private Object value;
127: private long timeCached = -1;
128:
129: public CacheEntry(Object value, long timeCached) {
130: this .timeCached = timeCached;
131: this .value = value;
132: }
133:
134: public long getTimeCached() {
135: return timeCached;
136: }
137:
138: public Object getValue() {
139: return value;
140: }
141: }
142:
143: // David Flanaghan: http://www.davidflanagan.com/blog/000014.html
144: private static class LRULinkedHashMap extends LinkedHashMap {
145: protected int maxsize;
146:
147: public LRULinkedHashMap(int maxsize) {
148: super (maxsize * 4 / 3 + 1, 0.75f, true);
149: this .maxsize = maxsize;
150: }
151:
152: protected boolean removeEldestEntry(Map.Entry eldest) {
153: return this.size() > this.maxsize;
154: }
155: }
156: }
|