001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH (http://www.alkacon.com) 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * For further information about Alkacon Software GmbH, please see the 018 * company website: http://www.alkacon.com 019 * 020 * For further information about OpenCms, please see the 021 * project website: http://www.opencms.org 022 * 023 * You should have received a copy of the GNU Lesser General Public 024 * License along with this library; if not, write to the Free Software 025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 026 */ 027 028package org.opencms.flex; 029 030import org.opencms.cache.CmsLruCache; 031import org.opencms.cache.I_CmsLruCacheObject; 032import org.opencms.file.CmsObject; 033import org.opencms.loader.CmsJspLoader; 034import org.opencms.main.CmsLog; 035import org.opencms.main.I_CmsEventListener; 036import org.opencms.main.OpenCms; 037import org.opencms.security.CmsRole; 038import org.opencms.util.CmsCollectionsGenericWrapper; 039import org.opencms.util.CmsStringUtil; 040 041import java.util.Collection; 042import java.util.Collections; 043import java.util.HashSet; 044import java.util.Hashtable; 045import java.util.Iterator; 046import java.util.Map; 047import java.util.Set; 048 049import org.apache.commons.collections.map.LRUMap; 050import org.apache.commons.logging.Log; 051 052/** 053 * This class implements the FlexCache.<p> 054 * 055 * The data structure used is a two-level hashtable. 056 * This is optimized for the structure of the keys that are used to describe the 057 * caching behaviour of the entries. 058 * The first hash-level is calculated from the resource name, i.e. the 059 * name of the resource as it is referred to in the VFS of OpenCms. 060 * The second hash-level is calculated from the cache-key of the resource, 061 * which also is a String representing the specifc variation of the cached entry.<p> 062 * 063 * A suffix [online] or [offline] is appended to te resource name 064 * to distinguish between the online and offline projects of OpenCms. 065 * Also, for support of JSP based workplace pages, a suffix [workplace] 066 * is appended. The same cached workplace pages are used both in the online and 067 * all offline projects.<p> 068 * 069 * Entries in the first level of the cache are of type CmsFlexCacheVariation, 070 * which is a sub-class of CmsFlexCache. 071 * This class is a simple data type that contains of a Map of CmsFlexCacheEntries, 072 * with variations - Strings as keys.<p> 073 * 074 * Here's a short summary of used terms: 075 * <ul> 076 * <li><b>key:</b> 077 * A combination of a resource name and a variation. 078 * The data structure used is CmsFlexCacheKey. 079 * <li><b>resource:</b> 080 * A String with the resource name and an appended [online] of [offline] suffix. 081 * <li><b>variation:</b> 082 * A String describing a variation of a cached entry in the CmsFlexCache language. 083 * <li><b>entry:</b> 084 * A CmsFlexCacheEntry data structure which is describes a cached OpenCms resource. 085 * For every entry a key is saved which contains the resource name and the variation. 086 * </ul> 087 * 088 * Cache clearing is handled using events. 089 * The cache is fully flushed if an event {@link I_CmsEventListener#EVENT_PUBLISH_PROJECT} 090 * or {@link I_CmsEventListener#EVENT_CLEAR_CACHES} is caught.<p> 091 * 092 * @since 6.0.0 093 * 094 * @see org.opencms.flex.CmsFlexCacheKey 095 * @see org.opencms.flex.CmsFlexCacheEntry 096 * @see org.opencms.cache.CmsLruCache 097 * @see org.opencms.cache.I_CmsLruCacheObject 098 */ 099public class CmsFlexCache extends Object implements I_CmsEventListener { 100 101 /** 102 * A simple data container class for the FlexCache variations.<p> 103 */ 104 public static class CmsFlexCacheVariation extends Object { 105 106 /** The key belonging to the resource. */ 107 public CmsFlexCacheKey m_key; 108 109 /** Maps variations to CmsFlexCacheEntries. */ 110 public Map<String, I_CmsLruCacheObject> m_map; 111 112 /** 113 * Generates a new instance of CmsFlexCacheVariation.<p> 114 * 115 * @param theKey The (resource) key to contruct this variation list for 116 */ 117 public CmsFlexCacheVariation(CmsFlexCacheKey theKey) { 118 119 m_key = theKey; 120 m_map = new Hashtable<String, I_CmsLruCacheObject>(INITIAL_CAPACITY_VARIATIONS); 121 } 122 } 123 124 /** 125 * Extended LRUMap that handles the variations in case a key is removed.<p> 126 */ 127 class CmsFlexKeyMap extends LRUMap { 128 129 /** Serial version UID required for safe serialization. */ 130 private static final long serialVersionUID = 6931995916013396902L; 131 132 /** 133 * Initialize the map with the given size.<p> 134 * 135 * @param maxSize the maximum number of key to cache 136 */ 137 public CmsFlexKeyMap(int maxSize) { 138 139 super(maxSize); 140 } 141 142 /** 143 * Ensures that all variations that referenced by this key are released 144 * if the key is released.<p> 145 * 146 * @param entry the entry to remove 147 * 148 * @return <code>true</code> to actually delete the entry 149 * 150 * @see LRUMap#removeLRU(LinkEntry) 151 */ 152 @Override 153 protected boolean removeLRU(LinkEntry entry) { 154 155 CmsFlexCacheVariation v = (CmsFlexCacheVariation)entry.getValue(); 156 if (v == null) { 157 return true; 158 } 159 Map<String, I_CmsLruCacheObject> m = v.m_map; 160 if ((m == null) || (m.size() == 0)) { 161 return true; 162 } 163 Collection<I_CmsLruCacheObject> entries = m.values(); 164 synchronized (m_variationCache) { 165 for (I_CmsLruCacheObject e : entries) { 166 m_variationCache.remove(e); 167 } 168 v.m_map.clear(); 169 v.m_map = null; 170 v.m_key = null; 171 } 172 return true; 173 } 174 } 175 176 /** Suffix to append to online cache entries. */ 177 public static final String CACHE_OFFLINESUFFIX = " [offline]"; 178 179 /** Suffix to append to online cache entries. */ 180 public static final String CACHE_ONLINESUFFIX = " [online]"; 181 182 /** Trigger for clearcache event: Clear complete cache. */ 183 public static final int CLEAR_ALL = 0; 184 185 /** Trigger for clearcache event: Clear only entries. */ 186 public static final int CLEAR_ENTRIES = 1; 187 188 /** Trigger for clearcache event: Clear complete offine cache. */ 189 public static final int CLEAR_OFFLINE_ALL = 4; 190 191 /** Trigger for clearcache event: Clear only offline entries. */ 192 public static final int CLEAR_OFFLINE_ENTRIES = 5; 193 194 /** Trigger for clearcache event: Clear complete online cache. */ 195 public static final int CLEAR_ONLINE_ALL = 2; 196 197 /** Trigger for clearcache event: Clear only online entries. */ 198 public static final int CLEAR_ONLINE_ENTRIES = 3; 199 200 /** Initial cache size, this should be a power of 2 because of the Java collections implementation. */ 201 public static final int INITIAL_CAPACITY_CACHE = 512; 202 203 /** Initial size for variation lists, should be a power of 2. */ 204 public static final int INITIAL_CAPACITY_VARIATIONS = 8; 205 206 /** Offline repository constant. */ 207 public static final String REPOSITORY_OFFLINE = "offline"; 208 209 /** Online repository constant. */ 210 public static final String REPOSITORY_ONLINE = "online"; 211 212 /** The log object for this class. */ 213 private static final Log LOG = CmsLog.getLog(CmsFlexCache.class); 214 215 /** The LRU cache to organize the cached entries. */ 216 protected CmsLruCache m_variationCache; 217 218 /** Indicates if offline resources should be cached or not. */ 219 private boolean m_cacheOffline; 220 221 /** Indicates if the cache is enabled or not. */ 222 private boolean m_enabled; 223 224 /** Map to store the entries for fast lookup. */ 225 private Map<String, CmsFlexCacheVariation> m_keyCache; 226 227 /** Counter for the size. */ 228 private int m_size; 229 230 /** 231 * Constructor for class CmsFlexCache.<p> 232 * 233 * The parameter "enabled" is used to control if the cache is 234 * actually on or off. Even if you don't need the cache, you still 235 * have to create an instance of it with enabled=false. 236 * This is because you need some of the FlexCache data structures 237 * for JSP inclusion buffering.<p> 238 * 239 * @param configuration the flex cache configuration 240 */ 241 public CmsFlexCache(CmsFlexCacheConfiguration configuration) { 242 243 m_enabled = configuration.isCacheEnabled(); 244 m_cacheOffline = configuration.isCacheOffline(); 245 246 long maxCacheBytes = configuration.getMaxCacheBytes(); 247 long avgCacheBytes = configuration.getAvgCacheBytes(); 248 int maxEntryBytes = configuration.getMaxEntryBytes(); 249 int maxKeys = configuration.getMaxKeys(); 250 251 m_variationCache = new CmsLruCache(maxCacheBytes, avgCacheBytes, maxEntryBytes); 252 OpenCms.getMemoryMonitor().register(getClass().getName() + ".m_entryLruCache", m_variationCache); 253 254 if (m_enabled) { 255 CmsFlexKeyMap flexKeyMap = new CmsFlexKeyMap(maxKeys); 256 m_keyCache = Collections.synchronizedMap( 257 CmsCollectionsGenericWrapper.<String, CmsFlexCacheVariation> map(flexKeyMap)); 258 OpenCms.getMemoryMonitor().register(getClass().getName() + ".m_resourceMap", flexKeyMap); 259 260 OpenCms.addCmsEventListener( 261 this, 262 new int[] { 263 I_CmsEventListener.EVENT_PUBLISH_PROJECT, 264 I_CmsEventListener.EVENT_CLEAR_CACHES, 265 I_CmsEventListener.EVENT_FLEX_PURGE_JSP_REPOSITORY, 266 I_CmsEventListener.EVENT_FLEX_CACHE_CLEAR}); 267 } 268 269 if (LOG.isInfoEnabled()) { 270 LOG.info( 271 Messages.get().getBundle().key( 272 Messages.INIT_FLEXCACHE_CREATED_2, 273 Boolean.valueOf(m_enabled), 274 Boolean.valueOf(m_cacheOffline))); 275 } 276 } 277 278 /** 279 * Indicates if offline project resources are cached.<p> 280 * 281 * @return true if offline projects are cached, false if not 282 */ 283 public boolean cacheOffline() { 284 285 return m_cacheOffline; 286 } 287 288 /** 289 * Implements the CmsEvent interface, 290 * the FlexCache uses the events to clear itself in case a project is published.<p> 291 * 292 * @param event CmsEvent that has occurred 293 */ 294 public void cmsEvent(org.opencms.main.CmsEvent event) { 295 296 if (!isEnabled()) { 297 return; 298 } 299 300 switch (event.getType()) { 301 case I_CmsEventListener.EVENT_PUBLISH_PROJECT: 302 case I_CmsEventListener.EVENT_CLEAR_CACHES: 303 if (LOG.isDebugEnabled()) { 304 LOG.debug(Messages.get().getBundle().key(Messages.LOG_FLEXCACHE_RECEIVED_EVENT_CLEAR_CACHE_0)); 305 } 306 clear(); 307 break; 308 case I_CmsEventListener.EVENT_FLEX_PURGE_JSP_REPOSITORY: 309 if (LOG.isDebugEnabled()) { 310 LOG.debug(Messages.get().getBundle().key(Messages.LOG_FLEXCACHE_RECEIVED_EVENT_PURGE_REPOSITORY_0)); 311 } 312 purgeJspRepository(); 313 break; 314 case I_CmsEventListener.EVENT_FLEX_CACHE_CLEAR: 315 if (LOG.isDebugEnabled()) { 316 LOG.debug( 317 Messages.get().getBundle().key(Messages.LOG_FLEXCACHE_RECEIVED_EVENT_CLEAR_CACHE_PARTIALLY_0)); 318 } 319 Map<String, ?> m = event.getData(); 320 if (m == null) { 321 break; 322 } 323 Integer it = null; 324 try { 325 it = (Integer)m.get("action"); 326 } catch (Exception e) { 327 // it will be null 328 } 329 if (it == null) { 330 break; 331 } 332 int i = it.intValue(); 333 switch (i) { 334 case CLEAR_ALL: 335 clear(); 336 break; 337 case CLEAR_ENTRIES: 338 clearEntries(); 339 break; 340 case CLEAR_ONLINE_ALL: 341 clearOnline(); 342 break; 343 case CLEAR_ONLINE_ENTRIES: 344 clearOnlineEntries(); 345 break; 346 case CLEAR_OFFLINE_ALL: 347 clearOffline(); 348 break; 349 case CLEAR_OFFLINE_ENTRIES: 350 clearOfflineEntries(); 351 break; 352 default: 353 // no operation 354 } 355 break; 356 default: 357 // no operation 358 } 359 } 360 361 /** 362 * Returns the CmsFlexCacheKey data structure for a given 363 * key (i.e. resource name).<p> 364 * 365 * Useful if you want to show the cache key for a resources, 366 * like on the FlexCache administration page.<p> 367 * 368 * Only users with administrator permissions are allowed 369 * to perform this operation.<p> 370 * 371 * @param key the resource name for which to look up the variation for 372 * @param cms the CmsObject used for user authorization 373 * @return the CmsFlexCacheKey data structure found for the resource 374 */ 375 public CmsFlexCacheKey getCachedKey(String key, CmsObject cms) { 376 377 if (!isEnabled() || !OpenCms.getRoleManager().hasRole(cms, CmsRole.WORKPLACE_MANAGER)) { 378 return null; 379 } 380 Object o = m_keyCache.get(key); 381 if (o != null) { 382 return ((CmsFlexCacheVariation)o).m_key; 383 } 384 return null; 385 } 386 387 /** 388 * Returns a set of all cached resource names.<p> 389 * 390 * Useful if you want to show a list of all cached resources, 391 * like on the FlexCache administration page.<p> 392 * 393 * Only users with administrator permissions are allowed 394 * to perform this operation.<p> 395 * 396 * @param cms the CmsObject used for user authorization 397 * @return a Set of cached resource names (which are of type String) 398 */ 399 public Set<String> getCachedResources(CmsObject cms) { 400 401 if (!isEnabled() || !OpenCms.getRoleManager().hasRole(cms, CmsRole.WORKPLACE_MANAGER)) { 402 return null; 403 } 404 return m_keyCache.keySet(); 405 } 406 407 /** 408 * Returns all variations in the cache for a given resource name. 409 * The variations are of type String.<p> 410 * 411 * Useful if you want to show a list of all cached entry - variations, 412 * like on the FlexCache administration page.<p> 413 * 414 * Only users with administrator permissions are allowed 415 * to perform this operation.<p> 416 * 417 * @param key the resource name for which to look up the variations for 418 * @param cms the CmsObject used for user authorization 419 * @return a Set of cached variations (which are of type String) 420 */ 421 public Set<String> getCachedVariations(String key, CmsObject cms) { 422 423 if (!isEnabled() || !OpenCms.getRoleManager().hasRole(cms, CmsRole.WORKPLACE_MANAGER)) { 424 return null; 425 } 426 Object o = m_keyCache.get(key); 427 if (o != null) { 428 return ((CmsFlexCacheVariation)o).m_map.keySet(); 429 } 430 return null; 431 } 432 433 /** 434 * Returns the LRU cache where the CacheEntries are cached.<p> 435 * 436 * @return the LRU cache where the CacheEntries are cached 437 */ 438 public CmsLruCache getEntryLruCache() { 439 440 return m_variationCache; 441 } 442 443 /** 444 * Indicates if the cache is enabled (i.e. actually 445 * caching entries) or not.<p> 446 * 447 * @return true if the cache is enabled, false if not 448 */ 449 public boolean isEnabled() { 450 451 return m_enabled; 452 } 453 454 /** 455 * Returns the total number of cached resource keys. 456 * 457 * @return the number of resource keys in the cache 458 */ 459 public int keySize() { 460 461 if (!isEnabled()) { 462 return 0; 463 } 464 return m_keyCache.size(); 465 } 466 467 /** 468 * Returns the total number of entries in the cache.<p> 469 * 470 * @return the number of entries in the cache 471 */ 472 public int size() { 473 474 return m_variationCache.size(); 475 } 476 477 /** 478 * Looks up a specific entry in the cache.<p> 479 * 480 * In case a found entry has a timeout set, it will be checked upon lookup. 481 * In case the timeout of the entry has been reached, it will be removed from 482 * the cache (and null will be returned in this case).<p> 483 * 484 * @param key The key to look for in the cache 485 * @return the entry found for the key, or null if key is not in the cache 486 */ 487 CmsFlexCacheEntry get(CmsFlexRequestKey key) { 488 489 if (!isEnabled()) { 490 // cache is disabled 491 return null; 492 } 493 Object o = m_keyCache.get(key.getResource()); 494 if (o != null) { 495 // found a matching key in the cache 496 CmsFlexCacheVariation v = (CmsFlexCacheVariation)o; 497 String variation = v.m_key.matchRequestKey(key); 498 499 if (CmsStringUtil.isEmpty(variation)) { 500 // requested resource is not cacheable 501 return null; 502 } 503 CmsFlexCacheEntry entry = (CmsFlexCacheEntry)v.m_map.get(variation); 504 if (entry == null) { 505 // no cache entry available for variation 506 return null; 507 } 508 if (entry.getDateExpires() < System.currentTimeMillis()) { 509 // cache entry avaiable but expired, remove entry 510 m_variationCache.remove(entry); 511 return null; 512 } 513 // return the found cache entry 514 return entry; 515 } else { 516 return null; 517 } 518 } 519 520 /** 521 * Returns the CmsFlexCacheKey data structure for a given resource name.<p> 522 * 523 * @param resource the resource name for which to look up the key for 524 * @return the CmsFlexCacheKey data structure found for the resource 525 */ 526 CmsFlexCacheKey getKey(String resource) { 527 528 if (!isEnabled()) { 529 return null; 530 } 531 Object o = m_keyCache.get(resource); 532 if (o != null) { 533 if (LOG.isDebugEnabled()) { 534 LOG.debug(Messages.get().getBundle().key(Messages.LOG_FLEXCACHEKEY_FOUND_1, resource)); 535 } 536 return ((CmsFlexCacheVariation)o).m_key; 537 } else { 538 if (LOG.isDebugEnabled()) { 539 LOG.debug(Messages.get().getBundle().key(Messages.LOG_FLEXCACHEKEY_NOT_FOUND_1, resource)); 540 } 541 return null; 542 } 543 } 544 545 /** 546 * Checks if the cache is empty or if at last one element is contained.<p> 547 * 548 * @return true if the cache is empty, false otherwise 549 */ 550 boolean isEmpty() { 551 552 if (!isEnabled()) { 553 return true; 554 } 555 return m_keyCache.isEmpty(); 556 } 557 558 /** 559 * This method adds new entries to the cache.<p> 560 * 561 * The key describes the conditions under which the value can be cached. 562 * Usually the key belongs to the response. 563 * The variation describes the conditions under which the 564 * entry was created. This is usually calculated from the request. 565 * If the variation is != null, the entry is cachable.<p> 566 * 567 * @param key the key for the new value entry 568 * @param entry the CmsFlexCacheEntry to store in the cache 569 * @param variation the pre-calculated variation for the entry 570 * @return true if the value was added to the cache, false otherwise 571 */ 572 boolean put(CmsFlexCacheKey key, CmsFlexCacheEntry entry, String variation) { 573 574 if (!isEnabled()) { 575 return false; 576 } 577 if (LOG.isDebugEnabled()) { 578 LOG.debug(Messages.get().getBundle().key(Messages.LOG_FLEXCACHE_ADD_ENTRY_1, key.getResource())); 579 } 580 if (variation != null) { 581 // This is a cachable result 582 key.setVariation(variation); 583 if (LOG.isDebugEnabled()) { 584 LOG.debug( 585 Messages.get().getBundle().key( 586 Messages.LOG_FLEXCACHE_ADD_ENTRY_WITH_VARIATION_2, 587 key.getResource(), 588 key.getVariation())); 589 } 590 put(key, entry); 591 // Note that duplicates are NOT checked, it it assumed that this is done beforehand, 592 // while checking if the entry is already in the cache or not. 593 return true; 594 } else { 595 // Result is not cachable 596 if (LOG.isDebugEnabled()) { 597 LOG.debug(Messages.get().getBundle().key(Messages.LOG_FLEXCACHE_RESOURCE_NOT_CACHEABLE_0)); 598 } 599 return false; 600 } 601 } 602 603 /** 604 * Adds a key with a new, empty variation map to the cache.<p> 605 * 606 * @param key the key to add to the cache. 607 */ 608 void putKey(CmsFlexCacheKey key) { 609 610 if (!isEnabled()) { 611 return; 612 } 613 Object o = m_keyCache.get(key.getResource()); 614 if (o == null) { 615 // No variation map for this resource yet, so create one 616 CmsFlexCacheVariation variationMap = new CmsFlexCacheVariation(key); 617 m_keyCache.put(key.getResource(), variationMap); 618 if (LOG.isDebugEnabled()) { 619 LOG.debug(Messages.get().getBundle().key(Messages.LOG_FLEXCACHE_ADD_KEY_1, key.getResource())); 620 } 621 } 622 // If != null the key is already in the cache, so we just do nothing 623 } 624 625 /** 626 * Removes an entry from the cache.<p> 627 * 628 * @param key the key which describes the entry to remove from the cache 629 */ 630 void remove(CmsFlexCacheKey key) { 631 632 if (!isEnabled()) { 633 return; 634 } 635 CmsFlexCacheVariation o = m_keyCache.get(key.getResource()); 636 if (o != null) { 637 I_CmsLruCacheObject old = o.m_map.get(key.getVariation()); 638 if (old != null) { 639 getEntryLruCache().remove(old); 640 } 641 } 642 } 643 644 /** 645 * Empties the cache completely.<p> 646 */ 647 private synchronized void clear() { 648 649 if (!isEnabled()) { 650 return; 651 } 652 m_keyCache.clear(); 653 m_size = 0; 654 655 m_variationCache.clear(); 656 657 if (LOG.isInfoEnabled()) { 658 LOG.info(Messages.get().getBundle().key(Messages.LOG_FLEXCACHE_CLEAR_0)); 659 } 660 } 661 662 /** 663 * Internal method to perform cache clearance.<p> 664 * 665 * It clears "one half" of the cache, i.e. either 666 * the online or the offline parts. 667 * A parameter is used to indicate if only 668 * the entries or keys and entries are to be cleared.<p> 669 * 670 * @param suffix used to distinguish between "[Online]" and "[Offline]" entries 671 * @param entriesOnly if <code>true</code>, only entries will be cleared, otherwise 672 * the entries and the keys will be cleared 673 */ 674 private synchronized void clearAccordingToSuffix(String suffix, boolean entriesOnly) { 675 676 Set<String> keys = new HashSet<String>(m_keyCache.keySet()); 677 Iterator<String> i = keys.iterator(); 678 while (i.hasNext()) { 679 String s = i.next(); 680 if (s.endsWith(suffix)) { 681 CmsFlexCacheVariation v = m_keyCache.get(s); 682 if (entriesOnly) { 683 // Clear only entry 684 m_size -= v.m_map.size(); 685 Iterator<I_CmsLruCacheObject> allEntries = v.m_map.values().iterator(); 686 while (allEntries.hasNext()) { 687 I_CmsLruCacheObject nextObject = allEntries.next(); 688 allEntries.remove(); 689 m_variationCache.remove(nextObject); 690 } 691 v.m_map = new Hashtable<String, I_CmsLruCacheObject>(INITIAL_CAPACITY_VARIATIONS); 692 } else { 693 // Clear key and entry 694 m_size -= v.m_map.size(); 695 Iterator<I_CmsLruCacheObject> allEntries = v.m_map.values().iterator(); 696 while (allEntries.hasNext()) { 697 I_CmsLruCacheObject nextObject = allEntries.next(); 698 allEntries.remove(); 699 m_variationCache.remove(nextObject); 700 } 701 702 v.m_map = null; 703 v.m_key = null; 704 m_keyCache.remove(s); 705 } 706 } 707 } 708 if (LOG.isInfoEnabled()) { 709 LOG.info( 710 Messages.get().getBundle().key( 711 Messages.LOG_FLEXCACHE_CLEAR_HALF_2, 712 suffix, 713 Boolean.valueOf(entriesOnly))); 714 } 715 } 716 717 /** 718 * Clears all entries in the cache, online or offline.<p> 719 * 720 * The keys are not cleared.<p> 721 * 722 * Only users with administrator permissions are allowed 723 * to perform this operation.<p> 724 */ 725 private synchronized void clearEntries() { 726 727 if (!isEnabled()) { 728 return; 729 } 730 if (LOG.isInfoEnabled()) { 731 LOG.info(Messages.get().getBundle().key(Messages.LOG_FLEXCACHE_CLEAR_ALL_0)); 732 } 733 // create new set to avoid ConcurrentModificationExceptions 734 Set<String> cacheKeys = new HashSet<String>(m_keyCache.keySet()); 735 Iterator<String> i = cacheKeys.iterator(); 736 while (i.hasNext()) { 737 CmsFlexCacheVariation v = m_keyCache.get(i.next()); 738 Iterator<I_CmsLruCacheObject> allEntries = v.m_map.values().iterator(); 739 while (allEntries.hasNext()) { 740 I_CmsLruCacheObject nextObject = allEntries.next(); 741 allEntries.remove(); 742 m_variationCache.remove(nextObject); 743 } 744 v.m_map = new Hashtable<String, I_CmsLruCacheObject>(INITIAL_CAPACITY_VARIATIONS); 745 } 746 m_size = 0; 747 } 748 749 /** 750 * Clears all entries and all keys from offline projects in the cache.<p> 751 * 752 * Cached resources from the online project are not touched.<p> 753 * 754 * Only users with administrator permissions are allowed 755 * to perform this operation.<p> 756 */ 757 private void clearOffline() { 758 759 if (!isEnabled()) { 760 return; 761 } 762 if (LOG.isInfoEnabled()) { 763 LOG.info(Messages.get().getBundle().key(Messages.LOG_FLEXCACHE_CLEAR_KEYS_AND_ENTRIES_0)); 764 } 765 clearAccordingToSuffix(CACHE_OFFLINESUFFIX, false); 766 } 767 768 /** 769 * Clears all entries from offline projects in the cache.<p> 770 * 771 * The keys from the offline projects are not cleared. 772 * Cached resources from the online project are not touched.<p> 773 * 774 * Only users with administrator permissions are allowed 775 * to perform this operation.<p> 776 */ 777 private void clearOfflineEntries() { 778 779 if (!isEnabled()) { 780 return; 781 } 782 if (LOG.isInfoEnabled()) { 783 LOG.info(Messages.get().getBundle().key(Messages.LOG_FLEXCACHE_CLEAR_OFFLINE_ENTRIES_0)); 784 } 785 clearAccordingToSuffix(CACHE_OFFLINESUFFIX, true); 786 } 787 788 /** 789 * Clears all entries and all keys from the online project in the cache.<p> 790 * 791 * Cached resources from the offline projects are not touched.<p> 792 * 793 * Only users with administrator permissions are allowed 794 * to perform this operation.<p> 795 */ 796 private void clearOnline() { 797 798 if (!isEnabled()) { 799 return; 800 } 801 if (LOG.isInfoEnabled()) { 802 LOG.info(Messages.get().getBundle().key(Messages.LOG_FLEXCACHE_CLEAR_ONLINE_KEYS_AND_ENTRIES_0)); 803 } 804 clearAccordingToSuffix(CACHE_ONLINESUFFIX, false); 805 } 806 807 /** 808 * Clears all entries from the online project in the cache.<p> 809 * 810 * The keys from the online project are not cleared. 811 * Cached resources from the offline projects are not touched.<p> 812 * 813 * Only users with administrator permissions are allowed 814 * to perform this operation.<p> 815 */ 816 private void clearOnlineEntries() { 817 818 if (!isEnabled()) { 819 return; 820 } 821 if (LOG.isInfoEnabled()) { 822 LOG.info(Messages.get().getBundle().key(Messages.LOG_FLEXCACHE_CLEAR_ONLINE_ENTRIES_0)); 823 } 824 clearAccordingToSuffix(CACHE_ONLINESUFFIX, true); 825 } 826 827 /** 828 * This method purges the JSP repository dirs, 829 * i.e. it deletes all JSP files that OpenCms has written to the 830 * real FS.<p> 831 * 832 * Obviously this method must be used with caution. 833 * Purpose of this method is to allow 834 * a complete purge of all JSP pages on a machine after 835 * a major update of JSP templates was made.<p> 836 */ 837 private synchronized void purgeJspRepository() { 838 839 CmsJspLoader cmsJspLoader = (CmsJspLoader)OpenCms.getResourceManager().getLoader( 840 CmsJspLoader.RESOURCE_LOADER_ID); 841 842 cmsJspLoader.triggerPurge(new Runnable() { 843 844 @SuppressWarnings("synthetic-access") 845 public void run() { 846 847 clear(); 848 } 849 }); 850 } 851 852 /** 853 * Save a value to the cache.<p> 854 * 855 * @param key the key under which the value is saved 856 * @param theCacheEntry the entry to cache 857 */ 858 private void put(CmsFlexCacheKey key, CmsFlexCacheEntry theCacheEntry) { 859 860 CmsFlexCacheVariation o = m_keyCache.get(key.getResource()); 861 if (key.getTimeout() > 0) { 862 theCacheEntry.setDateExpiresToNextTimeout(key.getTimeout()); 863 } 864 if (o != null) { 865 // We already have a variation map for this resource 866 Map<String, I_CmsLruCacheObject> m = o.m_map; 867 boolean wasAdded = true; 868 if (!m.containsKey(key.getVariation())) { 869 wasAdded = m_variationCache.add(theCacheEntry); 870 } else { 871 wasAdded = m_variationCache.touch(theCacheEntry); 872 } 873 874 if (wasAdded) { 875 theCacheEntry.setVariationData(key.getVariation(), m); 876 m.put(key.getVariation(), theCacheEntry); 877 } 878 } else { 879 // No variation map for this resource yet, so create one 880 CmsFlexCacheVariation list = new CmsFlexCacheVariation(key); 881 882 boolean wasAdded = m_variationCache.add(theCacheEntry); 883 884 if (wasAdded) { 885 theCacheEntry.setVariationData(key.getVariation(), list.m_map); 886 list.m_map.put(key.getVariation(), theCacheEntry); 887 m_keyCache.put(key.getResource(), list); 888 } 889 } 890 891 if (LOG.isDebugEnabled()) { 892 LOG.debug( 893 Messages.get().getBundle().key( 894 Messages.LOG_FLEXCACHE_ADDED_ENTRY_FOR_RESOURCE_WITH_VARIATION_3, 895 new Integer(m_size), 896 key.getResource(), 897 key.getVariation())); 898 LOG.debug(Messages.get().getBundle().key(Messages.LOG_FLEXCACHE_ADDED_ENTRY_1, theCacheEntry.toString())); 899 } 900 } 901}