1 4 package org.ofbiz.minerva.pool.cache; 5 6 import java.io.PrintWriter ; 7 import java.util.*; 8 9 16 public class LeastRecentlyUsedCache implements ObjectCache { 17 18 private Object lock = new Object (); 19 private HashMap keyMap = new HashMap(); 20 private PrintWriter log = null; 21 private Node mostRecentNode, leastRecentNode; 22 private int size; 23 private int maxSize; 24 private CachedObjectFactory factory; 25 26 public LeastRecentlyUsedCache(CachedObjectFactory factory, int maxSize) { 27 this.factory = factory; 28 this.maxSize = maxSize; 29 } 30 31 public Object getObject(Object key) { 32 return getObject(key, false); 33 } 34 35 public Object useObject(Object key) { 36 return getObject(key, true); 37 } 38 39 public void returnObject(Object key, Object value) { 40 Object pooled = keyMap.get(key); 41 Object source = factory.translateObject(value); 42 43 if (pooled == null) { 44 factory.deleteObject(source); 45 } else if (pooled instanceof Node) { 46 Node node = (Node) pooled; 47 if (node.data == source) { 48 try { 49 node.setUsed(false); 50 } catch (ConcurrentModificationException e) { 51 } 52 } else { 53 factory.deleteObject(source); 54 } 55 } else if (pooled instanceof LinkedList) { 56 for (Iterator it = ((LinkedList) pooled).iterator(); it.hasNext();) { 57 Node node = (Node) it.next(); 58 if (node.data == source) { 59 try { 60 node.setUsed(false); 61 } catch (ConcurrentModificationException e) { 62 } 63 return; 64 } 65 } 66 factory.deleteObject(source); 67 } else 68 throw new Error ("LRU Cache Assertion Failure: Wrong class '" + pooled.getClass().getName() + "' in keyMap!"); 69 } 70 71 public void removeObjects(Object key) { 72 synchronized (lock) { 73 Object value = keyMap.get(key); 74 if (value == null) { 75 return; 76 } else if (value instanceof Node) { 77 removeNode((Node) value); 78 } else if (value instanceof LinkedList) { 79 LinkedList list = (LinkedList) value; 80 int max = list.size(); 81 for (int i = 0; i < max; i++) { 82 removeNode((Node) list.get(0)); 83 } 84 } 85 } 86 } 87 88 public void setSize(int maxSize) { 89 this.maxSize = maxSize; 90 checkMaxSize(); 91 } 92 93 public void close() { 94 synchronized (lock) { 95 Node current = leastRecentNode; 96 Node next = current == null ? null : current.moreRecent; 97 while (current != null) { 98 removeNode(current); 99 current = next; 100 next = current == null ? null : current.moreRecent; 101 } 102 } 103 } 104 105 private Object getObject(Object key, boolean use) { 106 Node node = null; 107 try { 108 Object value = keyMap.get(key); 109 if (value == null) { 110 node = addObject(key); 111 } else if (value instanceof Node) { 112 node = (Node) value; 113 if (!node.used) { 114 makeMostRecent(node); 115 } else { 116 node = addObject(key); 117 } 118 } else if (value instanceof LinkedList) { 119 for (Iterator it = ((LinkedList) value).iterator(); it.hasNext();) { 120 node = (Node) it.next(); 121 if (!node.used) { 122 makeMostRecent(node); 123 break; 124 } else { 125 node = null; 126 } 127 } 128 if (node == null) { 129 node = addObject(key); 130 } 131 } else 132 throw new Error ("LRU Cache Assertion Failure: Wrong class '" + value.getClass().getName() + "' in keyMap!"); 133 if (use) { 134 node.setUsed(true); 135 } 136 } catch (ConcurrentModificationException e) { 137 return getObject(key, use); 138 } 139 return factory.prepareObject(node.data); 140 } 141 142 private Node addObject(Object key) { 143 Object data; 144 try { 145 data = factory.createObject(key); 146 } catch (Exception e) { 147 if (log != null) 148 e.printStackTrace(log); 149 return null; 150 } 151 Node result; 152 synchronized (lock) { 153 if (mostRecentNode == null) { 154 result = new Node(null, null, data); 155 mostRecentNode = result; 156 leastRecentNode = result; 157 } else { 158 result = new Node(mostRecentNode, null, data); 159 mostRecentNode.moreRecent = result; 160 mostRecentNode = result; 161 } 162 ++size; 163 checkMaxSize(); 164 } 165 166 Object value = keyMap.get(key); 168 if (value == null) { 169 keyMap.put(key, result); 170 } else if (value instanceof LinkedList) { 171 ((LinkedList) value).add(result); 172 } else if (value instanceof Node) { 173 LinkedList list = new LinkedList(); 174 list.add(value); 175 list.add(result); 176 keyMap.put(key, list); 177 } else 178 throw new Error ("LRU Cache Assertion Failure: Wrong class '" + value.getClass().getName() + "' in keyMap!"); 179 keyMap.put(result, key); 180 return result; 181 } 182 183 private void checkMaxSize() { 184 if (maxSize <= 0) 185 return; 186 while (size > maxSize) { 187 Node drop = leastRecentNode; 188 leastRecentNode = drop.moreRecent; 189 leastRecentNode.lessRecent = null; 190 --size; 191 192 removeNode(drop); 193 } 194 } 195 196 private void makeMostRecent(Node node) { 197 synchronized (lock) { 198 if (node.moreRecent == null) { 199 if (mostRecentNode != node) 200 throw new ConcurrentModificationException(); 201 return; 202 } 203 204 Node previous = node.moreRecent; 206 Node next = node.lessRecent; 207 previous.lessRecent = next; 208 if (next == null) { 209 leastRecentNode = previous; 210 } else { 211 next.moreRecent = previous; 212 } 213 214 node.moreRecent = null; 216 node.lessRecent = mostRecentNode; 217 mostRecentNode.moreRecent = node; 218 mostRecentNode = node; 219 } 220 } 221 222 private void removeNode(Node node) { 224 boolean used = node.used; 225 if (!used) { 226 node.used = true; 227 } 228 Object key = keyMap.remove(node); 229 230 231 Object value = keyMap.get(key); 232 if (value instanceof Node) { 233 keyMap.remove(key); 234 } else if (value instanceof LinkedList) { 235 LinkedList list = (LinkedList) value; 236 Iterator it = list.iterator(); 237 while (it.hasNext()) { 238 Node current = (Node) it.next(); 239 if (current == node) { 240 it.remove(); 241 break; 242 } 243 } 244 if (list.size() == 1) { 245 keyMap.put(key, list.get(0)); 246 } 247 } else 248 throw new Error ("LRU Cache Assertion Failure: Wrong class '" + value.getClass().getName() + "' in keyMap!"); 249 if (!used) { 250 factory.deleteObject(node.data); 251 } 252 node.moreRecent = null; 253 node.lessRecent = null; 254 } 255 256 private class Node { 257 258 Node lessRecent; 259 Node moreRecent; 260 Object data; 261 boolean used = false; 262 263 public Node(Node lessRecent, Node moreRecent, Object data) { 264 this(lessRecent, moreRecent, data, false); 265 } 266 267 public Node(Node lessRecent, Node moreRecent, Object data, boolean used) { 268 this.lessRecent = lessRecent; 269 this.moreRecent = moreRecent; 270 this.data = data; 271 this.used = used; 272 } 273 274 public synchronized void setUsed(boolean used) { 275 if (this.used == used) 276 throw new ConcurrentModificationException(); 277 this.used = used; 278 } 279 } 280 281 355 } 356 | Popular Tags |