1 3 27 package pt.waveweb.util; 28 29 import java.util.ArrayList ; 30 import java.util.Collection ; 31 import java.util.Collections ; 32 import java.util.HashMap ; 33 import java.util.HashSet ; 34 import java.util.Iterator ; 35 import java.util.Map ; 36 import java.util.Set ; 37 import java.util.TreeMap ; 38 39 48 public class LruCache implements Map 49 { 50 private int _maxCapacity = 32768; 51 private long _lifespan; 52 private long _timeout; 53 private TreeMap _timeOrder; 54 private HashMap _keyOrder; 55 private ArrayList _entryPool; 56 57 66 public LruCache(long timeout, int maxCapacity) 67 { 68 this(timeout, Long.MAX_VALUE, 0, maxCapacity); 69 } 70 71 77 public LruCache(long timeout, long lifespan, int maxCapacity) 78 { 79 this(timeout, lifespan, 0, maxCapacity); 80 } 81 82 92 public LruCache(long timeout, long lifespan, int initialCapacity, int maxCapacity) 93 { 94 if (timeout < 0) 95 { 96 throw new IllegalArgumentException ("timeout < 0"); 97 } 98 99 _timeout = timeout; 100 101 if (lifespan < 0) 102 { 103 throw new IllegalArgumentException ("lifespan < 0"); 104 } 105 106 _lifespan = lifespan; 107 108 if (initialCapacity < 0) 109 { 110 throw new IllegalArgumentException ("initialCapacity < 0"); 111 } 112 113 if (maxCapacity < 0) 114 { 115 throw new IllegalArgumentException ("maxCapacity < 0"); 116 } 117 118 _timeOrder = new TreeMap (); 119 _keyOrder = new HashMap (initialCapacity); 120 _maxCapacity = maxCapacity; 121 _entryPool = new ArrayList (initialCapacity); 122 } 123 124 125 public synchronized boolean containsKey(Object key) 126 { 127 return (get(key) != null); 128 } 129 130 public synchronized boolean containsValue(Object value) 131 { 132 Iterator i = _timeOrder.values().iterator(); 135 136 while (i.hasNext()) 137 { 138 Entry ent = (Entry) i.next(); 139 140 if (ent.getValue().equals(value)) 141 { 142 return true; 143 } 144 } 145 146 return false; 147 } 148 149 157 public synchronized Set entrySet() 158 { 159 Iterator entries = _timeOrder.entrySet().iterator(); 160 HashSet hs = new HashSet (_timeOrder.size()); 161 Map.Entry ent; 162 163 while (entries.hasNext()) 164 { 165 ent = (Entry) ((Map.Entry ) entries.next()).getValue(); 166 hs.add(ent); 167 } 168 169 return Collections.unmodifiableSet(hs); 170 } 171 172 public synchronized boolean equals(Object o) 173 { 174 LruCache c = (LruCache) o; 175 176 return _timeOrder.equals(c._timeOrder) && _keyOrder.equals(c._keyOrder); 177 } 178 179 public synchronized int hashCode() 180 { 181 return _timeOrder.hashCode() ^ _keyOrder.hashCode(); 182 } 183 184 public boolean isEmpty() 185 { 186 return _timeOrder.isEmpty(); 187 } 188 189 193 public synchronized Set keySet() 194 { 195 return Collections.unmodifiableSet(_keyOrder.keySet()); 196 } 197 198 public synchronized Object get(Object key) 199 { 200 Entry ent = (Entry) _keyOrder.get(key); 202 203 if (ent == null) 204 { 205 return null; 207 } 208 209 if (!update(ent)) 215 { 216 return null; 217 } 218 else 219 { 220 return ent.getValue(); 221 } 222 } 223 224 228 public synchronized Object put(Object key, Object val) 229 { 230 return put(key, val, _timeout); 231 } 232 233 238 public synchronized Object put(Object key, Object val, long expirationTime) 239 { 240 while (_keyOrder.size() >= _maxCapacity) 241 { 242 remove(((Entry) _timeOrder.lastKey()).getKey()); 243 } 244 245 Entry ent = getEntryFromPool(key, val, expirationTime, _lifespan); 246 247 Entry retVal = add(ent); 248 249 if (retVal != null) 250 { 251 return retVal.getValue(); 252 } 253 254 return retVal; 255 } 256 257 private synchronized Entry add(Entry ent) 258 { 259 _keyOrder.put(ent.getKey(), ent); 260 261 return (Entry) _timeOrder.put(ent, ent); 262 } 263 264 268 public synchronized void putAll(Map t) 269 { 270 Iterator i = t.keySet().iterator(); 271 Object key; 272 273 while (i.hasNext()) 274 { 275 key = i.next(); 276 put(key, t.get(key)); 277 } 278 } 279 280 public synchronized Object remove(Object key) 281 { 282 Entry ent = (Entry) _keyOrder.remove(key); 284 285 if (ent == null) 286 { 287 return null; 288 } 289 290 _timeOrder.remove(ent); 291 292 Object retVal = ent.getValue(); 293 returnEntryToPool(ent); 294 295 return retVal; 296 } 297 298 public synchronized int size() 299 { 300 return _keyOrder.size(); 301 } 302 303 307 public synchronized Collection values() 308 { 309 return Collections.unmodifiableCollection(_timeOrder.values()); 310 } 311 312 public synchronized void prune() 313 { 314 Iterator vals = _timeOrder.values().iterator(); 315 316 Entry ent = null; 317 318 while (vals.hasNext()) 319 { 320 ent = (Entry) vals.next(); 321 322 if (ent.expired()) 323 { 324 remove(ent.getKey()); 325 } 326 } 327 } 328 329 public synchronized void clear() 330 { 331 _keyOrder.clear(); 332 _timeOrder.clear(); 333 } 334 335 public synchronized boolean contains(Object key) 336 { 337 if (_keyOrder.get(key) != null) 338 { 339 return true; 340 } 341 342 return false; 343 } 344 345 public long getTimeout() 346 { 347 return _timeout; 348 } 349 350 public void setTimeout(long millis) 351 { 352 _timeout = millis; 353 } 354 355 public int getMaxCapacity() 356 { 357 return _maxCapacity; 358 } 359 360 public void setMaxCapacity(int max) 361 { 362 _maxCapacity = max; 363 } 364 365 366 367 372 synchronized Entry getEntry(Object key) 373 { 374 return (Entry) _keyOrder.get(key); 375 } 376 377 378 379 385 private synchronized boolean update(Entry ent) 386 { 387 if (ent.expired()) 388 { 389 remove(ent.getKey()); 390 391 return false; } 393 394 _timeOrder.remove(ent); 395 ent.touch(); 396 _timeOrder.put(ent, ent); 397 398 return true; } 400 401 407 private Entry getEntryFromPool(Object key, Object obj, long expirationTime, long lifespan) 408 { 409 int last = _entryPool.size() - 1; 410 411 if (last >= 0) 412 { 413 Entry ent = (Entry) _entryPool.remove(last); 414 ent.set(key, obj, expirationTime, lifespan); 415 416 return ent; 417 } 418 419 return new Entry(key, obj, expirationTime, lifespan); 420 } 421 422 427 private void returnEntryToPool(Entry ent) 428 { 429 ent.reset(); 430 _entryPool.add(ent); 431 } 432 433 436 440 public class Entry implements Map.Entry , Comparable 441 { 442 443 private Object _key; 444 private Object _obj; 445 private long _created; 446 private long _expirationTimeout; 447 private long _lifespan; 448 private long _lastAccessed; 449 450 456 protected Entry(Object key, Object obj, long expirationTimeout, long lifespan) 457 { 458 set(key, obj, expirationTimeout, lifespan); 459 } 460 461 protected void set(Object key, Object obj, long expirationTimeout, long lifespan) 462 { 463 _key = key; 464 _obj = obj; 465 _created = System.currentTimeMillis(); 466 _lastAccessed = _created; 467 _expirationTimeout = expirationTimeout; 468 _lifespan = lifespan; 469 } 470 471 477 public boolean expired() 478 { 479 long currentTime = System.currentTimeMillis(); 480 481 long expirationTime = _lastAccessed + _expirationTimeout; 482 long deathTime = _created + _lifespan; 483 484 boolean expired = false; 485 486 if (expirationTime > 0) 488 { 489 expired = currentTime >= expirationTime; 490 } 491 else 492 { 493 } 497 498 boolean dead = false; 499 500 if (deathTime > 0) 502 { 503 dead = currentTime >= deathTime; 504 } 505 else 506 { 507 } 511 512 if (expired || dead) 515 { 516 return true; 518 } 519 520 return false; 521 } 522 523 529 protected void touch() 530 { 531 _lastAccessed = System.currentTimeMillis(); 532 } 533 534 538 public void reset() 539 { 540 _key = ""; 541 _obj = ""; 542 } 543 544 548 public Object getKey() 549 { 550 return _key; 551 } 552 553 556 public Object getValue() 557 { 558 return _obj; 559 } 560 561 564 public Object setValue(Object obj) 565 { 566 Object tmp = _obj; 567 _obj = obj; 568 569 return tmp; 570 } 571 572 579 public int hashCode() 580 { 581 return getKey().hashCode(); 582 } 583 584 590 protected long getLastAccessed() 591 { 592 return _lastAccessed; 593 } 594 595 private long getCreationTime() 596 { 597 return _created; 598 } 599 600 603 public String toString() 604 { 605 StringBuffer buf = new StringBuffer (); 606 buf.append(getKey() + "=" + getValue()); 607 608 return buf.toString(); 609 } 610 611 619 public boolean equals(Object entry) 620 { 621 Entry ent = (Entry) entry; 622 623 if (getKey().equals(ent.getKey())) 624 { 625 return true; 626 } 627 628 return false; 629 } 630 631 639 public int compareTo(Object obj) 640 { 641 if (equals(obj)) 643 { 644 return 0; 645 } 646 647 Entry ent = (Entry) obj; 648 long _ts = ent.getLastAccessed(); 649 650 if (_lastAccessed > _ts) 652 { 653 return -1; 654 } 655 656 if (_lastAccessed < _ts) 658 { 659 return 1; 660 } 661 662 long _creation = ent.getCreationTime(); 663 664 if (_creation > _ts) 666 { 667 return -1; 668 } 669 670 if (_creation < _ts) 672 { 673 return 1; 674 } 675 676 int mine = _key.hashCode(); 679 int other = ent.getKey().hashCode(); 680 681 if (mine > other) 682 { 683 return -1; 684 } 685 else 686 if (mine < other) 687 { 688 return 1; 689 } 690 691 return 1; 694 } 695 } 696 } 697 | Popular Tags |