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