1 31 32 package org.opencms.flex; 33 34 import org.opencms.cache.CmsLruCache; 35 import org.opencms.cache.I_CmsLruCacheObject; 36 import org.opencms.file.CmsObject; 37 import org.opencms.main.CmsLog; 38 import org.opencms.main.I_CmsEventListener; 39 import org.opencms.main.OpenCms; 40 import org.opencms.security.CmsRole; 41 import org.opencms.util.CmsFileUtil; 42 import org.opencms.util.CmsStringUtil; 43 44 import java.io.File ; 45 import java.util.Collections ; 46 import java.util.HashMap ; 47 import java.util.HashSet ; 48 import java.util.Hashtable ; 49 import java.util.Iterator ; 50 import java.util.Map ; 51 import java.util.Set ; 52 53 import org.apache.commons.collections.map.LRUMap; 54 import org.apache.commons.logging.Log; 55 56 108 public class CmsFlexCache extends Object implements I_CmsEventListener { 109 110 115 public class CmsFlexCacheVariation extends Object { 116 117 118 public CmsFlexCacheKey m_key; 119 120 121 public Map m_map; 122 123 128 public CmsFlexCacheVariation(CmsFlexCacheKey theKey) { 129 130 m_key = theKey; 131 m_map = new Hashtable (INITIAL_CAPACITY_VARIATIONS); 132 } 133 } 134 135 140 class CmsFlexKeyMap extends LRUMap { 141 142 143 private static final long serialVersionUID = 6931995916013396902L; 144 145 150 public CmsFlexKeyMap(int maxSize) { 151 152 super(maxSize); 153 } 154 155 159 protected boolean removeLRU(LinkEntry entry) { 160 161 CmsFlexCacheVariation v = (CmsFlexCacheVariation)entry.getValue(); 162 if (v == null) { 163 return true; 164 } 165 Map m = v.m_map; 166 if ((m == null) || (m.size() == 0)) { 167 return true; 168 } 169 Object [] entries = m.values().toArray(); 170 synchronized (m_variationCache) { 171 for (int i = 0, s = entries.length; i < s; i++) { 172 CmsFlexCacheEntry e = (CmsFlexCacheEntry)entries[i]; 173 m_variationCache.remove(e); 174 } 175 v.m_map.clear(); 176 v.m_map = null; 177 v.m_key = null; 178 } 179 return true; 180 } 181 } 182 183 184 public static final String CACHE_OFFLINESUFFIX = " [offline]"; 185 186 187 public static final String CACHE_ONLINESUFFIX = " [online]"; 188 189 190 public static final int CLEAR_ALL = 0; 191 192 193 public static final int CLEAR_ENTRIES = 1; 194 195 196 public static final int CLEAR_OFFLINE_ALL = 4; 197 198 199 public static final int CLEAR_OFFLINE_ENTRIES = 5; 200 201 202 public static final int CLEAR_ONLINE_ALL = 2; 203 204 205 public static final int CLEAR_ONLINE_ENTRIES = 3; 206 207 208 public static final int INITIAL_CAPACITY_CACHE = 512; 209 210 211 public static final int INITIAL_CAPACITY_VARIATIONS = 8; 212 213 214 public static final String REPOSITORY_OFFLINE = "offline"; 215 216 217 public static final String REPOSITORY_ONLINE = "online"; 218 219 220 private static final Log LOG = CmsLog.getLog(CmsFlexCache.class); 221 222 223 protected CmsLruCache m_variationCache; 224 225 226 private boolean m_cacheOffline; 227 228 229 private boolean m_enabled; 230 231 232 private Map m_keyCache; 233 234 235 private int m_size; 236 237 248 public CmsFlexCache(CmsFlexCacheConfiguration configuration) { 249 250 m_enabled = configuration.isCacheEnabled(); 251 m_cacheOffline = configuration.isCacheOffline(); 252 253 int maxCacheBytes = configuration.getMaxCacheBytes(); 254 int avgCacheBytes = configuration.getAvgCacheBytes(); 255 int maxEntryBytes = configuration.getMaxEntryBytes(); 256 int maxKeys = configuration.getMaxKeys(); 257 258 m_variationCache = new CmsLruCache(maxCacheBytes, avgCacheBytes, maxEntryBytes); 259 260 if (OpenCms.getMemoryMonitor().enabled()) { 261 OpenCms.getMemoryMonitor().register(getClass().getName() + ".m_entryLruCache", m_variationCache); 262 } 263 264 if (m_enabled) { 265 CmsFlexKeyMap flexKeyMap = new CmsFlexKeyMap(maxKeys); 266 m_keyCache = Collections.synchronizedMap(flexKeyMap); 267 268 if (OpenCms.getMemoryMonitor().enabled()) { 269 OpenCms.getMemoryMonitor().register(getClass().getName() + ".m_resourceMap", flexKeyMap); 270 } 271 272 OpenCms.addCmsEventListener(this, new int[] { 273 I_CmsEventListener.EVENT_PUBLISH_PROJECT, 274 I_CmsEventListener.EVENT_CLEAR_CACHES, 275 I_CmsEventListener.EVENT_FLEX_PURGE_JSP_REPOSITORY, 276 I_CmsEventListener.EVENT_FLEX_CACHE_CLEAR}); 277 } 278 279 if (LOG.isInfoEnabled()) { 280 LOG.info(Messages.get().getBundle().key( 281 Messages.INIT_FLEXCACHE_CREATED_2, 282 new Boolean (m_enabled), 283 new Boolean (m_cacheOffline))); 284 } 285 } 286 287 292 public boolean cacheOffline() { 293 294 return m_cacheOffline; 295 } 296 297 303 public void cmsEvent(org.opencms.main.CmsEvent event) { 304 305 if (!isEnabled()) { 306 return; 307 } 308 309 switch (event.getType()) { 310 case I_CmsEventListener.EVENT_PUBLISH_PROJECT: 311 case I_CmsEventListener.EVENT_CLEAR_CACHES: 312 if (LOG.isDebugEnabled()) { 313 LOG.debug(Messages.get().getBundle().key(Messages.LOG_FLEXCACHE_RECEIVED_EVENT_CLEAR_CACHE_0)); 314 } 315 clear(); 316 break; 317 case I_CmsEventListener.EVENT_FLEX_PURGE_JSP_REPOSITORY: 318 if (LOG.isDebugEnabled()) { 319 LOG.debug(Messages.get().getBundle().key(Messages.LOG_FLEXCACHE_RECEIVED_EVENT_PURGE_REPOSITORY_0)); 320 } 321 purgeJspRepository(); 322 break; 323 case I_CmsEventListener.EVENT_FLEX_CACHE_CLEAR: 324 if (LOG.isDebugEnabled()) { 325 LOG.debug(Messages.get().getBundle().key( 326 Messages.LOG_FLEXCACHE_RECEIVED_EVENT_CLEAR_CACHE_PARTIALLY_0)); 327 } 328 Map m = event.getData(); 329 if (m == null) { 330 break; 331 } 332 Integer it = null; 333 try { 334 it = (Integer )m.get("action"); 335 } catch (Exception e) { 336 } 338 if (it == null) { 339 break; 340 } 341 int i = it.intValue(); 342 switch (i) { 343 case CLEAR_ALL: 344 clear(); 345 break; 346 case CLEAR_ENTRIES: 347 clearEntries(); 348 break; 349 case CLEAR_ONLINE_ALL: 350 clearOnline(); 351 break; 352 case CLEAR_ONLINE_ENTRIES: 353 clearOnlineEntries(); 354 break; 355 case CLEAR_OFFLINE_ALL: 356 clearOffline(); 357 break; 358 case CLEAR_OFFLINE_ENTRIES: 359 clearOfflineEntries(); 360 break; 361 default: 362 } 364 default: 365 } 367 } 368 369 383 public CmsFlexCacheKey getCachedKey(String key, CmsObject cms) { 384 385 if (!isEnabled() || !cms.hasRole(CmsRole.WORKPLACE_MANAGER)) { 386 return null; 387 } 388 Object o = m_keyCache.get(key); 389 if (o != null) { 390 return ((CmsFlexCacheVariation)o).m_key; 391 } 392 return null; 393 } 394 395 406 public Set getCachedResources(CmsObject cms) { 407 408 if (!isEnabled() || !cms.hasRole(CmsRole.WORKPLACE_MANAGER)) { 409 return null; 410 } 411 return m_keyCache.keySet(); 412 } 413 414 428 public Set getCachedVariations(String key, CmsObject cms) { 429 430 if (!isEnabled() || !cms.hasRole(CmsRole.WORKPLACE_MANAGER)) { 431 return null; 432 } 433 Object o = m_keyCache.get(key); 434 if (o != null) { 435 return ((CmsFlexCacheVariation)o).m_map.keySet(); 436 } 437 return null; 438 } 439 440 445 public CmsLruCache getEntryLruCache() { 446 447 return m_variationCache; 448 } 449 450 456 public boolean isEnabled() { 457 458 return m_enabled; 459 } 460 461 466 public int keySize() { 467 468 if (!isEnabled()) { 469 return 0; 470 } 471 return m_keyCache.size(); 472 } 473 474 479 public int size() { 480 481 return m_variationCache.size(); 482 } 483 484 488 protected void finalize() throws Throwable { 489 490 try { 491 clear(); 492 m_variationCache = null; 493 m_keyCache = null; 494 } catch (Throwable t) { 495 } 497 super.finalize(); 498 } 499 500 510 CmsFlexCacheEntry get(CmsFlexRequestKey key) { 511 512 if (!isEnabled()) { 513 return null; 515 } 516 Object o = m_keyCache.get(key.getResource()); 517 if (o != null) { 518 CmsFlexCacheVariation v = (CmsFlexCacheVariation)o; 520 String variation = v.m_key.matchRequestKey(key); 521 522 if (CmsStringUtil.isEmpty(variation)) { 523 return null; 525 } 526 CmsFlexCacheEntry entry = (CmsFlexCacheEntry)v.m_map.get(variation); 527 if (entry == null) { 528 return null; 530 } 531 if (entry.getDateExpires() < System.currentTimeMillis()) { 532 m_variationCache.remove(entry); 534 return null; 535 } 536 return entry; 538 } else { 539 return null; 540 } 541 } 542 543 549 CmsFlexCacheKey getKey(String resource) { 550 551 if (!isEnabled()) { 552 return null; 553 } 554 Object o = m_keyCache.get(resource); 555 if (o != null) { 556 if (LOG.isDebugEnabled()) { 557 LOG.debug(Messages.get().getBundle().key(Messages.LOG_FLEXCACHEKEY_FOUND_1, resource)); 558 } 559 return ((CmsFlexCacheVariation)o).m_key; 560 } else { 561 if (LOG.isDebugEnabled()) { 562 LOG.debug(Messages.get().getBundle().key(Messages.LOG_FLEXCACHEKEY_NOT_FOUND_1, resource)); 563 } 564 return null; 565 } 566 } 567 568 573 boolean isEmpty() { 574 575 if (!isEnabled()) { 576 return true; 577 } 578 return m_keyCache.isEmpty(); 579 } 580 581 595 boolean put(CmsFlexCacheKey key, CmsFlexCacheEntry entry, String variation) { 596 597 if (!isEnabled()) { 598 return false; 599 } 600 if (LOG.isDebugEnabled()) { 601 LOG.debug(Messages.get().getBundle().key(Messages.LOG_FLEXCACHE_ADD_ENTRY_1, key.getResource())); 602 } 603 if (variation != null) { 604 key.setVariation(variation); 606 if (LOG.isDebugEnabled()) { 607 LOG.debug(Messages.get().getBundle().key( 608 Messages.LOG_FLEXCACHE_ADD_ENTRY_WITH_VARIATION_2, 609 key.getResource(), 610 key.getVariation())); 611 } 612 put(key, entry); 613 return true; 616 } else { 617 if (LOG.isDebugEnabled()) { 619 LOG.debug(Messages.get().getBundle().key(Messages.LOG_FLEXCACHE_RESOURCE_NOT_CACHEABLE_0)); 620 } 621 return false; 622 } 623 } 624 625 630 void putKey(CmsFlexCacheKey key) { 631 632 if (!isEnabled()) { 633 return; 634 } 635 Object o = m_keyCache.get(key.getResource()); 636 if (o == null) { 637 CmsFlexCacheVariation variationMap = new CmsFlexCacheVariation(key); 639 m_keyCache.put(key.getResource(), variationMap); 640 if (LOG.isDebugEnabled()) { 641 LOG.debug(Messages.get().getBundle().key(Messages.LOG_FLEXCACHE_ADD_KEY_1, key.getResource())); 642 } 643 } 644 } 646 647 652 void remove(CmsFlexCacheKey key) { 653 654 if (!isEnabled()) { 655 return; 656 } 657 Object o = m_keyCache.get(key.getResource()); 658 if (o != null) { 659 Object old = ((HashMap )o).get(key.getVariation()); 661 if (old != null) { 662 getEntryLruCache().remove((I_CmsLruCacheObject)old); 663 } 664 } 665 } 666 667 670 private synchronized void clear() { 671 672 if (!isEnabled()) { 673 return; 674 } 675 m_keyCache.clear(); 676 m_size = 0; 677 678 m_variationCache.clear(); 679 680 if (LOG.isInfoEnabled()) { 681 LOG.info(Messages.get().getBundle().key(Messages.LOG_FLEXCACHE_CLEAR_0)); 682 } 683 } 684 685 697 private synchronized void clearAccordingToSuffix(String suffix, boolean entriesOnly) { 698 699 Set keys = new HashSet (m_keyCache.keySet()); 700 Iterator i = keys.iterator(); 701 while (i.hasNext()) { 702 String s = (String )i.next(); 703 if (s.endsWith(suffix)) { 704 CmsFlexCacheVariation v = (CmsFlexCacheVariation)m_keyCache.get(s); 705 if (entriesOnly) { 706 m_size -= v.m_map.size(); 708 Iterator allEntries = v.m_map.values().iterator(); 709 while (allEntries.hasNext()) { 710 I_CmsLruCacheObject nextObject = (I_CmsLruCacheObject)allEntries.next(); 711 allEntries.remove(); 712 m_variationCache.remove(nextObject); 713 } 714 v.m_map = new Hashtable (INITIAL_CAPACITY_VARIATIONS); 715 } else { 716 m_size -= v.m_map.size(); 718 Iterator allEntries = v.m_map.values().iterator(); 719 while (allEntries.hasNext()) { 720 I_CmsLruCacheObject nextObject = (I_CmsLruCacheObject)allEntries.next(); 721 allEntries.remove(); 722 m_variationCache.remove(nextObject); 723 } 724 725 v.m_map = null; 726 v.m_key = null; 727 m_keyCache.remove(s); 728 } 729 } 730 } 731 if (LOG.isInfoEnabled()) { 732 LOG.info(Messages.get().getBundle().key( 733 Messages.LOG_FLEXCACHE_CLEAR_HALF_2, 734 suffix, 735 new Boolean (entriesOnly))); 736 } 737 } 738 739 747 private synchronized void clearEntries() { 748 749 if (!isEnabled()) { 750 return; 751 } 752 if (LOG.isInfoEnabled()) { 753 LOG.info(Messages.get().getBundle().key(Messages.LOG_FLEXCACHE_CLEAR_ALL_0)); 754 } 755 Set cacheKeys = new HashSet (m_keyCache.keySet()); 757 Iterator i = cacheKeys.iterator(); 758 while (i.hasNext()) { 759 CmsFlexCacheVariation v = (CmsFlexCacheVariation)m_keyCache.get(i.next()); 760 Iterator allEntries = v.m_map.values().iterator(); 761 while (allEntries.hasNext()) { 762 I_CmsLruCacheObject nextObject = (I_CmsLruCacheObject)allEntries.next(); 763 allEntries.remove(); 764 m_variationCache.remove(nextObject); 765 } 766 v.m_map = new Hashtable (INITIAL_CAPACITY_VARIATIONS); 767 } 768 m_size = 0; 769 } 770 771 779 private void clearOffline() { 780 781 if (!isEnabled()) { 782 return; 783 } 784 if (LOG.isInfoEnabled()) { 785 LOG.info(Messages.get().getBundle().key(Messages.LOG_FLEXCACHE_CLEAR_KEYS_AND_ENTRIES_0)); 786 } 787 clearAccordingToSuffix(CACHE_OFFLINESUFFIX, false); 788 } 789 790 799 private void clearOfflineEntries() { 800 801 if (!isEnabled()) { 802 return; 803 } 804 if (LOG.isInfoEnabled()) { 805 LOG.info(Messages.get().getBundle().key(Messages.LOG_FLEXCACHE_CLEAR_OFFLINE_ENTRIES_0)); 806 } 807 clearAccordingToSuffix(CACHE_OFFLINESUFFIX, true); 808 } 809 810 818 private void clearOnline() { 819 820 if (!isEnabled()) { 821 return; 822 } 823 if (LOG.isInfoEnabled()) { 824 LOG.info(Messages.get().getBundle().key(Messages.LOG_FLEXCACHE_CLEAR_ONLINE_KEYS_AND_ENTRIES_0)); 825 } 826 clearAccordingToSuffix(CACHE_ONLINESUFFIX, false); 827 } 828 829 838 private void clearOnlineEntries() { 839 840 if (!isEnabled()) { 841 return; 842 } 843 if (LOG.isInfoEnabled()) { 844 LOG.info(Messages.get().getBundle().key(Messages.LOG_FLEXCACHE_CLEAR_ONLINE_ENTRIES_0)); 845 } 846 clearAccordingToSuffix(CACHE_ONLINESUFFIX, true); 847 } 848 849 859 private synchronized void purgeJspRepository() { 860 861 if (LOG.isInfoEnabled()) { 862 LOG.info(Messages.get().getBundle().key(Messages.LOG_FLEXCACHE_WILL_PURGE_JSP_REPOSITORY_0)); 863 } 864 865 File d; 866 d = new File (org.opencms.loader.CmsJspLoader.getJspRepository() + REPOSITORY_ONLINE + File.separator); 867 CmsFileUtil.purgeDirectory(d); 868 869 d = new File (org.opencms.loader.CmsJspLoader.getJspRepository() + REPOSITORY_OFFLINE + File.separator); 870 CmsFileUtil.purgeDirectory(d); 871 872 clear(); 873 if (LOG.isInfoEnabled()) { 874 LOG.info(Messages.get().getBundle().key(Messages.LOG_FLEXCACHE_PURGED_JSP_REPOSITORY_0)); 875 } 876 } 877 878 884 private void put(CmsFlexCacheKey key, CmsFlexCacheEntry theCacheEntry) { 885 886 Object o = m_keyCache.get(key.getResource()); 887 if (key.getTimeout() > 0) { 888 theCacheEntry.setDateExpiresToNextTimeout(key.getTimeout()); 889 } 890 if (o != null) { 891 Map m = ((CmsFlexCacheVariation)o).m_map; 893 boolean wasAdded = true; 894 if (!m.containsKey(key.getVariation())) { 895 wasAdded = m_variationCache.add(theCacheEntry); 896 } else { 897 wasAdded = m_variationCache.touch(theCacheEntry); 898 } 899 900 if (wasAdded) { 901 theCacheEntry.setVariationData(key.getVariation(), m); 902 m.put(key.getVariation(), theCacheEntry); 903 } 904 } else { 905 CmsFlexCacheVariation list = new CmsFlexCacheVariation(key); 907 908 boolean wasAdded = m_variationCache.add(theCacheEntry); 909 910 if (wasAdded) { 911 theCacheEntry.setVariationData(key.getVariation(), list.m_map); 912 list.m_map.put(key.getVariation(), theCacheEntry); 913 m_keyCache.put(key.getResource(), list); 914 } 915 } 916 917 if (LOG.isDebugEnabled()) { 918 LOG.debug(Messages.get().getBundle().key( 919 Messages.LOG_FLEXCACHE_ADDED_ENTRY_FOR_RESOURCE_WITH_VARIATION_3, 920 new Integer (m_size), 921 key.getResource(), 922 key.getVariation())); 923 LOG.debug(Messages.get().getBundle().key(Messages.LOG_FLEXCACHE_ADDED_ENTRY_1, theCacheEntry.toString())); 924 } 925 } 926 } | Popular Tags |