1 /*
2 * #%L
3 * Nuiton Utils
4 * %%
5 * Copyright (C) 2004 - 2010 CodeLutin
6 * %%
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License as
9 * published by the Free Software Foundation, either version 3 of the
10 * License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Lesser Public License for more details.
16 *
17 * You should have received a copy of the GNU General Lesser Public
18 * License along with this program. If not, see
19 * <http://www.gnu.org/licenses/lgpl-3.0.html>.
20 * #L%
21 */
22
23 package org.nuiton.util;
24
25 import org.apache.commons.logging.Log;
26 import org.apache.commons.logging.LogFactory;
27
28 import java.util.ArrayList;
29 import java.util.Collections;
30 import java.util.HashMap;
31 import java.util.HashSet;
32 import java.util.Iterator;
33 import java.util.LinkedHashMap;
34 import java.util.Map;
35 import java.util.Set;
36
37
38 /** Created: 23 mai 2006 04:08:03
39 * @author Benjamin Poussin - poussin@codelutin.com */
40
41 public class LRUMapMultiKey extends LinkedHashMap<LRUMapMultiKey.Key, Object> {
42
43 private static final long serialVersionUID = 1L;
44
45 private static final Log log = LogFactory.getLog(LRUMapMultiKey.class);
46
47 /** @author Benjamin Poussin - poussin@codelutin.com */
48 public static class Key extends ArrayList<Object> {
49
50 private static final long serialVersionUID = 1L;
51
52 // protected LRUMapMultiKey map = null;
53 // protected Reference ref = null;
54 protected int hash = 0;
55
56 public Key(Object... k) {
57 Collections.addAll(this, k);
58 }
59
60 @Override
61 public int hashCode() {
62 if (hash == 0) {
63 hash = super.hashCode();
64 }
65 return hash;
66 }
67
68 // /* (non-Javadoc)
69 // * @see java.util.AbstractList#equals(java.lang.Object)
70 // */
71 // @Override
72 // public boolean equals(Object o) {
73 // if (o != null && o instanceof Reference) {
74 // Object ref = ((Reference)o).get();
75 // if (ref == null) {
76 // boolean result = o.hashCode() == hashCode();
77 // return result;
78 // }
79 // }
80 // return super.equals(o);
81 // }
82
83 // /* (non-Javadoc)
84 // * @see java.lang.Object#finalize()
85 // */
86 // @Override
87 // protected void finalize() throws Throwable {
88 // if (map != null) {
89 // for (Iterator i=iterator(); i.hasNext();) {
90 // Object k = i.next();
91 // Set<Reference<Key>> list = map.keys.get(k);
92 // if (list != null) {
93 // Object o = ref;
94 // if (o == null) {
95 // o = this;
96 // }
97 // boolean ok = list.remove(o);
98 // if (list.size() == 0) {
99 // map.keys.remove(k);
100 // }
101 // }
102 // }
103 // }
104 // }
105
106 }
107
108
109 protected Map<Object, Set<Key>> keys = new HashMap<Object, Set<Key>>();
110
111 protected int maxSize;
112
113 public LRUMapMultiKey(int maxSize) {
114 super(maxSize <= 0 ? 1000 : maxSize * 100 / 75, (float) 0.75, true);
115 this.maxSize = maxSize;
116 }
117
118 public Key createKey(Object... k) {
119 return new Key(k);
120 }
121
122 /* (non-Javadoc)
123 * @see java.util.WeakHashMap#clear()
124 */
125 @Override
126 public void clear() {
127 keys.clear();
128 super.clear();
129 }
130
131 /* (non-Javadoc)
132 * @see java.util.WeakHashMap#remove(java.lang.Object)
133 */
134 @Override
135 public Object remove(Object k) {
136 if (k instanceof Key) {
137 return super.remove(k);
138 } else {
139 ArrayList<Key> result = new ArrayList<Key>();
140 Set<Key> list = keys.remove(k);
141 if (list != null) {
142 for (Iterator<Key> i = list.iterator(); i.hasNext(); ) {
143 Key key = i.next();
144 result.add(key);
145 super.remove(key);
146 }
147 list.clear(); // not necessary but perhaps help the garbage
148 }
149 return result;
150 }
151 }
152
153 /* (non-Javadoc)
154 * @see java.util.WeakHashMap#put(java.lang.Object, java.lang.Object)
155 */
156 @Override
157 public Object put(Key key, Object value) {
158 // if (!(akey instanceof Key)) {
159 // throw new IllegalArgumentException("key must be Key object");
160 // }
161 // Key key = (Key)akey;
162 for (Iterator i = key.iterator(); i.hasNext(); ) {
163 Object k = i.next();
164 Set<Key> list = keys.get(k);
165 if (list == null) {
166 list = new HashSet<Key>();
167 keys.put(k, list);
168 }
169 list.add(key);
170 //System.out.println("+++++++++++++++++++ put key: " + key + " list("+k+") == " + list.size());
171 }
172 //System.out.println("++++++++++++++++++++++++++++ LRU size = " + size() + " maxSize: " + maxSize);
173 Object result = super.put(key, value);
174 //System.out.println("+++++++++++++++++ LRU size = " + size());
175 return result;
176 }
177
178 /* (non-Javadoc)
179 * @see java.util.LinkedHashMap#removeEldestEntry(java.util.Map.Entry)
180 */
181 @Override
182 protected boolean removeEldestEntry(Map.Entry<Key, Object> eldest) {
183 if (this.maxSize > 0 && size() > this.maxSize) {
184 Key key = eldest.getKey();
185 for (Iterator i = key.iterator(); i.hasNext(); ) {
186 Object k = i.next();
187 Set<Key> list = keys.get(k);
188 if (list != null) {
189 list.remove(key);
190 if (list.size() == 0) {
191 keys.remove(k);
192 }
193 }
194 }
195
196 if (!containsKey(eldest.getKey())) {
197 log.warn("possible memory leak !!! removeEldestEntry (" + eldest.getKey().getClass() + ")" + eldest.getKey() + " size " + size() + " maxSize" + maxSize);
198 }
199 return true;
200 }
201 return false;
202 }
203
204 // /* (non-Javadoc)
205 // * @see org.apache.commons.collections.map.LRUMap#removeLRU(org.apache.commons.collections.map.AbstractLinkedMap.LinkEntry)
206 // */
207 // @Override
208 // protected boolean removeLRU(AbstractLinkedMap.LinkEntry entry) {
209 // Key key = (Key)entry.getKey();
210 // for (Iterator i=key.iterator(); i.hasNext();) {
211 // Object k = i.next();
212 // Set<Key> list = keys.get(k);
213 // if (list != null) {
214 // boolean ok = list.remove(key);
215 // if (list.size() == 0) {
216 // keys.remove(k);
217 // }
218 // }
219 // }
220 // return true;
221 // }
222
223 }
224
225