1 64 package com.jcorporate.expresso.core.cache; 65 66 import EDU.oswego.cs.dl.util.concurrent.ConcurrentReaderHashMap; 67 import com.jcorporate.expresso.core.misc.ConfigCacheManager; 68 import com.jcorporate.expresso.core.misc.ConfigManager; 69 import com.jcorporate.expresso.core.misc.StringUtil; 70 import com.jcorporate.expresso.kernel.ComponentLifecycle; 71 import com.jcorporate.expresso.kernel.Configuration; 72 import com.jcorporate.expresso.kernel.exception.ConfigurationException; 73 import com.jcorporate.expresso.kernel.util.ClassLocator; 74 import com.jcorporate.expresso.kernel.util.FastStringBuffer; 75 import org.apache.log4j.Logger; 76 77 import java.util.ArrayList ; 78 import java.util.HashMap ; 79 import java.util.Iterator ; 80 import java.util.Map ; 81 import java.util.Vector ; 82 83 88 89 public class DefaultCacheManager 90 extends com.jcorporate.expresso.kernel.ComponentBase 91 implements ComponentLifecycle, CacheSystem { 92 93 94 97 private Map cacheInstances; 98 99 109 private static double minMemoryPercentage = 20.00; 110 111 112 113 114 115 private static int maxRetries = 20; 116 117 123 volatile private static HashMap listeners = null; 124 125 128 private static Logger log = Logger.getLogger(DefaultCacheManager.class); 129 130 134 private static CacheSyncInterface cacheSync = null; 135 136 139 private static boolean syncInitialized = false; 140 141 public DefaultCacheManager() { 142 } 143 144 150 public java.util.Set getAllCacheNames() { 151 HashMap thisCache = null; 152 153 thisCache = new HashMap(cacheInstances); 155 return thisCache.keySet(); 156 } 157 158 165 public Cacheable getItem(String cacheName, String valueKey) { 166 Cacheable returnValue; 167 Cache thisCache = null; 168 169 thisCache = (Cache) cacheInstances.get(cacheName); 170 171 if (thisCache == null) { 172 if (log.isDebugEnabled()) { 173 log.debug("Cache " + cacheName + " did not exist "); 174 } 175 returnValue = null; 176 } else { 177 Cacheable co = thisCache.getItem(valueKey); 178 returnValue = co; 179 if (log.isDebugEnabled()) { 180 if (co == null) { 181 log.debug("Cache " + thisCache.getName() + 182 " returns null for key " + valueKey); 183 184 } else { 185 log.debug("A " + ((Object ) co).getClass().getName() + 186 " was returned for " + thisCache.getName() + 187 " key " + valueKey); 188 } 189 } 190 191 192 } 193 194 return returnValue; 195 } 196 197 204 public int getItemCount(String cacheName) { 205 java.util.List v = getItems(cacheName); 206 207 if (v == null) { 208 return 0; 209 } 210 211 return v.size(); 212 } 213 214 221 public void setItems(String cacheName, java.util.List itemList) throws CacheException { 222 setItems(cacheName, itemList, -1); 223 } 224 225 226 234 public void setItems(String cacheName, java.util.List itemList, long expiration) throws CacheException { 235 Cache thisCache = null; 236 if (!existsCache(cacheName)) { 237 createCache(cacheName, true); 238 } 239 240 thisCache = this.getCache(cacheName, false); 241 if (thisCache != null) { 247 thisCache.setItems(itemList); 248 249 CacheEntry ce = thisCache.getCacheEntry(cacheName); 250 if (ce != null) { 251 ce.setExpiration(expiration); 252 } 253 254 notifyRemote(cacheName, "all"); 255 notifyListeners(cacheName); 256 checkMemory(); 257 } 258 } 259 260 261 270 public java.util.List getItems(String cacheName) { 271 272 Vector returnValue = null; 273 Cache thisCache = null; 274 275 if (cacheInstances == null) { 276 returnValue = null; 277 } else { 278 thisCache = (Cache) cacheInstances.get(cacheName); 279 280 if (thisCache == null) { 281 returnValue = null; 282 } else { 283 Vector v = thisCache.getItems(); 284 285 if (v == null || v.size() == 0) { 286 returnValue = null; 287 } else { 288 returnValue = v; 289 } 290 } 291 } 292 293 294 return returnValue; 295 } 296 297 304 public void addItem(String cacheName, Cacheable newItem) 305 throws CacheException { 306 addItem(cacheName, newItem, -1); 307 } 308 309 310 319 public void addItem(String cacheName, Cacheable newItem, long expiry) 320 throws CacheException { 321 322 Cache targetCache = this.getCache(cacheName, true); 323 324 if (targetCache != null) { 325 CacheEntry ce = new CacheEntry(newItem, expiry); 326 targetCache.addItem(ce); 327 notifyListeners(cacheName); 328 } 329 330 } 331 332 342 public void put(String cacheName, Cacheable newItem) 343 throws CacheException { 344 put(cacheName, newItem, -1); 345 } 346 347 358 public void put(String cacheName, Cacheable newItem, long expiry) 359 throws CacheException { 360 361 Cache targetCache = this.getCache(cacheName, true); 362 363 if (targetCache != null) { 364 CacheEntry ce = new CacheEntry(newItem, expiry); 365 targetCache.addItem(ce); 366 } 367 } 368 369 370 380 public void addListener(String listener, String listenTo) { 381 if (listeners == null) { 382 listeners = new HashMap(); 383 } 384 385 ArrayList listenerList = (ArrayList ) listeners.get(listenTo); 386 387 if (listenerList == null) { 388 listenerList = new ArrayList (); 389 listeners.put(listenTo, listenerList); 390 } 391 392 synchronized (listenerList) { 393 if (!listenerList.contains(listener)) { 394 listenerList.add(listener); 395 } 396 } 397 398 } 399 400 404 public void adjustForMemory() { 405 checkMemory(); 406 } 407 408 409 415 public void clear(String cacheName) throws CacheException { 416 notifyRemote(cacheName, "all"); 417 clearNoNotify(cacheName); 418 notifyListeners(cacheName); 419 } 420 421 427 public void clear() throws CacheException { 428 ArrayList cachesToClear = new ArrayList (); 429 for (Iterator it = cacheInstances.values().iterator(); 431 it.hasNext();) { 432 Cache thisCache = (Cache) it.next(); 433 if (thisCache != null) { 435 cachesToClear.add(thisCache); 436 } 437 } 438 439 for (Iterator ci = cachesToClear.iterator(); ci.hasNext();) { 441 Cache thisCache = (Cache) ci.next(); 442 clear(thisCache.getName()); } 444 445 } 446 447 450 public void clearNoNotify() { 451 cacheInstances = new ConcurrentReaderHashMap(30); 452 } 453 454 461 public void clearNoNotify(String cacheName) { 462 Cache thisCache = (Cache) cacheInstances.get(cacheName); 463 if (thisCache != null) { 464 thisCache.clear(); 465 cacheInstances.remove(cacheName); 466 } 467 } 468 469 479 public Cache createCache(String cacheName, boolean ordered, int maxSize) throws CacheException { 480 Cache existingCache = this.getCache(cacheName, false); 481 if (existingCache != null) { 482 483 return existingCache; 484 } 485 486 notifyListeners(cacheName); 487 checkMemory(); 488 489 Cache newCache = null; 490 Map thisCacheList = cacheInstances; 491 if (ordered) { 492 String className = ConfigManager.getClassHandler("orderedCache"); 493 494 if (className == null || className.length() < 0) { 495 if (log.isDebugEnabled()) { 496 log.debug("No class specified for 'orderedCache' class handler. Using default"); 497 } 498 } else { 499 try { 500 newCache = (Cache) ClassLocator.loadClass(className).newInstance(); 501 } catch (Exception e) { 502 log.error("Error loading ordered cache " + className, e); 503 } 504 } 505 if (newCache == null) { 506 newCache = new OrderedCache(); 507 } 508 509 newCache.setName(cacheName); 510 newCache.setMaxSize(maxSize); 511 } else { 512 String className = ConfigManager.getClassHandler("unOrderedCache"); 513 514 if (className == null || className.length() < 0) { 515 if (log.isDebugEnabled()) { 516 log.debug("No class specified for 'unOrderedCache' class handler. Using default"); 517 } 518 } else { 519 try { 520 newCache = (Cache) ClassLocator.loadClass(className).newInstance(); 521 } catch (Exception e) { 522 log.error("Error loading ordered cache " + className, e); 523 } 524 } 525 if (newCache == null) { 526 newCache = new UnOrderedCache(); 527 } 528 529 newCache.setName(cacheName); 530 newCache.setMaxSize(maxSize); 531 } 532 thisCacheList.put(cacheName, newCache); 533 return newCache; 534 535 } 536 537 545 public Cache createCache(String cacheName, boolean ordered) throws CacheException { 546 return createCache(cacheName, ordered, 0); 547 } 548 549 557 public boolean existsCache(String cacheName) { 558 if (cacheInstances != null) { 559 return cacheInstances.containsKey(cacheName); 560 } else { 561 return false; 562 } 563 } 564 565 572 public Cache getCache(String cacheName) { 573 return (Cache) cacheInstances.get(cacheName); 574 } 575 576 577 583 public void removeItem(String cacheName, Cacheable itemToRemove) 584 throws CacheException { 585 586 587 notifyRemote(cacheName, itemToRemove.getKey()); 588 notifyListeners(cacheName); 589 removeItemNoNotify(cacheName, itemToRemove); 590 } 591 592 599 public void removeItemNoNotify(String cacheName, Cacheable itemToRemove) 600 throws CacheException { 601 Cache thisCache = this.getCache(cacheName, false); if (thisCache != null) { 603 thisCache.removeItem(itemToRemove); 604 } 605 606 607 608 609 610 611 if ("com.jcorporate.expresso.services.dbobj.DbObjLimit".equals(cacheName)) { 612 clear(itemToRemove.getKey()); 613 } 614 } 615 616 626 private static synchronized void createCacheSync() 627 throws ClassNotFoundException , 628 IllegalAccessException , 629 InstantiationException { 630 if (cacheSync != null) { 631 return; 632 } 633 634 String s = ConfigManager.getClassHandler("cacheSynchronizer"); 635 636 if (s == null || s.length() == 0) { 637 638 syncInitialized = true; 641 cacheSync = null; 642 643 return; 644 } 645 646 cacheSync = (CacheSyncInterface) ClassLocator.loadClass(s).newInstance(); 647 } 648 649 public void initialize() { 650 cacheInstances = new ConcurrentReaderHashMap(30); 651 } 652 653 public void configure(Configuration newConfig) throws ConfigurationException { 654 try { 655 createCacheSync(); 656 } catch (InstantiationException ex) { 657 log.error("Error creating cache synchronizer. Synchronization disabled", ex); 658 } catch (IllegalAccessException ex) { 659 log.error("Error creating cache synchronizer. Synchronization disabled", ex); 660 } catch (ClassNotFoundException ex) { 661 log.error("Error creating cache synchronizer. Synchronization disabled", ex); 662 } 663 } 664 665 666 675 private static void notifyRemote(String cacheName, 676 String key) 677 throws CacheException { 678 679 if (syncInitialized && cacheSync == null) { 680 return; } 682 683 684 try { 685 if (cacheSync == null) { 686 createCacheSync(); 687 688 if (cacheSync == null) { 689 return; 690 } 691 } 692 synchronized (cacheSync) { 693 CacheSyncMessage message = new CacheSyncMessage(); 694 message.setCacheName(cacheName); 695 message.setKey(key); 696 cacheSync.notifyRemote(message); 698 } 699 } catch (ClassCastException cce) { 700 log.error("Error loading CacheSyncInterface", cce); 701 throw new CacheException("Error instantiating CacheSyncInterface", 702 cce); 703 } catch (InstantiationException ie) { 704 log.error("Error loading CacheSyncInterface", ie); 705 throw new CacheException("Error instantiating CacheSyncInterface", 706 ie); 707 } catch (IllegalAccessException iae) { 708 log.error("Error loading CacheSyncInterface", iae); 709 throw new CacheException("Security error instantiating CacheSyncInterface", 710 iae); 711 } catch (ClassNotFoundException cnfe) { 712 log.error("Error loading CacheSyncInterface", cnfe); 713 throw new CacheException("Couldn't locate CacheSync Interface specified in expresso-config.xml", 714 cnfe); 715 } 716 } 717 718 719 public void reconfigure(Configuration newConfig) throws ConfigurationException { 720 721 throw new java.lang.UnsupportedOperationException ("Method reconfigure() not yet implemented."); 722 } 723 724 public void destroy() { 725 cacheInstances = null; 726 } 727 728 729 737 private Cache getCache(String cacheName, boolean forceCreate) { 738 Cache returnValue = null; 739 try { 740 returnValue = (Cache) cacheInstances.get(cacheName); 741 if (returnValue == null && forceCreate) { 742 returnValue = createCache(cacheName, false); 743 if (returnValue == null) { 744 log.warn("Somebody else removed my own cache before I was able to add it."); 745 } 746 } 747 } catch (CacheException ex) { 748 log.error("Error creating cache: ", ex); 749 } catch (java.util.ConcurrentModificationException cme) { 750 cme.printStackTrace(); 751 throw cme; 752 } 753 754 return returnValue; 755 } 756 757 758 765 private void notifyListeners(String listenTo) 766 throws CacheException { 767 768 if (listeners == null) { 769 if (log.isDebugEnabled()) { 770 log.debug("There are no listeners at all"); 771 } 772 773 return; 774 } 775 776 ArrayList listenList = (ArrayList ) listeners.get(listenTo); 777 778 if (listenList == null) { 779 if (log.isDebugEnabled()) { 780 log.debug("There are no listeners to cache " + "/" + listenTo); 781 } 782 783 return; 784 } 785 786 synchronized (listenList) { 789 listenList = (ArrayList ) listenList.clone(); 790 } 791 792 String oneListener = null; 793 794 for (Iterator i = listenList.iterator(); i.hasNext();) { 795 oneListener = (String ) i.next(); 796 797 if (log.isDebugEnabled()) { 798 log.debug("Clearing cache " + oneListener + 799 " because it is " + " a listener to " + listenTo); 800 } 801 802 clear(oneListener); 803 } 804 } 805 806 814 public void checkMemory() { 815 Runtime r = Runtime.getRuntime(); 816 double avail = r.totalMemory(); 817 double free = r.freeMemory(); 818 double pfree = ((free / avail) * 100.000); 819 ConfigCacheManager myConfig = null; 820 821 822 myConfig = ConfigManager.getConfig().getCacheManager(); 823 824 if (myConfig != null) { 825 String minMemoryString = StringUtil.notNull(myConfig.getMinMemoryPercentage()); 826 827 if (!minMemoryString.equals("")) { 828 minMemoryPercentage = new Double (minMemoryString).doubleValue(); 829 } 830 831 String maxRetriesString = StringUtil.notNull(myConfig.getMaxRetries()); 832 833 if (!maxRetriesString.equals("")) { 834 maxRetries = new Integer (maxRetriesString).intValue(); 835 } 836 } 837 if (log.isDebugEnabled()) { 838 log.debug("Free memory " + free + ", Available " + avail + 839 ", Percent free " + pfree + "%"); 840 } 841 842 boolean warned = false; 843 int retries = 0; 844 845 while (pfree < minMemoryPercentage) { 846 retries++; 847 848 if (retries > maxRetries) { 849 FastStringBuffer warnMessage = FastStringBuffer.getInstance(); 850 try { 851 warnMessage.append("Tried"); 852 warnMessage.append(maxRetries); 853 warnMessage.append(" times to free memory - still below minimum"); 854 log.warn(warnMessage.toString()); 855 } finally { 856 warnMessage.release(); 857 warnMessage = null; 858 } 859 860 861 return; 862 } 863 if (log.isInfoEnabled()) { 864 log.info("Memory below specified minimum limit free - " + 865 "looking for caches to clear"); 866 } 867 868 boolean somethingCleared = clearLowestCache(); 869 870 if (!somethingCleared) { 871 avail = r.totalMemory(); 872 free = r.freeMemory(); 873 pfree = ((free / avail) * 100.00); 874 875 if (!warned) { 876 warned = true; 877 878 FastStringBuffer fsb = FastStringBuffer.getInstance(); 879 try { 880 fsb.append( 881 "WARNING: Out of memory & no more caches can be cleared. To fix, change container (Tomcat) startup to have larger -Xms and -Xmx params for java. Avail:"); 882 fsb.append(avail); 883 fsb.append(", Free:"); 884 fsb.append(free); 885 fsb.append(", "); 886 fsb.append(pfree); 887 fsb.append("% free"); 888 log.warn(fsb.toString()); 889 } finally { 890 fsb.release(); 891 fsb = null; 892 } 893 } 894 } 895 896 if (log.isInfoEnabled()) { 897 log.info("Finished clearing cache. Now Garbage Collecting"); 898 } 899 System.gc(); 900 avail = r.totalMemory(); 901 free = r.freeMemory(); 902 pfree = ((free / avail) * 100.00); 903 } 904 } 905 906 907 912 public boolean clearLowestCache() { 913 914 String oneCacheName = null; 915 Cache lowestCache = null; 916 Cache oneCache = null; 917 long lowestCount = java.lang.Long.MAX_VALUE; 918 919 Iterator cn = getAllCacheNames().iterator(); 920 921 if (cn != null) { 922 while (cn.hasNext()) { 923 oneCacheName = (String ) cn.next(); 924 oneCache = getCache(oneCacheName, false); 925 926 if (oneCache != null && 927 (oneCache.getUsedCount() < lowestCount)) { 928 lowestCache = oneCache; 929 lowestCount = oneCache.getUsedCount(); 930 } 931 } 932 933 } 934 935 937 if (lowestCache != null) { 938 if (log.isDebugEnabled()) { 939 log.debug("Cache '" + lowestCache.getName() + 940 "' is least used & being cleared"); 941 } 942 943 lowestCache.clear(); 944 } else { 945 return false; 946 } 947 948 return true; 949 } 950 951 956 public void displayStatus() { 957 Runtime r = Runtime.getRuntime(); 958 double avail = r.totalMemory(); 959 double free = r.freeMemory(); 960 double pfree = ((free / avail) * 100.000); 961 962 if (log.isInfoEnabled()) { 963 log.info("Cache Status"); 964 log.info("Free memory " + free + ", Available " + avail + 965 ", Percent free " + pfree + "%"); 966 } 967 968 String oneConfigKey = null; 969 String oneCacheName = null; 970 Cache oneCache = null; 971 972 Iterator cn = this.getAllCacheNames().iterator(); 973 974 if (cn != null) { 975 while (cn.hasNext()) { 976 oneCacheName = (String ) cn.next(); 977 oneCache = this.getCache(oneCacheName, false); 978 if (oneCache != null) { 979 if (log.isDebugEnabled()) { 980 log.debug("Context/Cache " + oneConfigKey + "/" + 981 oneCacheName + " has " + 982 oneCache.getItemCount() + " items & " + 983 oneCache.getUsedCount() + " accesses"); 984 } 985 } 986 } 987 988 } 989 990 } 991 992 993 } | Popular Tags |