View Javadoc
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