KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > lobobrowser > util > LRUCache


1 /*
2     GNU LESSER GENERAL PUBLIC LICENSE
3     Copyright (C) 2006 The Lobo Project
4
5     This library is free software; you can redistribute it and/or
6     modify it under the terms of the GNU Lesser General Public
7     License as published by the Free Software Foundation; either
8     version 2.1 of the License, or (at your option) any later version.
9
10     This library is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13     Lesser General Public License for more details.
14
15     You should have received a copy of the GNU Lesser General Public
16     License along with this library; if not, write to the Free Software
17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18
19     Contact info: xamjadmin@users.sourceforge.net
20 */

21 package org.lobobrowser.util;
22
23 import java.util.*;
24
25 /**
26  * A cache with least-recently-used policy.
27  * Note that this class is not thread safe by itself.
28  */

29 public class LRUCache implements java.io.Serializable JavaDoc {
30     private static final long serialVersionUID = 940427225784212823L;
31     private final int approxMaxSize;
32     private final Map cacheMap = new HashMap();
33     
34     /**
35      * Ascending timestamp order. First is least recently used.
36      */

37     private final TreeSet timedSet = new TreeSet();
38     private int currentSize = 0;
39     
40     public LRUCache(int approxMaxSize) {
41         this.approxMaxSize = approxMaxSize;
42     }
43     
44     public void put(Object JavaDoc key, Object JavaDoc value, int approxSize) {
45         if(approxSize > this.approxMaxSize) {
46             throw new IllegalArgumentException JavaDoc("Max size is " + this.approxMaxSize);
47         }
48         OrderedValue ordVal = (OrderedValue) this.cacheMap.get(key);
49         if(ordVal != null) {
50             this.currentSize += (approxSize - ordVal.approximateSize);
51             this.timedSet.remove(ordVal);
52             ordVal.approximateSize = approxSize;
53             ordVal.value = value;
54             ordVal.touch();
55             this.timedSet.add(ordVal);
56         }
57         else {
58             ordVal = new OrderedValue(value, approxSize);
59             this.cacheMap.put(key, ordVal);
60             this.timedSet.add(ordVal);
61             this.currentSize += approxSize;
62         }
63         while(this.currentSize > this.approxMaxSize) {
64             this.removeLRU();
65         }
66     }
67
68     private void removeLRU() {
69         OrderedValue ordVal = (OrderedValue) this.timedSet.first();
70         if(ordVal != null) {
71             if(this.timedSet.remove(ordVal)) {
72                 this.currentSize -= ordVal.approximateSize;
73             }
74             else {
75                 throw new IllegalStateException JavaDoc("Could not remove existing tree node.");
76             }
77         }
78         else {
79             throw new IllegalStateException JavaDoc("Cannot remove LRU since the cache is empty.");
80         }
81     }
82     
83     public Object JavaDoc get(Object JavaDoc key) {
84         OrderedValue ordVal = (OrderedValue) this.cacheMap.get(key);
85         if(ordVal != null) {
86             this.timedSet.remove(ordVal);
87             ordVal.touch();
88             this.timedSet.add(ordVal);
89             return ordVal.value;
90         }
91         else {
92             return null;
93         }
94     }
95     
96     private class OrderedValue implements Comparable JavaDoc, java.io.Serializable JavaDoc {
97         private static final long serialVersionUID = 340227625744215821L;
98         private long timestamp;
99         private int approximateSize;
100         private Object JavaDoc value;
101
102         private OrderedValue(Object JavaDoc value, int approxSize) {
103             this.value = value;
104             this.approximateSize = approxSize;
105             this.touch();
106         }
107         
108         private final void touch() {
109             this.timestamp = System.currentTimeMillis();
110         }
111
112         public int compareTo(Object JavaDoc arg0) {
113             if(this == arg0) {
114                 return 0;
115             }
116             OrderedValue other = (OrderedValue) arg0;
117             long diff = this.timestamp - other.timestamp;
118             if(diff != 0) {
119                 return (int) diff;
120             }
121             int hc1 = System.identityHashCode(this);
122             int hc2 = System.identityHashCode(other);
123             if(hc1 == hc2) {
124                 hc1 = System.identityHashCode(this.value);
125                 hc2 = System.identityHashCode(other.value);
126             }
127             return hc1 - hc2;
128         }
129     }
130 }
131
Popular Tags