1 24 package org.ofbiz.base.util.cache; 25 26 import java.io.Serializable ; 27 import java.util.Collection ; 28 import java.util.Iterator ; 29 import java.util.List ; 30 import java.util.Map ; 31 import java.util.MissingResourceException ; 32 import java.util.ResourceBundle ; 33 import java.util.Set ; 34 import java.util.WeakHashMap ; 35 36 import javolution.util.FastList; 37 import javolution.util.FastMap; 38 import javolution.util.FastSet; 39 40 import org.ofbiz.base.util.Debug; 41 import org.ofbiz.base.util.ObjectType; 42 import org.ofbiz.base.util.UtilValidate; 43 44 59 public class UtilCache implements Serializable { 60 61 public static final String module = UtilCache.class.getName(); 62 63 64 public static Map utilCacheTable = new WeakHashMap (); 65 66 67 protected static Map defaultIndices = FastMap.newInstance(); 68 69 70 protected String name = null; 71 72 73 public CacheLineTable cacheLineTable = null; 74 75 76 protected long hitCount = 0; 77 78 79 protected long missCountNotFound = 0; 80 81 protected long missCountExpired = 0; 82 83 protected long missCountSoftRef = 0; 84 85 86 protected long removeHitCount = 0; 87 88 protected long removeMissCount = 0; 89 90 93 protected int maxSize = 0; 94 protected int maxInMemory = 0; 95 96 99 protected long expireTime = 0; 100 101 102 protected boolean useSoftReference = false; 103 104 105 protected boolean useFileSystemStore = false; 106 private String fileStore = "data/utilcache"; 107 108 109 protected Set listeners = FastSet.newInstance(); 110 111 118 public UtilCache(String cacheName, int maxSize, int maxInMemory, long expireTime, boolean useSoftReference, boolean useFileSystemStore) { 119 this.maxSize = maxSize; 120 this.maxInMemory = maxInMemory; 121 this.expireTime = expireTime; 122 this.useSoftReference = useSoftReference; 123 this.useFileSystemStore = useFileSystemStore; 124 name = cacheName + this.getNextDefaultIndex(cacheName); 125 126 setPropertiesParams(cacheName); 127 128 utilCacheTable.put(name, this); 129 } 130 131 public UtilCache(String cacheName, int maxSize, long expireTime, boolean useSoftReference) { 132 this(cacheName, maxSize, maxSize, expireTime, useSoftReference, false); 133 } 134 135 141 public UtilCache(String cacheName, int maxSize, long expireTime) { 142 this(cacheName, maxSize, expireTime, false); 143 } 144 145 149 public UtilCache(int maxSize, long expireTime) { 150 this.useSoftReference = false; 151 this.maxSize = maxSize; 152 this.expireTime = expireTime; 153 String name = "specified" + this.getNextDefaultIndex("specified"); 154 155 setPropertiesParams(name); 156 157 utilCacheTable.put(name, this); 158 } 159 160 164 public UtilCache(String cacheName, boolean useSoftReference) { 165 name = cacheName + this.getNextDefaultIndex(cacheName); 166 this.useSoftReference = useSoftReference; 167 168 setPropertiesParams("default"); 169 setPropertiesParams(cacheName); 170 171 utilCacheTable.put(name, this); 172 } 173 174 178 public UtilCache(String cacheName) { 179 name = cacheName + this.getNextDefaultIndex(cacheName); 180 181 setPropertiesParams("default"); 182 setPropertiesParams(cacheName); 183 184 utilCacheTable.put(name, this); 185 } 186 187 188 public UtilCache() { 189 setPropertiesParams("default"); 190 191 name = "default" + this.getNextDefaultIndex("default"); 192 utilCacheTable.put(name, this); 193 } 194 195 protected String getNextDefaultIndex(String cacheName) { 196 Integer curInd = (Integer ) UtilCache.defaultIndices.get(cacheName); 197 198 if (curInd == null) { 199 UtilCache.defaultIndices.put(cacheName, new Integer (1)); 200 return ""; 201 } else { 202 UtilCache.defaultIndices.put(cacheName, new Integer (curInd.intValue() + 1)); 203 return Integer.toString(curInd.intValue() + 1); 204 } 205 } 206 207 public static String getPropertyParam(ResourceBundle res, String [] propNames, String parameter) { 208 String value = null; 209 for (int i = 0; i < propNames.length && value == null; i++ ) { 210 try { 211 value = res.getString(propNames[i] + '.' + parameter); 212 } catch (MissingResourceException e) {} 213 } 214 return value; 219 } 220 221 protected void setPropertiesParams(String cacheName) { 222 setPropertiesParams(new String [] {cacheName}); 223 } 224 225 public void setPropertiesParams(String [] propNames) { 226 ResourceBundle res = ResourceBundle.getBundle("cache"); 227 228 if (res != null) { 229 try { 230 String value = getPropertyParam(res, propNames, "maxSize"); 231 if (UtilValidate.isNotEmpty(value)) { 232 Integer intValue = new Integer (value); 233 if (intValue != null) { 234 this.maxSize = intValue.intValue(); 235 } 236 } 237 } catch (Exception e) { 238 Debug.logWarning(e, "Error getting maxSize value from cache.properties file for propNames: " + propNames, module); 239 } 240 try { 241 String value = getPropertyParam(res, propNames, "maxInMemory"); 242 if (UtilValidate.isNotEmpty(value)) { 243 Integer intValue = new Integer (value); 244 if (intValue != null) { 245 this.maxInMemory = intValue.intValue(); 246 } 247 } 248 } catch (Exception e) { 249 Debug.logWarning(e, "Error getting maxInMemory value from cache.properties file for propNames: " + propNames, module); 250 } 251 try { 252 String value = getPropertyParam(res, propNames, "expireTime"); 253 if (UtilValidate.isNotEmpty(value)) { 254 Long longValue = new Long (value); 255 if (longValue != null) { 256 this.expireTime = longValue.longValue(); 257 } 258 } 259 } catch (Exception e) { 260 Debug.logWarning(e, "Error getting expireTime value from cache.properties file for propNames: " + propNames, module); 261 } 262 try { 263 String value = getPropertyParam(res, propNames, "useSoftReference"); 264 if (value != null) { 265 useSoftReference = "true".equals(value); 266 } 267 } catch (Exception e) { 268 Debug.logWarning(e, "Error getting useSoftReference value from cache.properties file for propNames: " + propNames, module); 269 } 270 try { 271 String value = getPropertyParam(res, propNames, "useFileSystemStore"); 272 if (value != null) { 273 useFileSystemStore = "true".equals(value); 274 } 275 } catch (Exception e) { 276 Debug.logWarning(e, "Error getting useFileSystemStore value from cache.properties file for propNames: " + propNames, module); 277 } 278 try { 279 String value = res.getString("cache.file.store"); 280 if (value != null) { 281 fileStore = value; 282 } 283 } catch (Exception e) { 284 Debug.logWarning(e, "Error getting cache.file.store value from cache.properties file for propNames: " + propNames, module); 285 } 286 } 287 288 int maxMemSize = this.maxInMemory; 289 if (maxMemSize == 0) maxMemSize = (int) maxSize; 290 this.cacheLineTable = new CacheLineTable(this.fileStore, this.name, this.useFileSystemStore, maxMemSize); 291 } 292 293 297 public synchronized Object put(Object key, Object value) { 298 return put(key, value, expireTime); 299 } 300 301 306 public synchronized Object put(Object key, Object value, long expireTime) { 307 if (key == null) { 308 if (Debug.verboseOn()) Debug.logVerbose("In UtilCache tried to put with null key, using NullObject for cache " + this.getName(), module); 309 key = ObjectType.NULL; 310 } 311 CacheLine oldCacheLine; 312 if (expireTime > 0) { 313 oldCacheLine = (CacheLine) cacheLineTable.put(key, new CacheLine(value, useSoftReference, System.currentTimeMillis(), expireTime)); 314 } else { 315 oldCacheLine = (CacheLine) cacheLineTable.put(key, new CacheLine(value, useSoftReference, expireTime)); 316 } 317 318 if (oldCacheLine == null) { 319 noteAddition(key, value); 320 return null; 321 } else { 322 noteUpdate(key, value, oldCacheLine.getValue()); 323 return oldCacheLine.getValue(); 324 } 325 326 } 327 328 333 public Object get(Object key) { 334 CacheLine line = getInternal(key, true); 335 if (line == null) { 336 return null; 337 } else { 338 return line.getValue(); 339 } 340 } 341 342 protected CacheLine getInternalNoCheck(Object key) { 343 if (key == null) { 344 if (Debug.verboseOn()) Debug.logVerbose("In UtilCache tried to get with null key, using NullObject for cache " + this.getName(), module); 345 key = ObjectType.NULL; 346 } 347 CacheLine line = (CacheLine) cacheLineTable.get(key); 348 return line; 349 } 350 351 protected CacheLine getInternal(Object key, boolean countGet) { 352 CacheLine line = getInternalNoCheck(key); 353 if (line == null) { 354 if (countGet) missCountNotFound++; 355 } else if (line.softReferenceCleared()) { 356 removeInternal(key, false); 357 if (countGet) missCountSoftRef++; 358 line = null; 359 } else if (this.hasExpired(line)) { 360 removeInternal(key, false); 363 if (countGet) missCountExpired++; 364 line = null; 365 } else { 366 if (countGet) hitCount++; 367 } 368 return line; 369 } 370 371 public List values() { 372 if (cacheLineTable == null) { 373 return null; 374 } 375 376 List valuesList = FastList.newInstance(); 377 Iterator i = cacheLineTable.keySet().iterator(); 378 while (i.hasNext()) { 379 Object key = i.next(); 380 valuesList.add(this.get(key)); 381 } 382 383 return valuesList; 384 } 385 386 public long getSizeInBytes() { 387 long totalSize = 0; 388 Iterator i = cacheLineTable.values().iterator(); 389 while (i.hasNext()) { 390 totalSize += ((CacheLine) i.next()).getSizeInBytes(); 391 } 392 return totalSize; 393 } 394 395 399 public synchronized Object remove(Object key) { 400 return this.removeInternal(key, true); 401 } 402 403 404 protected synchronized Object removeInternal(Object key, boolean countRemove) { 405 if (key == null) { 406 if (Debug.verboseOn()) Debug.logVerbose("In UtilCache tried to remove with null key, using NullObject for cache " + this.getName(), module); 407 key = ObjectType.NULL; 408 } 409 CacheLine line = (CacheLine) cacheLineTable.remove(key); 410 if (line != null) { 411 noteRemoval(key, line.getValue()); 412 if (countRemove) this.removeHitCount++; 413 return line.getValue(); 414 } else { 415 if (countRemove) this.removeMissCount++; 416 return null; 417 } 418 } 419 420 421 public synchronized void clear() { 422 Iterator it = cacheLineTable.keySet().iterator(); 423 while (it.hasNext()) { 424 Object key = it.next(); 425 CacheLine line = getInternalNoCheck(key); 426 noteRemoval(key, line == null ? null : line.getValue()); 427 } 428 cacheLineTable.clear(); 429 clearCounters(); 430 } 431 432 433 public static void clearAllCaches() { 434 Iterator entries = utilCacheTable.entrySet().iterator(); 435 while (entries.hasNext()) { 436 Map.Entry entry = (Map.Entry ) entries.next(); 437 UtilCache utilCache = (UtilCache) entry.getValue(); 438 utilCache.clear(); 439 } 440 } 441 442 445 public String getName() { 446 return this.name; 447 } 448 449 452 public long getHitCount() { 453 return this.hitCount; 454 } 455 456 459 public long getMissCountNotFound() { 460 return this.missCountNotFound; 461 } 462 463 466 public long getMissCountExpired() { 467 return this.missCountExpired; 468 } 469 470 473 public long getMissCountSoftRef() { 474 return this.missCountSoftRef; 475 } 476 477 480 public long getMissCountTotal() { 481 return this.missCountSoftRef + this.missCountNotFound + this.missCountExpired; 482 } 483 484 public long getRemoveHitCount() { 485 return this.removeHitCount; 486 } 487 488 public long getRemoveMissCount() { 489 return this.removeMissCount; 490 } 491 492 494 public void clearCounters() { 495 this.hitCount = 0; 496 this.missCountNotFound = 0; 497 this.missCountExpired = 0; 498 this.missCountSoftRef = 0; 499 this.removeHitCount = 0; 500 this.removeMissCount = 0; 501 } 502 503 507 public void setMaxSize(int maxSize) { 508 cacheLineTable.setLru((int) maxSize); 509 this.maxSize = maxSize; 510 } 511 512 515 public long getMaxSize() { 516 return maxSize; 517 } 518 519 523 public void setExpireTime(long expireTime) { 524 if (this.expireTime <= 0 && expireTime > 0) { 526 long currentTime = System.currentTimeMillis(); 527 Iterator values = cacheLineTable.values().iterator(); 528 while (values.hasNext()) { 529 CacheLine line = (CacheLine) values.next(); 530 line.loadTime = currentTime; 531 } 532 } else if (this.expireTime <= 0 && expireTime > 0) { 533 } 535 536 this.expireTime = expireTime; 537 } 538 539 542 public long getExpireTime() { 543 return expireTime; 544 } 545 546 547 public void setUseSoftReference(boolean useSoftReference) { 548 if (this.useSoftReference != useSoftReference) { 549 this.useSoftReference = useSoftReference; 550 Iterator values = cacheLineTable.values().iterator(); 551 while (values.hasNext()) { 552 CacheLine line = (CacheLine) values.next(); 553 line.setUseSoftReference(useSoftReference); 554 } 555 } 556 } 557 558 559 public boolean getUseSoftReference() { 560 return this.useSoftReference; 561 } 562 563 public boolean getUseFileSystemStore() { 564 return this.useFileSystemStore; 565 } 566 567 570 public long size() { 571 return cacheLineTable.size(); 572 } 573 574 579 public boolean containsKey(Object key) { 580 CacheLine line = getInternal(key, false); 581 if (line != null) { 582 return true; 583 } else { 584 return false; 585 } 586 } 587 588 593 public Set getCacheLineKeys() { 594 return cacheLineTable.keySet(); 595 } 596 597 public Collection getCacheLineValues() { 598 return cacheLineTable.values(); 599 } 600 601 609 public boolean hasExpired(Object key) { 610 CacheLine line = getInternalNoCheck(key); 611 return hasExpired(line); 612 } 613 614 protected boolean hasExpired(CacheLine line) { 615 if (line == null) return false; 616 617 if (line.softReferenceCleared()) return true; 620 621 if (line.expireTime <= 0) return false; 623 624 if (line.loadTime <= 0) return true; 626 627 if ((line.loadTime + line.expireTime) < System.currentTimeMillis()) { 628 return true; 629 } else { 630 return false; 631 } 632 } 633 634 635 public void clearExpired() { 636 Iterator keys = cacheLineTable.keySet().iterator(); 637 while (keys.hasNext()) { 638 Object key = keys.next(); 639 if (hasExpired(key)) { 640 removeInternal(key, false); 641 } 642 } 643 } 644 645 646 protected void noteAddition(Object key, Object newValue) { 647 synchronized (listeners) { 648 Iterator it = listeners.iterator(); 649 while (it.hasNext()) { 650 CacheListener listener = (CacheListener) it.next(); 651 listener.noteKeyAddition(this, key, newValue); 652 } 653 } 654 } 655 656 657 protected void noteRemoval(Object key, Object oldValue) { 658 synchronized (listeners) { 659 Iterator it = listeners.iterator(); 660 while (it.hasNext()) { 661 CacheListener listener = (CacheListener) it.next(); 662 listener.noteKeyRemoval(this, key, oldValue); 663 } 664 } 665 } 666 667 668 protected void noteUpdate(Object key, Object newValue, Object oldValue) { 669 synchronized (listeners) { 670 Iterator it = listeners.iterator(); 671 while (it.hasNext()) { 672 CacheListener listener = (CacheListener) it.next(); 673 listener.noteKeyUpdate(this, key, newValue, oldValue); 674 } 675 } 676 } 677 678 679 public void addListener(CacheListener listener) { 680 synchronized (listeners) { 681 listeners.add(listener); 682 } 683 } 684 685 686 public void removeListener(CacheListener listener) { 687 synchronized (listeners) { 688 listeners.remove(listener); 689 } 690 } 691 692 693 public static void clearExpiredFromAllCaches() { 694 Iterator entries = utilCacheTable.entrySet().iterator(); 695 while (entries.hasNext()) { 696 Map.Entry entry = (Map.Entry ) entries.next(); 697 UtilCache utilCache = (UtilCache) entry.getValue(); 698 utilCache.clearExpired(); 699 } 700 } 701 702 703 public static boolean validKey(String cacheName, Object key) { 704 UtilCache cache = (UtilCache) utilCacheTable.get(cacheName); 705 if (cache != null) { 706 if (cache.containsKey(key)) 707 return true; 708 } 709 return false; 710 } 711 712 public static void clearCachesThatStartWith(String startsWith) { 713 synchronized (utilCacheTable) { 714 Iterator it = utilCacheTable.entrySet().iterator(); 715 while (it.hasNext()) { 716 Map.Entry entry = (Map.Entry ) it.next(); 717 String name = (String ) entry.getKey(); 718 if (name.startsWith(startsWith)) { 719 UtilCache cache = (UtilCache) entry.getValue(); 720 cache.clear(); 721 } 722 } 723 } 724 } 725 726 public static void clearCache(String cacheName) { 727 synchronized (UtilCache.utilCacheTable) { 728 UtilCache cache = (UtilCache) UtilCache.utilCacheTable.get(cacheName); 729 if (cache == null) return; 730 cache.clear(); 731 } 732 } 733 } 734 | Popular Tags |