001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH & Co. KG (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 & Co. KG, 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.monitor; 029 030import org.opencms.cache.CmsLruCache; 031import org.opencms.cache.CmsMemoryObjectCache; 032import org.opencms.cache.CmsVfsMemoryObjectCache; 033import org.opencms.configuration.CmsSystemConfiguration; 034import org.opencms.db.CmsCacheSettings; 035import org.opencms.db.CmsDriverManager; 036import org.opencms.db.CmsPublishedResource; 037import org.opencms.db.CmsSecurityManager; 038import org.opencms.file.CmsFile; 039import org.opencms.file.CmsGroup; 040import org.opencms.file.CmsObject; 041import org.opencms.file.CmsProject; 042import org.opencms.file.CmsProperty; 043import org.opencms.file.CmsPropertyDefinition; 044import org.opencms.file.CmsResource; 045import org.opencms.file.CmsUser; 046import org.opencms.flex.CmsFlexCache.CmsFlexCacheVariation; 047import org.opencms.i18n.CmsLocaleManager; 048import org.opencms.lock.CmsLock; 049import org.opencms.lock.CmsLockManager; 050import org.opencms.mail.CmsMailTransport; 051import org.opencms.mail.CmsSimpleMail; 052import org.opencms.main.CmsEvent; 053import org.opencms.main.CmsLog; 054import org.opencms.main.CmsSessionManager; 055import org.opencms.main.I_CmsEventListener; 056import org.opencms.main.OpenCms; 057import org.opencms.publish.CmsPublishHistory; 058import org.opencms.publish.CmsPublishJobInfoBean; 059import org.opencms.publish.CmsPublishQueue; 060import org.opencms.scheduler.I_CmsScheduledJob; 061import org.opencms.security.CmsAccessControlList; 062import org.opencms.security.CmsOrganizationalUnit; 063import org.opencms.security.CmsPermissionSet; 064import org.opencms.security.CmsRole; 065import org.opencms.security.I_CmsPermissionHandler; 066import org.opencms.util.CmsDateUtil; 067import org.opencms.util.CmsStringUtil; 068import org.opencms.util.CmsUUID; 069import org.opencms.util.PrintfFormat; 070import org.opencms.xml.CmsXmlContentDefinition; 071import org.opencms.xml.CmsXmlEntityResolver; 072 073import java.util.ArrayList; 074import java.util.Collections; 075import java.util.ConcurrentModificationException; 076import java.util.Date; 077import java.util.HashMap; 078import java.util.Iterator; 079import java.util.List; 080import java.util.Locale; 081import java.util.Map; 082import java.util.concurrent.ConcurrentHashMap; 083 084import javax.mail.internet.InternetAddress; 085 086import org.apache.commons.collections.Buffer; 087import org.apache.commons.collections.buffer.SynchronizedBuffer; 088import org.apache.commons.collections.map.LRUMap; 089import org.apache.commons.logging.Log; 090 091import com.google.common.cache.CacheBuilder; 092 093/** 094 * Monitors OpenCms memory consumption.<p> 095 * 096 * The memory monitor also provides all kind of caches used in the OpenCms core.<p> 097 * 098 * @since 6.0.0 099 */ 100public class CmsMemoryMonitor implements I_CmsScheduledJob { 101 102 /** Cache types. */ 103 public enum CacheType { 104 /** Access Control Lists cache. */ 105 ACL, 106 /** Content Definition cache. */ 107 CONTENT_DEFINITION, 108 /** Group cache. */ 109 GROUP, 110 /** Has Role cache. */ 111 HAS_ROLE, 112 /** Locale cache. */ 113 LOCALE, 114 /** Lock cache. */ 115 LOCK, 116 /** Memory Object cache. */ 117 MEMORY_OBJECT, 118 /** Organizational Unit cache. */ 119 ORG_UNIT, 120 /** Permission cache. */ 121 PERMISSION, 122 /** Offline Project cache. */ 123 PROJECT, 124 /** Project resources cache. */ 125 PROJECT_RESOURCES, 126 /** Property cache. */ 127 PROPERTY, 128 /** Property List cache. */ 129 PROPERTY_LIST, 130 /** Publish history cache. */ 131 PUBLISH_HISTORY, 132 /** Publish queue cache. */ 133 PUBLISH_QUEUE, 134 /** Published resources cache. */ 135 PUBLISHED_RESOURCES, 136 /** Resource cache. */ 137 RESOURCE, 138 /** Resource List cache. */ 139 RESOURCE_LIST, 140 /** Role List cache. */ 141 ROLE_LIST, 142 /** User cache. */ 143 USER, 144 /** User list cache. */ 145 USER_LIST, 146 /** User Groups cache. */ 147 USERGROUPS, 148 /** VFS Object cache. */ 149 VFS_OBJECT, 150 /** XML Entity Permanent cache. */ 151 XML_ENTITY_PERM, 152 /** XML Entity Temporary cache. */ 153 XML_ENTITY_TEMP; 154 } 155 156 /** The concurrency level for the guava caches. */ 157 private static final int CONCURRENCY_LEVEL = 8; 158 159 /** Set interval for clearing the caches to 10 minutes. */ 160 private static final int INTERVAL_CLEAR = 1000 * 60 * 10; 161 162 /** The log object for this class. */ 163 private static final Log LOG = CmsLog.getLog(CmsMemoryMonitor.class); 164 165 /** Flag indicating if monitor is currently running. */ 166 private static boolean m_currentlyRunning; 167 168 /** Maximum depth for object size recursion. */ 169 private static final int MAX_DEPTH = 5; 170 171 /** Cache for access control lists. */ 172 private Map<String, CmsAccessControlList> m_cacheAccessControlList; 173 174 /** A temporary cache for XML content definitions. */ 175 private Map<String, CmsXmlContentDefinition> m_cacheContentDefinitions; 176 177 /** Cache for groups. */ 178 private Map<String, CmsGroup> m_cacheGroup; 179 180 /** Cache for roles. */ 181 private Map<String, Boolean> m_cacheHasRoles; 182 183 /** A cache for accelerated locale lookup. */ 184 private Map<String, Locale> m_cacheLocale; 185 186 /** Cache for the resource locks. */ 187 private Map<String, CmsLock> m_cacheLock; 188 189 /** The memory object cache map. */ 190 private Map<String, Object> m_cacheMemObject; 191 192 /** Cache for organizational units. */ 193 private Map<String, CmsOrganizationalUnit> m_cacheOrgUnit; 194 195 /** Cache for permission checks. */ 196 private Map<String, I_CmsPermissionHandler.CmsPermissionCheckResult> m_cachePermission; 197 198 /** Cache for offline projects. */ 199 private Map<String, CmsProject> m_cacheProject; 200 201 /** Cache for project resources. */ 202 private Map<String, List<CmsResource>> m_cacheProjectResources; 203 204 /** Cache for properties. */ 205 private Map<String, CmsProperty> m_cacheProperty; 206 207 /** Cache for property lists. */ 208 private Map<String, List<CmsProperty>> m_cachePropertyList; 209 210 /** Cache for published resources. */ 211 private Map<String, List<CmsPublishedResource>> m_cachePublishedResources; 212 213 /** Cache for resources. */ 214 private Map<String, CmsResource> m_cacheResource; 215 216 /** Cache for resource lists. */ 217 private Map<String, List<CmsResource>> m_cacheResourceList; 218 219 /** Cache for role lists. */ 220 private Map<String, List<CmsRole>> m_cacheRoleLists; 221 222 /** Cache for user data. */ 223 private Map<String, CmsUser> m_cacheUser; 224 225 /** Cache for user groups. */ 226 private Map<String, List<CmsGroup>> m_cacheUserGroups; 227 228 /** Cache for user lists. */ 229 private Map<String, List<CmsUser>> m_cacheUserList; 230 231 /** The vfs memory cache map. */ 232 private Map<String, Object> m_cacheVfsObject; 233 234 /** A permanent cache to avoid multiple readings of often used files from the VFS. */ 235 private Map<String, byte[]> m_cacheXmlPermanentEntity; 236 237 /** A temporary cache to avoid multiple readings of often used files from the VFS. */ 238 private Map<String, byte[]> m_cacheXmlTemporaryEntity; 239 240 /** The memory monitor configuration. */ 241 private CmsMemoryMonitorConfiguration m_configuration; 242 243 /** Map to keep track of disabled caches. */ 244 private Map<CacheType, Boolean> m_disabled = new HashMap<CacheType, Boolean>(); 245 246 /** Interval in which emails are send. */ 247 private int m_intervalEmail; 248 249 /** Interval in which the log is written. */ 250 private int m_intervalLog; 251 252 /** Interval between 2 warnings. */ 253 private int m_intervalWarning; 254 255 /** The time the caches were last cleared. */ 256 private long m_lastClearCache; 257 258 /** The time the last status email was send. */ 259 private long m_lastEmailStatus; 260 261 /** The time the last warning email was send. */ 262 private long m_lastEmailWarning; 263 264 /** The time the last status log was written. */ 265 private long m_lastLogStatus; 266 267 /** The time the last warning log was written. */ 268 private long m_lastLogWarning; 269 270 /** The number of times the log entry was written. */ 271 private int m_logCount; 272 273 /** Memory percentage to reach to go to warning level. */ 274 private int m_maxUsagePercent; 275 276 /** The average memory status. */ 277 private CmsMemoryStatus m_memoryAverage; 278 279 /** The current memory status. */ 280 private CmsMemoryStatus m_memoryCurrent; 281 282 /** Contains the object to be monitored. */ 283 private Map<String, Object> m_monitoredObjects; 284 285 /** Buffer for publish history. */ 286 private Buffer m_publishHistory; 287 288 /** Buffer for publish jobs. */ 289 private Buffer m_publishQueue; 290 291 /** Flag for memory warning mail send. */ 292 private boolean m_warningLoggedSinceLastStatus; 293 294 /** Flag for memory warning mail send. */ 295 private boolean m_warningSendSinceLastStatus; 296 297 /** 298 * Empty constructor, required by OpenCms scheduler.<p> 299 */ 300 public CmsMemoryMonitor() { 301 302 m_monitoredObjects = new HashMap<String, Object>(); 303 } 304 305 /** 306 * Creates a thread safe LRU cache map based on the guava cache builder.<p> 307 * Use this instead of synchronized maps for better performance.<p> 308 * 309 * @param capacity the cache capacity 310 * 311 * @return the cache map 312 */ 313 @SuppressWarnings("unchecked") 314 public static <T, V> Map<T, V> createLRUCacheMap(int capacity) { 315 316 CacheBuilder<?, ?> builder = CacheBuilder.newBuilder().concurrencyLevel(CONCURRENCY_LEVEL).maximumSize( 317 capacity); 318 builder.build(); 319 return (Map<T, V>)(builder.build().asMap()); 320 } 321 322 /** 323 * Returns the size of objects that are instances of 324 * <code>byte[]</code>, <code>String</code>, <code>CmsFile</code>,<code>I_CmsLruCacheObject</code>.<p> 325 * For other objects, a size of 0 is returned. 326 * 327 * @param obj the object 328 * @return the size of the object 329 */ 330 public static int getMemorySize(Object obj) { 331 332 if (obj instanceof I_CmsMemoryMonitorable) { 333 return ((I_CmsMemoryMonitorable)obj).getMemorySize(); 334 } 335 336 if (obj instanceof byte[]) { 337 // will always be a total of 16 + 8 338 return 8 + (int)(Math.ceil(((byte[])obj).length / 16.0) * 16.0); 339 } 340 341 if (obj instanceof String) { 342 // will always be a total of 16 + 24 343 return 24 + (int)(Math.ceil(((String)obj).length() / 8.0) * 16.0); 344 } 345 346 if (obj instanceof CmsFile) { 347 CmsFile f = (CmsFile)obj; 348 if (f.getContents() != null) { 349 return f.getContents().length + 1024; 350 } else { 351 return 1024; 352 } 353 } 354 355 if (obj instanceof CmsUUID) { 356 return 184; // worst case if UUID String has been generated 357 } 358 359 if (obj instanceof CmsPermissionSet) { 360 return 16; // two ints 361 } 362 363 if (obj instanceof CmsResource) { 364 return 1024; // estimated size 365 } 366 367 if (obj instanceof CmsPublishedResource) { 368 return 512; // estimated size 369 } 370 371 if (obj instanceof CmsUser) { 372 return 2048; // estimated size 373 } 374 375 if (obj instanceof CmsGroup) { 376 return 512; // estimated size 377 } 378 379 if (obj instanceof CmsProject) { 380 return 512; // estimated size 381 } 382 383 if (obj instanceof Boolean) { 384 return 8; // one boolean 385 } 386 387 if (obj instanceof CmsProperty) { 388 int size = 8; 389 390 CmsProperty property = (CmsProperty)obj; 391 size += getMemorySize(property.getName()); 392 393 if (property.getResourceValue() != null) { 394 size += getMemorySize(property.getResourceValue()); 395 } 396 397 if (property.getStructureValue() != null) { 398 size += getMemorySize(property.getStructureValue()); 399 } 400 401 if (property.getOrigin() != null) { 402 size += getMemorySize(property.getOrigin()); 403 } 404 405 return size; 406 } 407 408 if (obj instanceof CmsPropertyDefinition) { 409 int size = 8; 410 411 CmsPropertyDefinition propDef = (CmsPropertyDefinition)obj; 412 size += getMemorySize(propDef.getName()); 413 size += getMemorySize(propDef.getId()); 414 415 return size; 416 } 417 418 return 8; 419 } 420 421 /** 422 * Returns the total value size of a list object.<p> 423 * 424 * @param listValue the list object 425 * @param depth the max recursion depth for calculation the size 426 * 427 * @return the size of the list object 428 */ 429 public static long getValueSize(List<?> listValue, int depth) { 430 431 long totalSize = 0; 432 try { 433 Object[] values = listValue.toArray(); 434 for (int i = 0, s = values.length; i < s; i++) { 435 436 Object obj = values[i]; 437 438 if (obj instanceof CmsAccessControlList) { 439 obj = ((CmsAccessControlList)obj).getPermissionMap(); 440 } 441 442 if (obj instanceof CmsFlexCacheVariation) { 443 obj = ((CmsFlexCacheVariation)obj).m_map; 444 } 445 446 if ((obj instanceof Map) && (depth < MAX_DEPTH)) { 447 totalSize += getValueSize((Map<?, ?>)obj, depth + 1); 448 continue; 449 } 450 451 if ((obj instanceof List) && (depth < MAX_DEPTH)) { 452 totalSize += getValueSize((List<?>)obj, depth + 1); 453 continue; 454 } 455 456 totalSize += getMemorySize(obj); 457 } 458 } catch (ConcurrentModificationException e) { 459 // this might happen since even the .toArray() method internally creates an iterator 460 } catch (Throwable t) { 461 // catch all other exceptions otherwise the whole monitor will stop working 462 if (LOG.isDebugEnabled()) { 463 LOG.debug(Messages.get().getBundle().key(Messages.LOG_CAUGHT_THROWABLE_1, t.getMessage())); 464 } 465 } 466 467 return totalSize; 468 } 469 470 /** 471 * Returns the total value size of a map object.<p> 472 * 473 * @param mapValue the map object 474 * @param depth the max recursion depth for calculation the size 475 * 476 * @return the size of the map object 477 */ 478 public static long getValueSize(Map<?, ?> mapValue, int depth) { 479 480 long totalSize = 0; 481 try { 482 Object[] values = mapValue.values().toArray(); 483 for (int i = 0, s = values.length; i < s; i++) { 484 485 Object obj = values[i]; 486 487 if (obj instanceof CmsAccessControlList) { 488 obj = ((CmsAccessControlList)obj).getPermissionMap(); 489 } 490 491 if (obj instanceof CmsFlexCacheVariation) { 492 obj = ((CmsFlexCacheVariation)obj).m_map; 493 } 494 495 if ((obj instanceof Map) && (depth < MAX_DEPTH)) { 496 totalSize += getValueSize((Map<?, ?>)obj, depth + 1); 497 continue; 498 } 499 500 if ((obj instanceof List) && (depth < MAX_DEPTH)) { 501 totalSize += getValueSize((List<?>)obj, depth + 1); 502 continue; 503 } 504 505 totalSize += getMemorySize(obj); 506 } 507 } catch (ConcurrentModificationException e) { 508 // this might happen since even the .toArray() method internally creates an iterator 509 } catch (Throwable t) { 510 // catch all other exceptions otherwise the whole monitor will stop working 511 if (LOG.isDebugEnabled()) { 512 LOG.debug(Messages.get().getBundle().key(Messages.LOG_CAUGHT_THROWABLE_1, t.getMessage())); 513 } 514 } 515 516 return totalSize; 517 } 518 519 /** 520 * Returns the value sizes of value objects within the monitored object.<p> 521 * 522 * @param obj the object 523 * 524 * @return the value sizes of value objects or "-"-fields 525 */ 526 public static long getValueSize(Object obj) { 527 528 if (obj instanceof CmsLruCache) { 529 return ((CmsLruCache)obj).size(); 530 } 531 532 if (obj instanceof Map) { 533 return getValueSize((Map<?, ?>)obj, 1); 534 } 535 536 if (obj instanceof List) { 537 return getValueSize((List<?>)obj, 1); 538 } 539 540 try { 541 return getMemorySize(obj); 542 } catch (Exception exc) { 543 return 0; 544 } 545 } 546 547 /** 548 * Caches the given acl under the given cache key.<p> 549 * 550 * @param key the cache key 551 * @param acl the acl to cache 552 */ 553 public void cacheACL(String key, CmsAccessControlList acl) { 554 555 if (m_disabled.get(CacheType.ACL) != null) { 556 return; 557 } 558 m_cacheAccessControlList.put(key, acl); 559 } 560 561 /** 562 * Caches the given content definition under the given cache key.<p> 563 * 564 * @param key the cache key 565 * @param contentDefinition the content definition to cache 566 */ 567 public void cacheContentDefinition(String key, CmsXmlContentDefinition contentDefinition) { 568 569 if (m_disabled.get(CacheType.CONTENT_DEFINITION) != null) { 570 return; 571 } 572 m_cacheContentDefinitions.put(key, contentDefinition); 573 } 574 575 /** 576 * Caches the given group under its id AND fully qualified name.<p> 577 * 578 * @param group the group to cache 579 */ 580 public void cacheGroup(CmsGroup group) { 581 582 if (m_disabled.get(CacheType.GROUP) != null) { 583 return; 584 } 585 m_cacheGroup.put(group.getId().toString(), group); 586 m_cacheGroup.put(group.getName(), group); 587 } 588 589 /** 590 * Caches the given locale under the given cache key.<p> 591 * 592 * @param key the cache key 593 * @param locale the locale to cache 594 */ 595 public void cacheLocale(String key, Locale locale) { 596 597 if (m_cacheLocale != null) { 598 if (m_disabled.get(CacheType.LOCALE) != null) { 599 return; 600 } 601 // this may be accessed before initialization 602 m_cacheLocale.put(key, locale); 603 } 604 } 605 606 /** 607 * Caches the given lock.<p> 608 * 609 * The lock is cached by it resource's root path.<p> 610 * 611 * @param lock the lock to cache 612 */ 613 public void cacheLock(CmsLock lock) { 614 615 if (m_disabled.get(CacheType.LOCK) != null) { 616 return; 617 } 618 m_cacheLock.put(lock.getResourceName(), lock); 619 } 620 621 /** 622 * Caches the given object under the given cache key.<p> 623 * 624 * @param key the cache key 625 * @param obj the object to cache 626 */ 627 public void cacheMemObject(String key, Object obj) { 628 629 if (m_disabled.get(CacheType.MEMORY_OBJECT) != null) { 630 return; 631 } 632 m_cacheMemObject.put(key, obj); 633 } 634 635 /** 636 * Caches the given organizational under its id AND the fully qualified name.<p> 637 * 638 * @param orgUnit the organizational unit to cache 639 */ 640 public void cacheOrgUnit(CmsOrganizationalUnit orgUnit) { 641 642 if (m_disabled.get(CacheType.ORG_UNIT) != null) { 643 return; 644 } 645 m_cacheOrgUnit.put(orgUnit.getId().toString(), orgUnit); 646 m_cacheOrgUnit.put(orgUnit.getName(), orgUnit); 647 } 648 649 /** 650 * Caches the given permission check result under the given cache key.<p> 651 * 652 * @param key the cache key 653 * @param permission the permission check result to cache 654 */ 655 public void cachePermission(String key, I_CmsPermissionHandler.CmsPermissionCheckResult permission) { 656 657 if (m_disabled.get(CacheType.PERMISSION) != null) { 658 return; 659 } 660 m_cachePermission.put(key, permission); 661 } 662 663 /** 664 * Caches the given project under its id AND the fully qualified name.<p> 665 * 666 * @param project the project to cache 667 */ 668 public void cacheProject(CmsProject project) { 669 670 if (m_disabled.get(CacheType.PROJECT) != null) { 671 return; 672 } 673 m_cacheProject.put(project.getUuid().toString(), project); 674 m_cacheProject.put(project.getName(), project); 675 } 676 677 /** 678 * Caches the given project resource list under the given cache key.<p> 679 * 680 * @param key the cache key 681 * @param projectResources the project resources to cache 682 */ 683 public void cacheProjectResources(String key, List<CmsResource> projectResources) { 684 685 if (m_disabled.get(CacheType.PROJECT_RESOURCES) != null) { 686 return; 687 } 688 m_cacheProjectResources.put(key, projectResources); 689 } 690 691 /** 692 * Caches the given property under the given cache key.<p> 693 * 694 * @param key the cache key 695 * @param property the property to cache 696 */ 697 public void cacheProperty(String key, CmsProperty property) { 698 699 if (m_disabled.get(CacheType.PROPERTY) != null) { 700 return; 701 } 702 m_cacheProperty.put(key, property); 703 } 704 705 /** 706 * Caches the given property list under the given cache key.<p> 707 * 708 * @param key the cache key 709 * @param propertyList the property list to cache 710 */ 711 public void cachePropertyList(String key, List<CmsProperty> propertyList) { 712 713 if (m_disabled.get(CacheType.PROPERTY_LIST) != null) { 714 return; 715 } 716 m_cachePropertyList.put(key, propertyList); 717 } 718 719 /** 720 * Caches the given published resources list under the given cache key.<p> 721 * 722 * @param cacheKey the cache key 723 * @param publishedResources the published resources list to cache 724 */ 725 public void cachePublishedResources(String cacheKey, List<CmsPublishedResource> publishedResources) { 726 727 if (m_disabled.get(CacheType.PUBLISHED_RESOURCES) != null) { 728 return; 729 } 730 m_cachePublishedResources.put(cacheKey, publishedResources); 731 } 732 733 /** 734 * Caches the given publish job.<p> 735 * 736 * @param publishJob the publish job 737 */ 738 @SuppressWarnings("unchecked") 739 public void cachePublishJob(CmsPublishJobInfoBean publishJob) { 740 741 if (m_disabled.get(CacheType.PUBLISH_QUEUE) != null) { 742 return; 743 } 744 m_publishQueue.add(publishJob); 745 } 746 747 /** 748 * Caches the given publish job in the publish job history.<p> 749 * 750 * @param publishJob the publish job 751 */ 752 @SuppressWarnings("unchecked") 753 public void cachePublishJobInHistory(CmsPublishJobInfoBean publishJob) { 754 755 if (m_disabled.get(CacheType.PUBLISH_HISTORY) != null) { 756 return; 757 } 758 m_publishHistory.add(publishJob); 759 } 760 761 /** 762 * Caches the given resource under the given cache key.<p> 763 * 764 * @param key the cache key 765 * @param resource the resource to cache 766 */ 767 public void cacheResource(String key, CmsResource resource) { 768 769 if (m_disabled.get(CacheType.RESOURCE) != null) { 770 return; 771 } 772 m_cacheResource.put(key, resource); 773 } 774 775 /** 776 * Caches the given resource list under the given cache key.<p> 777 * 778 * @param key the cache key 779 * @param resourceList the resource list to cache 780 */ 781 public void cacheResourceList(String key, List<CmsResource> resourceList) { 782 783 if (m_disabled.get(CacheType.RESOURCE_LIST) != null) { 784 return; 785 } 786 m_cacheResourceList.put(key, resourceList); 787 } 788 789 /** 790 * Caches the given value under the given cache key.<p> 791 * 792 * @param key the cache key 793 * @param hasRole if the user has the given role 794 */ 795 public void cacheRole(String key, boolean hasRole) { 796 797 if (m_disabled.get(CacheType.HAS_ROLE) != null) { 798 return; 799 } 800 m_cacheHasRoles.put(key, Boolean.valueOf(hasRole)); 801 } 802 803 /** 804 * Caches the given value under the given cache key.<p> 805 * 806 * @param key the cache key 807 * @param roles the roles of the user 808 */ 809 public void cacheRoleList(String key, List<CmsRole> roles) { 810 811 if (m_disabled.get(CacheType.ROLE_LIST) != null) { 812 return; 813 } 814 m_cacheRoleLists.put(key, roles); 815 } 816 817 /** 818 * Caches the given user under its id AND the fully qualified name.<p> 819 * 820 * @param user the user to cache 821 */ 822 public void cacheUser(CmsUser user) { 823 824 if (m_disabled.get(CacheType.USER) != null) { 825 return; 826 } 827 m_cacheUser.put(user.getId().toString(), user); 828 m_cacheUser.put(user.getName(), user); 829 } 830 831 /** 832 * Caches the given list of user groups under the given cache key.<p> 833 * 834 * @param key the cache key 835 * @param userGroups the list of user groups to cache 836 */ 837 public void cacheUserGroups(String key, List<CmsGroup> userGroups) { 838 839 if (m_disabled.get(CacheType.USERGROUPS) != null) { 840 return; 841 } 842 m_cacheUserGroups.put(key, userGroups); 843 } 844 845 /** 846 * Caches the given list of users under the given cache key.<p> 847 * 848 * @param key the cache key 849 * @param userList the list of users to cache 850 */ 851 public void cacheUserList(String key, List<CmsUser> userList) { 852 853 if (m_disabled.get(CacheType.USER_LIST) != null) { 854 return; 855 } 856 m_cacheUserList.put(key, userList); 857 } 858 859 /** 860 * Caches the given vfs object under the given cache key.<p> 861 * 862 * @param key the cache key 863 * @param obj the vfs object to cache 864 */ 865 public void cacheVfsObject(String key, Object obj) { 866 867 if (m_disabled.get(CacheType.VFS_OBJECT) != null) { 868 return; 869 } 870 m_cacheVfsObject.put(key, obj); 871 } 872 873 /** 874 * Caches the given xml entity under the given system id.<p> 875 * 876 * @param systemId the cache key 877 * @param content the content to cache 878 */ 879 public void cacheXmlPermanentEntity(String systemId, byte[] content) { 880 881 if (m_disabled.get(CacheType.XML_ENTITY_PERM) != null) { 882 return; 883 } 884 m_cacheXmlPermanentEntity.put(systemId, content); 885 } 886 887 /** 888 * Caches the given xml entity under the given cache key.<p> 889 * 890 * @param key the cache key 891 * @param content the content to cache 892 */ 893 public void cacheXmlTemporaryEntity(String key, byte[] content) { 894 895 if (m_disabled.get(CacheType.XML_ENTITY_TEMP) != null) { 896 return; 897 } 898 m_cacheXmlTemporaryEntity.put(key, content); 899 } 900 901 /** 902 * Clears the access control list cache when access control entries are changed.<p> 903 */ 904 public void clearAccessControlListCache() { 905 906 flushCache(CacheType.ACL); 907 flushCache(CacheType.PERMISSION); 908 clearResourceCache(); 909 } 910 911 /** 912 * Clears almost all internal caches.<p> 913 */ 914 public void clearCache() { 915 916 clearPrincipalsCache(); 917 918 flushCache(CacheType.PROJECT); 919 flushCache(CacheType.RESOURCE); 920 flushCache(CacheType.RESOURCE_LIST); 921 flushCache(CacheType.PROPERTY); 922 flushCache(CacheType.PROPERTY_LIST); 923 flushCache(CacheType.PROJECT_RESOURCES); 924 flushCache(CacheType.PUBLISHED_RESOURCES); 925 } 926 927 /** 928 * Clears all internal principal-related caches.<p> 929 */ 930 public void clearPrincipalsCache() { 931 932 flushCache(CacheType.USER); 933 flushCache(CacheType.GROUP); 934 flushCache(CacheType.ORG_UNIT); 935 flushCache(CacheType.ACL); 936 flushCache(CacheType.PERMISSION); 937 flushCache(CacheType.HAS_ROLE); 938 flushCache(CacheType.ROLE_LIST); 939 flushCache(CacheType.USERGROUPS); 940 flushCache(CacheType.USER_LIST); 941 } 942 943 /** 944 * Clears all the depending caches when a resource was changed.<p> 945 */ 946 public void clearResourceCache() { 947 948 flushCache(CacheType.RESOURCE); 949 flushCache(CacheType.RESOURCE_LIST); 950 flushCache(CacheType.HAS_ROLE); 951 flushCache(CacheType.ROLE_LIST); 952 } 953 954 /** 955 * Clears the user cache for the given user.<p> 956 * 957 * @param user the user 958 */ 959 public void clearUserCache(CmsUser user) { 960 961 uncacheUser(user); 962 flushCache(CacheType.RESOURCE_LIST); 963 } 964 965 /** 966 * Disables the given cache.<p> 967 * 968 * @param types the cache type to disable 969 */ 970 public void disableCache(CacheType... types) { 971 972 for (CacheType type : types) { 973 m_disabled.put(type, Boolean.TRUE); 974 } 975 flushCache(types); 976 } 977 978 /** 979 * Enables the given cache.<p> 980 * 981 * @param types the cache type to disable 982 */ 983 public void enableCache(CacheType... types) { 984 985 for (CacheType type : types) { 986 m_disabled.remove(type); 987 } 988 } 989 990 /** 991 * Returns if monitoring is enabled.<p> 992 * 993 * @return true if monitoring is enabled 994 */ 995 public boolean enabled() { 996 997 return true; 998 } 999 1000 /** 1001 * Flushes the ACL cache.<p> 1002 * 1003 * @deprecated use {@link #flushCache(CacheType[])} instead 1004 */ 1005 @Deprecated 1006 public void flushACLs() { 1007 1008 flushCache(CacheType.ACL); 1009 } 1010 1011 /** 1012 * Flushes the given cache.<p> 1013 * 1014 * @param types the cache types to flush 1015 */ 1016 public void flushCache(CacheType... types) { 1017 1018 for (CacheType type : types) { 1019 switch (type) { 1020 case ACL: 1021 m_cacheAccessControlList.clear(); 1022 break; 1023 case CONTENT_DEFINITION: 1024 m_cacheContentDefinitions.clear(); 1025 break; 1026 case GROUP: 1027 m_cacheGroup.clear(); 1028 break; 1029 case HAS_ROLE: 1030 m_cacheHasRoles.clear(); 1031 break; 1032 case LOCALE: 1033 m_cacheLocale.clear(); 1034 break; 1035 case LOCK: 1036 m_cacheLock.clear(); 1037 break; 1038 case MEMORY_OBJECT: 1039 m_cacheMemObject.clear(); 1040 break; 1041 case ORG_UNIT: 1042 m_cacheOrgUnit.clear(); 1043 break; 1044 case PERMISSION: 1045 m_cachePermission.clear(); 1046 break; 1047 case PROJECT: 1048 m_cacheProject.clear(); 1049 break; 1050 case PROJECT_RESOURCES: 1051 m_cacheProjectResources.clear(); 1052 break; 1053 case PROPERTY: 1054 m_cacheProperty.clear(); 1055 break; 1056 case PROPERTY_LIST: 1057 m_cachePropertyList.clear(); 1058 break; 1059 case PUBLISHED_RESOURCES: 1060 m_cachePublishedResources.clear(); 1061 break; 1062 case PUBLISH_HISTORY: 1063 m_publishHistory.clear(); 1064 break; 1065 case PUBLISH_QUEUE: 1066 m_publishQueue.clear(); 1067 break; 1068 case RESOURCE: 1069 m_cacheResource.clear(); 1070 break; 1071 case RESOURCE_LIST: 1072 m_cacheResourceList.clear(); 1073 break; 1074 case ROLE_LIST: 1075 m_cacheRoleLists.clear(); 1076 break; 1077 case USER: 1078 m_cacheUser.clear(); 1079 break; 1080 case USERGROUPS: 1081 m_cacheUserGroups.clear(); 1082 break; 1083 case USER_LIST: 1084 m_cacheUserList.clear(); 1085 break; 1086 case VFS_OBJECT: 1087 m_cacheVfsObject.clear(); 1088 break; 1089 case XML_ENTITY_PERM: 1090 m_cacheXmlPermanentEntity.clear(); 1091 break; 1092 case XML_ENTITY_TEMP: 1093 m_cacheXmlTemporaryEntity.clear(); 1094 break; 1095 default: 1096 // can't happen 1097 } 1098 } 1099 } 1100 1101 /** 1102 * Flushes the xml content definitions cache.<p> 1103 * 1104 * @deprecated use {@link #flushCache(CacheType[])} instead 1105 */ 1106 @Deprecated 1107 public void flushContentDefinitions() { 1108 1109 flushCache(CacheType.CONTENT_DEFINITION); 1110 } 1111 1112 /** 1113 * Flushes the group cache.<p> 1114 * 1115 * @deprecated use {@link #flushCache(CacheType[])} instead 1116 */ 1117 @Deprecated 1118 public void flushGroups() { 1119 1120 flushCache(CacheType.GROUP); 1121 } 1122 1123 /** 1124 * Flushes the locale cache.<p> 1125 * 1126 * @deprecated use {@link #flushCache(CacheType[])} instead 1127 */ 1128 @Deprecated 1129 public void flushLocales() { 1130 1131 flushCache(CacheType.LOCALE); 1132 } 1133 1134 /** 1135 * Flushes the locks cache.<p> 1136 * 1137 * @param newLocks if not <code>null</code> the lock cache is replaced by the given map 1138 */ 1139 public void flushLocks(Map<String, CmsLock> newLocks) { 1140 1141 if ((newLocks == null) || newLocks.isEmpty()) { 1142 flushCache(CacheType.LOCK); 1143 return; 1144 } 1145 // initialize new lock cache 1146 Map<String, CmsLock> newLockCache = new ConcurrentHashMap<String, CmsLock>(newLocks); 1147 // register it 1148 register(CmsLockManager.class.getName(), newLockCache); 1149 // save the old cache 1150 Map<String, CmsLock> oldCache = m_cacheLock; 1151 // replace the old by the new cache 1152 m_cacheLock = newLockCache; 1153 // clean up the old cache 1154 oldCache.clear(); 1155 } 1156 1157 /** 1158 * Flushes the memory object cache.<p> 1159 * 1160 * @deprecated use {@link #flushCache(CacheType[])} instead 1161 */ 1162 @Deprecated 1163 public void flushMemObjects() { 1164 1165 flushCache(CacheType.MEMORY_OBJECT); 1166 } 1167 1168 /** 1169 * Flushes the organizational unit cache.<p> 1170 * 1171 * @deprecated use {@link #flushCache(CacheType[])} instead 1172 */ 1173 @Deprecated 1174 public void flushOrgUnits() { 1175 1176 flushCache(CacheType.ORG_UNIT); 1177 } 1178 1179 /** 1180 * Flushes the permission check result cache.<p> 1181 * 1182 * @deprecated use {@link #flushCache(CacheType[])} instead 1183 */ 1184 @Deprecated 1185 public void flushPermissions() { 1186 1187 flushCache(CacheType.PERMISSION); 1188 } 1189 1190 /** 1191 * Flushes the project resources cache.<p> 1192 * 1193 * @deprecated use {@link #flushCache(CacheType[])} instead 1194 */ 1195 @Deprecated 1196 public void flushProjectResources() { 1197 1198 flushCache(CacheType.PROJECT_RESOURCES); 1199 } 1200 1201 /** 1202 * Flushes the project cache.<p> 1203 * 1204 * @deprecated use {@link #flushCache(CacheType[])} instead 1205 */ 1206 @Deprecated 1207 public void flushProjects() { 1208 1209 flushCache(CacheType.PROJECT); 1210 } 1211 1212 /** 1213 * Flushes the property cache.<p> 1214 * 1215 * @deprecated use {@link #flushCache(CacheType[])} instead 1216 */ 1217 @Deprecated 1218 public void flushProperties() { 1219 1220 flushCache(CacheType.PROPERTY); 1221 } 1222 1223 /** 1224 * Flushes the property list cache.<p> 1225 * 1226 * @deprecated use {@link #flushCache(CacheType[])} instead 1227 */ 1228 @Deprecated 1229 public void flushPropertyLists() { 1230 1231 flushCache(CacheType.PROPERTY_LIST); 1232 } 1233 1234 /** 1235 * Flushes the published resources cache.<p> 1236 * 1237 * @deprecated use {@link #flushCache(CacheType[])} instead 1238 */ 1239 @Deprecated 1240 public void flushPublishedResources() { 1241 1242 flushCache(CacheType.PUBLISHED_RESOURCES); 1243 } 1244 1245 /** 1246 * Flushes the publish history.<p> 1247 * 1248 * @deprecated use {@link #flushCache(CacheType[])} instead 1249 */ 1250 @Deprecated 1251 public void flushPublishJobHistory() { 1252 1253 flushCache(CacheType.PUBLISH_HISTORY); 1254 } 1255 1256 /** 1257 * Flushes the publish queue.<p> 1258 * 1259 * @deprecated use {@link #flushCache(CacheType[])} instead 1260 */ 1261 @Deprecated 1262 public void flushPublishJobs() { 1263 1264 flushCache(CacheType.PUBLISH_QUEUE); 1265 } 1266 1267 /** 1268 * Flushes the resource list cache.<p> 1269 * 1270 * @deprecated use {@link #flushCache(CacheType[])} instead 1271 */ 1272 @Deprecated 1273 public void flushResourceLists() { 1274 1275 flushCache(CacheType.RESOURCE_LIST); 1276 } 1277 1278 /** 1279 * Flushes the resource cache.<p> 1280 * 1281 * @deprecated use {@link #flushCache(CacheType[])} instead 1282 */ 1283 @Deprecated 1284 public void flushResources() { 1285 1286 flushCache(CacheType.RESOURCE); 1287 } 1288 1289 /** 1290 * Flushes the role lists cache.<p> 1291 * 1292 * @deprecated use {@link #flushCache(CacheType[])} instead 1293 */ 1294 @Deprecated 1295 public void flushRoleLists() { 1296 1297 flushCache(CacheType.ROLE_LIST); 1298 } 1299 1300 /** 1301 * Flushes the roles cache.<p> 1302 * 1303 * @deprecated use {@link #flushCache(CacheType[])} instead 1304 */ 1305 @Deprecated 1306 public void flushRoles() { 1307 1308 flushCache(CacheType.HAS_ROLE); 1309 } 1310 1311 /** 1312 * Flushes the user groups cache.<p> 1313 * 1314 * @deprecated use {@link #flushCache(CacheType[])} instead 1315 */ 1316 @Deprecated 1317 public void flushUserGroups() { 1318 1319 flushCache(CacheType.USERGROUPS); 1320 flushCache(CacheType.USER_LIST); 1321 } 1322 1323 /** 1324 * Flushes the users cache.<p> 1325 * 1326 * @deprecated use {@link #flushCache(CacheType[])} instead 1327 */ 1328 @Deprecated 1329 public void flushUsers() { 1330 1331 flushCache(CacheType.USER); 1332 } 1333 1334 /** 1335 * Flushes the vfs object cache.<p> 1336 * 1337 * @deprecated use {@link #flushCache(CacheType[])} instead 1338 */ 1339 @Deprecated 1340 public void flushVfsObjects() { 1341 1342 flushCache(CacheType.VFS_OBJECT); 1343 } 1344 1345 /** 1346 * Flushes the xml permanent entities cache.<p> 1347 * 1348 * @deprecated use {@link #flushCache(CacheType[])} instead 1349 */ 1350 @Deprecated 1351 public void flushXmlPermanentEntities() { 1352 1353 flushCache(CacheType.XML_ENTITY_PERM); 1354 } 1355 1356 /** 1357 * Flushes the xml temporary entities cache.<p> 1358 * 1359 * @deprecated use {@link #flushCache(CacheType[])} instead 1360 */ 1361 @Deprecated 1362 public void flushXmlTemporaryEntities() { 1363 1364 flushCache(CacheType.XML_ENTITY_TEMP); 1365 } 1366 1367 /** 1368 * Returns all cached lock root paths.<p> 1369 * 1370 * @return a list of {@link String} objects 1371 */ 1372 public List<String> getAllCachedLockPaths() { 1373 1374 return new ArrayList<String>(m_cacheLock.keySet()); 1375 } 1376 1377 /** 1378 * Returns all cached locks.<p> 1379 * 1380 * @return a list of {@link CmsLock} objects 1381 */ 1382 public List<CmsLock> getAllCachedLocks() { 1383 1384 return new ArrayList<CmsLock>(m_cacheLock.values()); 1385 } 1386 1387 /** 1388 * Returns all cached publish jobs in the queue as ordered list.<p> 1389 * 1390 * @return all cached publish jobs 1391 */ 1392 @SuppressWarnings("unchecked") 1393 public List<CmsPublishJobInfoBean> getAllCachedPublishJobs() { 1394 1395 return new ArrayList<CmsPublishJobInfoBean>(m_publishQueue); 1396 } 1397 1398 /** 1399 * Returns all cached publish jobs in the history as ordered list.<p> 1400 * 1401 * @return all cached publish jobs 1402 */ 1403 @SuppressWarnings("unchecked") 1404 public List<CmsPublishJobInfoBean> getAllCachedPublishJobsInHistory() { 1405 1406 return new ArrayList<CmsPublishJobInfoBean>(m_publishHistory); 1407 } 1408 1409 /** 1410 * Returns the ACL cached with the given cache key or <code>null</code> if not found.<p> 1411 * 1412 * @param key the cache key to look for 1413 * 1414 * @return the ACL cached with the given cache key 1415 */ 1416 public CmsAccessControlList getCachedACL(String key) { 1417 1418 return m_cacheAccessControlList.get(key); 1419 } 1420 1421 /** 1422 * Returns the xml content definition cached with the given cache key or <code>null</code> if not found.<p> 1423 * 1424 * @param key the cache key to look for 1425 * 1426 * @return the xml content definition cached with the given cache key 1427 */ 1428 public CmsXmlContentDefinition getCachedContentDefinition(String key) { 1429 1430 return m_cacheContentDefinitions.get(key); 1431 } 1432 1433 /** 1434 * Returns the group cached with the given cache key or <code>null</code> if not found.<p> 1435 * 1436 * @param key the cache key to look for, this may be the group's uuid or the fqn 1437 * 1438 * @return the group cached with the given cache key 1439 */ 1440 public CmsGroup getCachedGroup(String key) { 1441 1442 return m_cacheGroup.get(key); 1443 } 1444 1445 /** 1446 * Returns the locale cached with the given cache key or <code>null</code> if not found.<p> 1447 * 1448 * @param key the cache key to look for 1449 * 1450 * @return the locale cached with the given cache key 1451 */ 1452 public Locale getCachedLocale(String key) { 1453 1454 if (m_cacheLocale == null) { 1455 // this may be accessed before initialization 1456 return null; 1457 } 1458 return m_cacheLocale.get(key); 1459 } 1460 1461 /** 1462 * Returns the lock cached with the given root path or <code>null</code> if not found.<p> 1463 * 1464 * @param rootPath the root path to look for 1465 * 1466 * @return the lock cached with the given root path 1467 */ 1468 public CmsLock getCachedLock(String rootPath) { 1469 1470 return m_cacheLock.get(rootPath); 1471 } 1472 1473 /** 1474 * Returns the memory object cached with the given cache key or <code>null</code> if not found.<p> 1475 * 1476 * @param key the cache key to look for 1477 * 1478 * @return the memory object cached with the given cache key 1479 */ 1480 public Object getCachedMemObject(String key) { 1481 1482 return m_cacheMemObject.get(key); 1483 } 1484 1485 /** 1486 * Returns the organizational unit cached with the given cache key or <code>null</code> if not found.<p> 1487 * 1488 * @param key the cache key to look for, this may be the organizational unit's uuid or the fqn 1489 * 1490 * @return the organizational unit cached with the given cache key 1491 */ 1492 public CmsOrganizationalUnit getCachedOrgUnit(String key) { 1493 1494 return m_cacheOrgUnit.get(key); 1495 } 1496 1497 /** 1498 * Returns the permission check result cached with the given cache key or <code>null</code> if not found.<p> 1499 * 1500 * @param key the cache key to look for 1501 * 1502 * @return the permission check result cached with the given cache key 1503 */ 1504 public I_CmsPermissionHandler.CmsPermissionCheckResult getCachedPermission(String key) { 1505 1506 return m_cachePermission.get(key); 1507 } 1508 1509 /** 1510 * Returns the project cached with the given cache key or <code>null</code> if not found.<p> 1511 * 1512 * @param key the cache key to look for, this may be the project's uuid or the fqn 1513 * 1514 * @return the project cached with the given cache key 1515 */ 1516 public CmsProject getCachedProject(String key) { 1517 1518 return m_cacheProject.get(key); 1519 } 1520 1521 /** 1522 * Returns the project resources list cached with the given cache key or <code>null</code> if not found.<p> 1523 * 1524 * @param key the cache key to look for 1525 * 1526 * @return the project resources list cached with the given cache key 1527 */ 1528 public List<CmsResource> getCachedProjectResources(String key) { 1529 1530 return m_cacheProjectResources.get(key); 1531 } 1532 1533 /** 1534 * Returns the property cached with the given cache key or <code>null</code> if not found.<p> 1535 * 1536 * @param key the cache key to look for 1537 * 1538 * @return the property cached with the given cache key 1539 */ 1540 public CmsProperty getCachedProperty(String key) { 1541 1542 return m_cacheProperty.get(key); 1543 } 1544 1545 /** 1546 * Returns the property list cached with the given cache key or <code>null</code> if not found.<p> 1547 * 1548 * @param key the cache key to look for 1549 * 1550 * @return the property list cached with the given cache key 1551 */ 1552 public List<CmsProperty> getCachedPropertyList(String key) { 1553 1554 return m_cachePropertyList.get(key); 1555 } 1556 1557 /** 1558 * Returns the published resources list cached with the given cache key or <code>null</code> if not found.<p> 1559 * 1560 * @param cacheKey the cache key to look for 1561 * 1562 * @return the published resources list cached with the given cache key 1563 */ 1564 public List<CmsPublishedResource> getCachedPublishedResources(String cacheKey) { 1565 1566 return m_cachePublishedResources.get(cacheKey); 1567 } 1568 1569 /** 1570 * Returns the publish job with the given cache key or <code>null</code> if not found.<p> 1571 * 1572 * @param key the cache key to look for 1573 * 1574 * @return the publish job with the given cache key 1575 */ 1576 public CmsPublishJobInfoBean getCachedPublishJob(String key) { 1577 1578 synchronized (m_publishQueue) { 1579 for (Object obj : m_publishQueue) { 1580 CmsPublishJobInfoBean publishJob = (CmsPublishJobInfoBean)obj; 1581 if (publishJob.getPublishHistoryId().toString().equals(key)) { 1582 return publishJob; 1583 } 1584 } 1585 } 1586 return null; 1587 } 1588 1589 /** 1590 * Returns the publish job from the history with the given cache key or <code>null</code> if not found.<p> 1591 * 1592 * @param key the cache key to look for 1593 * 1594 * @return the publish job with the given cache key 1595 */ 1596 public CmsPublishJobInfoBean getCachedPublishJobInHistory(String key) { 1597 1598 for (Object obj : m_publishHistory) { 1599 CmsPublishJobInfoBean publishJob = (CmsPublishJobInfoBean)obj; 1600 if (publishJob.getPublishHistoryId().toString().equals(key)) { 1601 return publishJob; 1602 } 1603 } 1604 1605 return null; 1606 } 1607 1608 /** 1609 * Returns the resource cached with the given cache key or <code>null</code> if not found.<p> 1610 * 1611 * @param key the cache key to look for 1612 * 1613 * @return the resource cached with the given cache key 1614 */ 1615 public CmsResource getCachedResource(String key) { 1616 1617 return m_cacheResource.get(key); 1618 } 1619 1620 /** 1621 * Returns the resource list cached with the given cache key or <code>null</code> if not found.<p> 1622 * 1623 * @param key the cache key to look for 1624 * 1625 * @return the resource list cached with the given cache key 1626 */ 1627 public List<CmsResource> getCachedResourceList(String key) { 1628 1629 return m_cacheResourceList.get(key); 1630 } 1631 1632 /** 1633 * Returns the value cached with the given cache key or <code>null</code> if not found.<p> 1634 * 1635 * @param key the cache key to look for 1636 * 1637 * @return if the user has the given role 1638 */ 1639 public Boolean getCachedRole(String key) { 1640 1641 return m_cacheHasRoles.get(key); 1642 } 1643 1644 /** 1645 * Returns the value cached with the given cache key or <code>null</code> if not found.<p> 1646 * 1647 * @param key the cache key to look for 1648 * 1649 * @return list of roles 1650 */ 1651 public List<CmsRole> getCachedRoleList(String key) { 1652 1653 return m_cacheRoleLists.get(key); 1654 } 1655 1656 /** 1657 * Returns the user cached with the given cache key or <code>null</code> if not found.<p> 1658 * 1659 * @param key the cache key to look for, this may be the user's uuid or the fqn 1660 * 1661 * @return the user cached with the given cache key 1662 */ 1663 public CmsUser getCachedUser(String key) { 1664 1665 return m_cacheUser.get(key); 1666 } 1667 1668 /** 1669 * Returns the user groups list cached with the given cache key or <code>null</code> if not found.<p> 1670 * 1671 * @param key the cache key to look for 1672 * 1673 * @return the user groups list cached with the given cache key 1674 */ 1675 public List<CmsGroup> getCachedUserGroups(String key) { 1676 1677 return m_cacheUserGroups.get(key); 1678 } 1679 1680 /** 1681 * Returns the user list cached with the given cache key or <code>null</code> if not found.<p> 1682 * 1683 * @param key the cache key to look for 1684 * 1685 * @return the user groups list cached with the given cache key 1686 */ 1687 public List<CmsUser> getCachedUserList(String key) { 1688 1689 return m_cacheUserList.get(key); 1690 } 1691 1692 /** 1693 * Returns the vfs object cached with the given cache key or <code>null</code> if not found.<p> 1694 * 1695 * @param key the cache key to look for 1696 * 1697 * @return the vfs object cached with the given cache key 1698 */ 1699 public Object getCachedVfsObject(String key) { 1700 1701 return m_cacheVfsObject.get(key); 1702 } 1703 1704 /** 1705 * Returns the xml permanent entity content cached with the given systemId or <code>null</code> if not found.<p> 1706 * 1707 * @param systemId the cache key to look for 1708 * 1709 * @return the xml permanent entity content cached with the given cache key 1710 */ 1711 public byte[] getCachedXmlPermanentEntity(String systemId) { 1712 1713 return m_cacheXmlPermanentEntity.get(systemId); 1714 } 1715 1716 /** 1717 * Returns the xml temporary entity content cached with the given cache key or <code>null</code> if not found.<p> 1718 * 1719 * @param key the cache key to look for 1720 * 1721 * @return the xml temporary entity content cached with the given cache key 1722 */ 1723 public byte[] getCachedXmlTemporaryEntity(String key) { 1724 1725 return m_cacheXmlTemporaryEntity.get(key); 1726 } 1727 1728 /** 1729 * Returns the configuration.<p> 1730 * 1731 * @return the configuration 1732 */ 1733 public CmsMemoryMonitorConfiguration getConfiguration() { 1734 1735 return m_configuration; 1736 } 1737 1738 /** 1739 * Returns the next publish job from the publish job queue.<p> 1740 * 1741 * @return the next publish job 1742 */ 1743 public CmsPublishJobInfoBean getFirstCachedPublishJob() { 1744 1745 synchronized (m_publishQueue) { 1746 if (!m_publishQueue.isEmpty()) { 1747 return (CmsPublishJobInfoBean)m_publishQueue.get(); 1748 } else { 1749 return null; 1750 } 1751 } 1752 } 1753 1754 /** 1755 * Returns the log count.<p> 1756 * 1757 * @return the log count 1758 */ 1759 public int getLogCount() { 1760 1761 return m_logCount; 1762 } 1763 1764 /** 1765 * Returns the current memory status.<p> 1766 * 1767 * @return the memory status 1768 */ 1769 public CmsMemoryStatus getMemoryStatus() { 1770 1771 m_memoryCurrent.update(); 1772 return m_memoryCurrent; 1773 } 1774 1775 /** 1776 * Initializes the monitor with the provided configuration.<p> 1777 * 1778 * @param configuration the configuration to use 1779 */ 1780 public void initialize(CmsSystemConfiguration configuration) { 1781 1782 CmsCacheSettings cacheSettings = configuration.getCacheSettings(); 1783 1784 m_memoryAverage = new CmsMemoryStatus(); 1785 m_memoryCurrent = new CmsMemoryStatus(); 1786 1787 m_warningSendSinceLastStatus = false; 1788 m_warningLoggedSinceLastStatus = false; 1789 m_lastEmailWarning = 0; 1790 m_lastEmailStatus = 0; 1791 m_lastLogStatus = 0; 1792 m_lastLogWarning = 0; 1793 m_lastClearCache = 0; 1794 m_configuration = configuration.getCmsMemoryMonitorConfiguration(); 1795 1796 m_intervalWarning = 720 * 60000; 1797 m_maxUsagePercent = 90; 1798 1799 m_intervalEmail = m_configuration.getEmailInterval() * 1000; 1800 m_intervalLog = m_configuration.getLogInterval() * 1000; 1801 1802 if (m_configuration.getWarningInterval() > 0) { 1803 m_intervalWarning = m_configuration.getWarningInterval(); 1804 } 1805 m_intervalWarning *= 1000; 1806 1807 if (m_configuration.getMaxUsagePercent() > 0) { 1808 m_maxUsagePercent = m_configuration.getMaxUsagePercent(); 1809 } 1810 1811 if (CmsLog.INIT.isInfoEnabled()) { 1812 CmsLog.INIT.info( 1813 Messages.get().getBundle().key(Messages.LOG_MM_INTERVAL_LOG_1, new Integer(m_intervalLog / 1000))); 1814 CmsLog.INIT.info( 1815 Messages.get().getBundle().key(Messages.LOG_MM_INTERVAL_EMAIL_1, new Integer(m_intervalEmail / 1000))); 1816 CmsLog.INIT.info( 1817 Messages.get().getBundle().key( 1818 Messages.LOG_MM_INTERVAL_WARNING_1, 1819 new Integer(m_intervalWarning / 1000))); 1820 CmsLog.INIT.info( 1821 Messages.get().getBundle().key(Messages.LOG_MM_INTERVAL_MAX_USAGE_1, new Integer(m_maxUsagePercent))); 1822 1823 if ((m_configuration.getEmailReceiver() == null) || (m_configuration.getEmailSender() == null)) { 1824 CmsLog.INIT.info(Messages.get().getBundle().key(Messages.LOG_MM_EMAIL_DISABLED_0)); 1825 } else { 1826 CmsLog.INIT.info( 1827 Messages.get().getBundle().key(Messages.LOG_MM_EMAIL_SENDER_1, m_configuration.getEmailSender())); 1828 Iterator<String> i = m_configuration.getEmailReceiver().iterator(); 1829 int n = 0; 1830 while (i.hasNext()) { 1831 CmsLog.INIT.info( 1832 Messages.get().getBundle().key(Messages.LOG_MM_EMAIL_RECEIVER_2, new Integer(n + 1), i.next())); 1833 n++; 1834 } 1835 } 1836 } 1837 1838 // create and register all system caches 1839 1840 // temporary xml entities cache 1841 m_cacheXmlTemporaryEntity = createLRUCacheMap(128); 1842 register(CmsXmlEntityResolver.class.getName() + ".xmlEntityTemporaryCache", m_cacheXmlTemporaryEntity); 1843 1844 // permanent xml entities cache 1845 m_cacheXmlPermanentEntity = new ConcurrentHashMap<String, byte[]>(32); 1846 register(CmsXmlEntityResolver.class.getName() + ".xmlEntityPermanentCache", m_cacheXmlPermanentEntity); 1847 1848 // xml content definitions cache 1849 m_cacheContentDefinitions = createLRUCacheMap(64); 1850 register(CmsXmlEntityResolver.class.getName() + ".contentDefinitionsCache", m_cacheContentDefinitions); 1851 1852 // lock cache 1853 m_cacheLock = new ConcurrentHashMap<String, CmsLock>(); 1854 register(CmsLockManager.class.getName(), m_cacheLock); 1855 1856 // locale cache 1857 m_cacheLocale = new ConcurrentHashMap<String, Locale>(); 1858 register(CmsLocaleManager.class.getName(), m_cacheLocale); 1859 1860 // permissions cache 1861 m_cachePermission = createLRUCacheMap(cacheSettings.getPermissionCacheSize()); 1862 register(CmsSecurityManager.class.getName(), m_cachePermission); 1863 1864 // user cache 1865 m_cacheUser = createLRUCacheMap(cacheSettings.getUserCacheSize()); 1866 register(CmsDriverManager.class.getName() + ".userCache", m_cacheUser); 1867 1868 // user list cache 1869 m_cacheUserList = createLRUCacheMap(cacheSettings.getUserCacheSize()); 1870 register(CmsDriverManager.class.getName() + ".userListCache", m_cacheUserList); 1871 1872 // group cache 1873 m_cacheGroup = createLRUCacheMap(cacheSettings.getGroupCacheSize()); 1874 register(CmsDriverManager.class.getName() + ".groupCache", m_cacheGroup); 1875 1876 // organizational unit cache 1877 m_cacheOrgUnit = createLRUCacheMap(cacheSettings.getOrgUnitCacheSize()); 1878 register(CmsDriverManager.class.getName() + ".orgUnitCache", m_cacheOrgUnit); 1879 1880 // user groups list cache 1881 m_cacheUserGroups = createLRUCacheMap(cacheSettings.getUserGroupsCacheSize()); 1882 register(CmsDriverManager.class.getName() + ".userGroupsCache", m_cacheUserGroups); 1883 1884 // project cache 1885 m_cacheProject = createLRUCacheMap(cacheSettings.getProjectCacheSize()); 1886 register(CmsDriverManager.class.getName() + ".projectCache", m_cacheProject); 1887 1888 // project resources cache cache 1889 m_cacheProjectResources = createLRUCacheMap(cacheSettings.getProjectResourcesCacheSize()); 1890 register(CmsDriverManager.class.getName() + ".projectResourcesCache", m_cacheProjectResources); 1891 1892 // publish history 1893 int size = configuration.getPublishManager().getPublishHistorySize(); 1894 Buffer buffer = CmsPublishHistory.getQueue(size); 1895 m_publishHistory = SynchronizedBuffer.decorate(buffer); 1896 register(CmsPublishHistory.class.getName() + ".publishHistory", buffer); 1897 1898 // publish queue 1899 buffer = CmsPublishQueue.getQueue(); 1900 m_publishQueue = SynchronizedBuffer.decorate(buffer); 1901 register(CmsPublishQueue.class.getName() + ".publishQueue", buffer); 1902 1903 // resource cache 1904 m_cacheResource = createLRUCacheMap(cacheSettings.getResourceCacheSize()); 1905 register(CmsDriverManager.class.getName() + ".resourceCache", m_cacheResource); 1906 1907 // roles cache 1908 m_cacheHasRoles = createLRUCacheMap(cacheSettings.getRolesCacheSize()); 1909 register(CmsDriverManager.class.getName() + ".rolesCache", m_cacheHasRoles); 1910 1911 // role lists cache 1912 m_cacheRoleLists = createLRUCacheMap(cacheSettings.getRolesCacheSize()); 1913 register(CmsDriverManager.class.getName() + ".roleListsCache", m_cacheRoleLists); 1914 1915 // resource list cache 1916 m_cacheResourceList = createLRUCacheMap(cacheSettings.getResourcelistCacheSize()); 1917 register(CmsDriverManager.class.getName() + ".resourceListCache", m_cacheResourceList); 1918 1919 // property cache 1920 m_cacheProperty = createLRUCacheMap(cacheSettings.getPropertyCacheSize()); 1921 register(CmsDriverManager.class.getName() + ".propertyCache", m_cacheProperty); 1922 1923 // property list cache 1924 m_cachePropertyList = createLRUCacheMap(cacheSettings.getPropertyListsCacheSize()); 1925 register(CmsDriverManager.class.getName() + ".propertyListCache", m_cachePropertyList); 1926 1927 // published resources list cache 1928 m_cachePublishedResources = createLRUCacheMap(5); 1929 register(CmsDriverManager.class.getName() + ".publishedResourcesCache", m_cachePublishedResources); 1930 1931 // acl cache 1932 m_cacheAccessControlList = createLRUCacheMap(cacheSettings.getAclCacheSize()); 1933 register(CmsDriverManager.class.getName() + ".accessControlListCache", m_cacheAccessControlList); 1934 1935 // vfs object cache 1936 m_cacheVfsObject = new ConcurrentHashMap<String, Object>(); 1937 register(CmsVfsMemoryObjectCache.class.getName(), m_cacheVfsObject); 1938 1939 // memory object cache 1940 m_cacheMemObject = new ConcurrentHashMap<String, Object>(); 1941 register(CmsMemoryObjectCache.class.getName(), m_cacheMemObject); 1942 1943 if (LOG.isDebugEnabled()) { 1944 // this will happen only once during system startup 1945 LOG.debug(Messages.get().getBundle().key(Messages.LOG_MM_CREATED_1, new Date(System.currentTimeMillis()))); 1946 } 1947 } 1948 1949 /** 1950 * Checks if the property cache is enabled.<p> 1951 * 1952 * @return <code>true</code> if the property cache is enabled 1953 * 1954 * @deprecated use {@link #isEnabled(CacheType)} instead 1955 */ 1956 @Deprecated 1957 public boolean isCacheProperty() { 1958 1959 return isEnabled(CacheType.PROPERTY); 1960 } 1961 1962 /** 1963 * Checks if the property list cache is enabled.<p> 1964 * 1965 * @return <code>true</code> if the property list cache is enabled 1966 * 1967 * @deprecated use {@link #isEnabled(CacheType)} instead 1968 */ 1969 @Deprecated 1970 public boolean isCachePropertyList() { 1971 1972 return isEnabled(CacheType.PROPERTY_LIST); 1973 } 1974 1975 /** 1976 * Checks if the resource cache is enabled.<p> 1977 * 1978 * @return <code>true</code> if the resource cache is enabled 1979 * 1980 * @deprecated use {@link #isEnabled(CacheType)} instead 1981 */ 1982 @Deprecated 1983 public boolean isCacheResource() { 1984 1985 return isEnabled(CacheType.RESOURCE); 1986 } 1987 1988 /** 1989 * Checks if the resource list cache is enabled.<p> 1990 * 1991 * @return <code>true</code> if the resource list cache is enabled 1992 * 1993 * @deprecated use {@link #isEnabled(CacheType)} instead 1994 */ 1995 @Deprecated 1996 public boolean isCacheResourceList() { 1997 1998 return isEnabled(CacheType.RESOURCE_LIST); 1999 } 2000 2001 /** 2002 * Checks if the given cache is enabled.<p> 2003 * 2004 * @param type the cache type to check 2005 * 2006 * @return <code>true</code> if the given cache is enabled 2007 */ 2008 public boolean isEnabled(CacheType type) { 2009 2010 return (m_disabled.get(type) == null); 2011 } 2012 2013 /** 2014 * Checks if there is a registered monitored object with the given key.<p> 2015 * 2016 * @param key the key to look for 2017 * 2018 * @return <code>true</code> if there is a registered monitored object with the given key 2019 */ 2020 public boolean isMonitoring(String key) { 2021 2022 return (m_monitoredObjects.get(key) != null); 2023 } 2024 2025 /** 2026 * @see org.opencms.scheduler.I_CmsScheduledJob#launch(CmsObject, Map) 2027 */ 2028 public String launch(CmsObject cms, Map<String, String> parameters) throws Exception { 2029 2030 CmsMemoryMonitor monitor = OpenCms.getMemoryMonitor(); 2031 2032 // make sure job is not launched twice 2033 if (m_currentlyRunning) { 2034 return null; 2035 } 2036 2037 try { 2038 m_currentlyRunning = true; 2039 2040 // update the memory status 2041 monitor.updateStatus(); 2042 2043 // check if the system is in a low memory condition 2044 if (monitor.lowMemory()) { 2045 // log warning 2046 monitor.monitorWriteLog(true); 2047 // send warning email 2048 monitor.monitorSendEmail(true); 2049 // clean up caches 2050 monitor.clearCaches(); 2051 } 2052 2053 // check if regular a log entry must be written 2054 if ((System.currentTimeMillis() - monitor.m_lastLogStatus) > monitor.m_intervalLog) { 2055 monitor.monitorWriteLog(false); 2056 } 2057 2058 // check if the memory status email must be send 2059 if ((System.currentTimeMillis() - monitor.m_lastEmailStatus) > monitor.m_intervalEmail) { 2060 monitor.monitorSendEmail(false); 2061 } 2062 } finally { 2063 // make sure state is reset even if an error occurs, 2064 // otherwise MM will not be executed after an error 2065 m_currentlyRunning = false; 2066 } 2067 2068 return null; 2069 } 2070 2071 /** 2072 * Returns true if the system runs low on memory.<p> 2073 * 2074 * @return true if the system runs low on memory 2075 */ 2076 public boolean lowMemory() { 2077 2078 return ((m_maxUsagePercent > 0) && (m_memoryCurrent.getUsage() > m_maxUsagePercent)); 2079 } 2080 2081 /** 2082 * Adds a new object to the monitor.<p> 2083 * 2084 * @param objectName name of the object 2085 * @param object the object for monitoring 2086 */ 2087 public void register(String objectName, Object object) { 2088 2089 if (enabled()) { 2090 m_monitoredObjects.put(objectName, object); 2091 } 2092 } 2093 2094 /** 2095 * Checks if some kind of persistence is required.<p> 2096 * 2097 * This could be overwritten in a distributed environment.<p> 2098 * 2099 * @return <code>true</code> if some kind of persistence is required 2100 */ 2101 public boolean requiresPersistency() { 2102 2103 return true; 2104 } 2105 2106 /** 2107 * Sets if the property cache is enabled.<p> 2108 * 2109 * @param cacheProperty if the property cache is enabled 2110 * 2111 * @deprecated use {@link #enableCache(CacheType[])} or {@link #disableCache(CacheType[])} instead 2112 */ 2113 @Deprecated 2114 public void setCacheProperty(boolean cacheProperty) { 2115 2116 if (cacheProperty) { 2117 enableCache(CacheType.PROPERTY); 2118 } else { 2119 disableCache(CacheType.PROPERTY); 2120 } 2121 } 2122 2123 /** 2124 * Sets if the property list cache is enabled.<p> 2125 * 2126 * @param cachePropertyList if the property list cache is enabled 2127 * 2128 * @deprecated use {@link #enableCache(CacheType[])} or {@link #disableCache(CacheType[])} instead 2129 */ 2130 @Deprecated 2131 public void setCachePropertyList(boolean cachePropertyList) { 2132 2133 if (cachePropertyList) { 2134 enableCache(CacheType.PROPERTY_LIST); 2135 } else { 2136 disableCache(CacheType.PROPERTY_LIST); 2137 } 2138 } 2139 2140 /** 2141 * Sets if the resource cache is enabled.<p> 2142 * 2143 * @param cacheResource if the resource cache is enabled 2144 * 2145 * @deprecated use {@link #enableCache(CacheType[])} or {@link #disableCache(CacheType[])} instead 2146 */ 2147 @Deprecated 2148 public void setCacheResource(boolean cacheResource) { 2149 2150 if (cacheResource) { 2151 enableCache(CacheType.RESOURCE); 2152 } else { 2153 disableCache(CacheType.RESOURCE); 2154 } 2155 } 2156 2157 /** 2158 * Sets if the resource list cache is enabled.<p> 2159 * 2160 * @param cacheResourceList if the resource list cache is enabled 2161 * 2162 * @deprecated use {@link #enableCache(CacheType[])} or {@link #disableCache(CacheType[])} instead 2163 */ 2164 @Deprecated 2165 public void setCacheResourceList(boolean cacheResourceList) { 2166 2167 if (cacheResourceList) { 2168 enableCache(CacheType.RESOURCE_LIST); 2169 } else { 2170 disableCache(CacheType.RESOURCE_LIST); 2171 } 2172 } 2173 2174 /** 2175 * Flushes all cached objects.<p> 2176 * 2177 * @throws Exception if something goes wrong 2178 */ 2179 public void shutdown() throws Exception { 2180 2181 for (CacheType type : CacheType.values()) { 2182 flushCache(type); 2183 } 2184 } 2185 2186 /** 2187 * Removes the given xml content definition from the cache.<p> 2188 * 2189 * @param key the cache key to remove from cache 2190 */ 2191 public void uncacheContentDefinition(String key) { 2192 2193 m_cacheContentDefinitions.remove(key); 2194 } 2195 2196 /** 2197 * Removes the given group from the cache.<p> 2198 * 2199 * The group is removed by name AND also by uuid.<p> 2200 * 2201 * @param group the group to remove from cache 2202 */ 2203 public void uncacheGroup(CmsGroup group) { 2204 2205 m_cacheGroup.remove(group.getId().toString()); 2206 m_cacheGroup.remove(group.getName()); 2207 } 2208 2209 /** 2210 * Removes the cached lock for the given root path from the cache.<p> 2211 * 2212 * @param rootPath the root path of the lock to remove from cache 2213 */ 2214 public void uncacheLock(String rootPath) { 2215 2216 m_cacheLock.remove(rootPath); 2217 } 2218 2219 /** 2220 * Removes the given organizational unit from the cache.<p> 2221 * 2222 * The organizational unit is removed by name AND also by uuid.<p> 2223 * 2224 * @param orgUnit the organizational unit to remove from cache 2225 */ 2226 public void uncacheOrgUnit(CmsOrganizationalUnit orgUnit) { 2227 2228 m_cacheOrgUnit.remove(orgUnit.getId().toString()); 2229 m_cacheOrgUnit.remove(orgUnit.getName()); 2230 } 2231 2232 /** 2233 * Removes the given project from the cache.<p> 2234 * 2235 * The project is removed by name AND also by uuid.<p> 2236 * 2237 * @param project the project to remove from cache 2238 */ 2239 public void uncacheProject(CmsProject project) { 2240 2241 m_cacheProject.remove(project.getUuid().toString()); 2242 m_cacheProject.remove(project.getName()); 2243 } 2244 2245 /** 2246 * Removes the given publish job from the cache.<p> 2247 * 2248 * @param publishJob the publish job to remove 2249 */ 2250 public void uncachePublishJob(CmsPublishJobInfoBean publishJob) { 2251 2252 m_publishQueue.remove(publishJob); 2253 } 2254 2255 /** 2256 * Removes the given publish job from the history.<p> 2257 * 2258 * @param publishJob the publish job to remove 2259 */ 2260 public void uncachePublishJobInHistory(CmsPublishJobInfoBean publishJob) { 2261 2262 m_publishHistory.remove(publishJob); 2263 } 2264 2265 /** 2266 * Removes the given user from the cache.<p> 2267 * 2268 * The user is removed by name AND also by uuid.<p> 2269 * 2270 * @param user the user to remove from cache 2271 */ 2272 public void uncacheUser(CmsUser user) { 2273 2274 m_cacheUser.remove(user.getId().toString()); 2275 m_cacheUser.remove(user.getName()); 2276 } 2277 2278 /** 2279 * Removes the given vfs object from the cache.<p> 2280 * 2281 * @param key the cache key to remove from cache 2282 */ 2283 public void uncacheVfsObject(String key) { 2284 2285 m_cacheVfsObject.remove(key); 2286 } 2287 2288 /** 2289 * Removes the given xml temporary entity from the cache.<p> 2290 * 2291 * @param key the cache key to remove from cache 2292 */ 2293 public void uncacheXmlTemporaryEntity(String key) { 2294 2295 m_cacheXmlTemporaryEntity.remove(key); 2296 } 2297 2298 /** 2299 * Clears the OpenCms caches.<p> 2300 */ 2301 protected void clearCaches() { 2302 2303 if ((m_lastClearCache + INTERVAL_CLEAR) > System.currentTimeMillis()) { 2304 // if the cache has already been cleared less then 15 minutes ago we skip this because 2305 // clearing the caches to often will hurt system performance and the 2306 // setup seems to be in trouble anyway 2307 return; 2308 } 2309 m_lastClearCache = System.currentTimeMillis(); 2310 if (LOG.isWarnEnabled()) { 2311 LOG.warn(Messages.get().getBundle().key(Messages.LOG_CLEAR_CACHE_MEM_CONS_0)); 2312 } 2313 OpenCms.fireCmsEvent( 2314 new CmsEvent(I_CmsEventListener.EVENT_CLEAR_CACHES, Collections.<String, Object> emptyMap())); 2315 System.gc(); 2316 } 2317 2318 /** 2319 * Returns the cache costs of a monitored object.<p> 2320 * 2321 * <code>obj</code> must be of type {@link CmsLruCache}.<p> 2322 * 2323 * @param obj the object 2324 * 2325 * @return the cache costs or "-" 2326 */ 2327 protected long getCosts(Object obj) { 2328 2329 long costs = 0; 2330 if (obj instanceof CmsLruCache) { 2331 costs = ((CmsLruCache)obj).getObjectCosts(); 2332 if (costs < 0) { 2333 costs = 0; 2334 } 2335 } 2336 2337 return costs; 2338 } 2339 2340 /** 2341 * Returns the number of items within a monitored object.<p> 2342 * 2343 * <code>obj</code> must be of type {@link CmsLruCache} or {@link Map}.<p> 2344 * 2345 * @param obj the object 2346 * 2347 * @return the number of items or "-" 2348 */ 2349 protected String getItems(Object obj) { 2350 2351 if (obj instanceof CmsLruCache) { 2352 return Integer.toString(((CmsLruCache)obj).size()); 2353 } 2354 if (obj instanceof Map) { 2355 return Integer.toString(((Map<?, ?>)obj).size()); 2356 } 2357 return "-"; 2358 } 2359 2360 /** 2361 * Returns the total size of key strings within a monitored map.<p> 2362 * 2363 * The keys must be of type {@link String}.<p> 2364 * 2365 * @param map the map 2366 * @param depth the max recursion depth for calculation the size 2367 * 2368 * @return total size of key strings 2369 */ 2370 protected long getKeySize(Map<?, ?> map, int depth) { 2371 2372 long keySize = 0; 2373 try { 2374 Object[] values = map.values().toArray(); 2375 for (int i = 0, s = values.length; i < s; i++) { 2376 2377 Object obj = values[i]; 2378 2379 if ((obj instanceof Map) && (depth < MAX_DEPTH)) { 2380 keySize += getKeySize((Map<?, ?>)obj, depth + 1); 2381 continue; 2382 } 2383 } 2384 values = null; 2385 2386 Object[] keys = map.keySet().toArray(); 2387 for (int i = 0, s = keys.length; i < s; i++) { 2388 2389 Object obj = keys[i]; 2390 2391 if (obj instanceof String) { 2392 String st = (String)obj; 2393 keySize += (st.length() * 2); 2394 } 2395 } 2396 } catch (ConcurrentModificationException e) { 2397 // this might happen since even the .toArray() method internally creates an iterator 2398 } catch (Throwable t) { 2399 // catch all other exceptions otherwise the whole monitor will stop working 2400 if (LOG.isDebugEnabled()) { 2401 LOG.debug(Messages.get().getBundle().key(Messages.LOG_CAUGHT_THROWABLE_1, t.getMessage())); 2402 } 2403 } 2404 2405 return keySize; 2406 } 2407 2408 /** 2409 * Returns the total size of key strings within a monitored object.<p> 2410 * 2411 * <code>obj</code> must be of type {@link Map}, the keys must be of type {@link String}.<p> 2412 * 2413 * @param obj the object 2414 * 2415 * @return the total size of key strings 2416 */ 2417 protected long getKeySize(Object obj) { 2418 2419 if (obj instanceof Map) { 2420 return getKeySize((Map<?, ?>)obj, 1); 2421 } 2422 2423 return 0; 2424 } 2425 2426 /** 2427 * Returns the max costs for all items within a monitored object.<p> 2428 * 2429 * <code>obj</code> must be of type {@link CmsLruCache} or {@link LRUMap}.<p> 2430 * 2431 * @param obj the object 2432 * 2433 * @return max cost limit or "-" 2434 */ 2435 protected String getLimit(Object obj) { 2436 2437 if (obj instanceof CmsLruCache) { 2438 return Long.toString(((CmsLruCache)obj).getMaxCacheCosts()); 2439 } 2440 if (obj instanceof LRUMap) { 2441 return Integer.toString(((LRUMap)obj).maxSize()); 2442 } 2443 2444 return "-"; 2445 } 2446 2447 /** 2448 * Sends a warning or status email with OpenCms Memory information.<p> 2449 * 2450 * @param warning if true, send a memory warning email 2451 */ 2452 protected void monitorSendEmail(boolean warning) { 2453 2454 if ((m_configuration.getEmailSender() == null) || (m_configuration.getEmailReceiver() == null)) { 2455 // send no mails if not fully configured 2456 return; 2457 } else if (warning 2458 && (m_warningSendSinceLastStatus 2459 && !((m_intervalEmail <= 0) 2460 && (System.currentTimeMillis() < (m_lastEmailWarning + m_intervalWarning))))) { 2461 // send no warning email if no status email has been send since the last warning 2462 // if status is disabled, send no warn email if warn interval has not passed 2463 return; 2464 } else if ((!warning) && (m_intervalEmail <= 0)) { 2465 // if email iterval is <= 0 status email is disabled 2466 return; 2467 } 2468 String date = CmsDateUtil.getDateTimeShort(System.currentTimeMillis()); 2469 String subject; 2470 String content = ""; 2471 if (warning) { 2472 m_warningSendSinceLastStatus = true; 2473 m_lastEmailWarning = System.currentTimeMillis(); 2474 subject = "OpenCms Memory W A R N I N G [" 2475 + OpenCms.getSystemInfo().getServerName().toUpperCase() 2476 + "/" 2477 + date 2478 + "]"; 2479 content += "W A R N I N G !\nOpenCms memory consumption on server " 2480 + OpenCms.getSystemInfo().getServerName().toUpperCase() 2481 + " has reached a critical level !\n\n" 2482 + "The configured limit is " 2483 + m_maxUsagePercent 2484 + "%\n\n"; 2485 } else { 2486 m_warningSendSinceLastStatus = false; 2487 m_lastEmailStatus = System.currentTimeMillis(); 2488 subject = "OpenCms Memory Status [" 2489 + OpenCms.getSystemInfo().getServerName().toUpperCase() 2490 + "/" 2491 + date 2492 + "]"; 2493 } 2494 2495 content += "Memory usage report of OpenCms server " 2496 + OpenCms.getSystemInfo().getServerName().toUpperCase() 2497 + " at " 2498 + date 2499 + "\n\n" 2500 + "Memory maximum heap size: " 2501 + m_memoryCurrent.getMaxMemory() 2502 + " mb\n" 2503 + "Memory current heap size: " 2504 + m_memoryCurrent.getTotalMemory() 2505 + " mb\n\n" 2506 + "Memory currently used : " 2507 + m_memoryCurrent.getUsedMemory() 2508 + " mb (" 2509 + m_memoryCurrent.getUsage() 2510 + "%)\n" 2511 + "Memory currently unused : " 2512 + m_memoryCurrent.getFreeMemory() 2513 + " mb\n\n\n"; 2514 2515 if (warning) { 2516 content += "*** Please take action NOW to ensure that no OutOfMemoryException occurs.\n\n\n"; 2517 } 2518 2519 CmsSessionManager sm = OpenCms.getSessionManager(); 2520 2521 if (sm != null) { 2522 content += "Current status of the sessions:\n\n"; 2523 content += "Logged in users : " + sm.getSessionCountAuthenticated() + "\n"; 2524 content += "Currently active sessions: " + sm.getSessionCountCurrent() + "\n"; 2525 content += "Total created sessions : " + sm.getSessionCountTotal() + "\n\n\n"; 2526 } 2527 2528 sm = null; 2529 2530 content += "Current status of the caches:\n\n"; 2531 List<String> keyList = new ArrayList<String>(m_monitoredObjects.keySet()); 2532 Collections.sort(keyList); 2533 long totalSize = 0; 2534 for (Iterator<String> keys = keyList.iterator(); keys.hasNext();) { 2535 String key = keys.next(); 2536 String[] shortKeys = key.split("\\."); 2537 String shortKey = shortKeys[shortKeys.length - 2] + '.' + shortKeys[shortKeys.length - 1]; 2538 PrintfFormat form = new PrintfFormat("%9s"); 2539 Object obj = m_monitoredObjects.get(key); 2540 2541 long size = getKeySize(obj) + getValueSize(obj) + getCosts(obj); 2542 totalSize += size; 2543 2544 content += new PrintfFormat("%-42.42s").sprintf(shortKey) 2545 + " " 2546 + "Entries: " 2547 + form.sprintf(getItems(obj)) 2548 + " " 2549 + "Limit: " 2550 + form.sprintf(getLimit(obj)) 2551 + " " 2552 + "Size: " 2553 + form.sprintf(Long.toString(size)) 2554 + "\n"; 2555 } 2556 content += "\nTotal size of cache memory monitored: " + totalSize + " (" + (totalSize / 1048576) + ")\n\n"; 2557 2558 String from = m_configuration.getEmailSender(); 2559 List<InternetAddress> receivers = new ArrayList<InternetAddress>(); 2560 List<String> receiverEmails = m_configuration.getEmailReceiver(); 2561 try { 2562 if ((from != null) && (receiverEmails != null) && !receiverEmails.isEmpty()) { 2563 Iterator<String> i = receiverEmails.iterator(); 2564 while (i.hasNext()) { 2565 receivers.add(new InternetAddress(i.next())); 2566 } 2567 CmsSimpleMail email = new CmsSimpleMail(); 2568 email.setFrom(from); 2569 email.setTo(receivers); 2570 email.setSubject(subject); 2571 email.setMsg(content); 2572 new CmsMailTransport(email).send(); 2573 } 2574 if (LOG.isInfoEnabled()) { 2575 if (warning) { 2576 LOG.info(Messages.get().getBundle().key(Messages.LOG_MM_WARNING_EMAIL_SENT_0)); 2577 } else { 2578 LOG.info(Messages.get().getBundle().key(Messages.LOG_MM_STATUS_EMAIL_SENT_0)); 2579 } 2580 } 2581 } catch (Exception e) { 2582 e.printStackTrace(); 2583 } 2584 } 2585 2586 /** 2587 * Write a warning or status log entry with OpenCms Memory information.<p> 2588 * 2589 * @param warning if true, write a memory warning log entry 2590 */ 2591 protected void monitorWriteLog(boolean warning) { 2592 2593 if (!LOG.isWarnEnabled()) { 2594 // we need at last warn level for this output 2595 return; 2596 } else if ((!warning) && (!LOG.isInfoEnabled())) { 2597 // if not warning we need info level 2598 return; 2599 } else if (warning 2600 && (m_warningLoggedSinceLastStatus 2601 && !(((m_intervalLog <= 0) 2602 && (System.currentTimeMillis() < (m_lastLogWarning + m_intervalWarning)))))) { 2603 // write no warning log if no status log has been written since the last warning 2604 // if status is disabled, log no warn entry if warn interval has not passed 2605 return; 2606 } else if ((!warning) && (m_intervalLog <= 0)) { 2607 // if log interval is <= 0 status log is disabled 2608 return; 2609 } 2610 2611 if (warning) { 2612 m_lastLogWarning = System.currentTimeMillis(); 2613 m_warningLoggedSinceLastStatus = true; 2614 LOG.warn( 2615 Messages.get().getBundle().key( 2616 Messages.LOG_MM_WARNING_MEM_CONSUME_2, 2617 new Long(m_memoryCurrent.getUsage()), 2618 new Integer(m_maxUsagePercent))); 2619 } else { 2620 m_warningLoggedSinceLastStatus = false; 2621 m_lastLogStatus = System.currentTimeMillis(); 2622 } 2623 2624 if (warning) { 2625 LOG.warn( 2626 Messages.get().getBundle().key( 2627 Messages.LOG_MM_WARNING_MEM_STATUS_6, 2628 new Object[] { 2629 new Long(m_memoryCurrent.getMaxMemory()), 2630 new Long(m_memoryCurrent.getTotalMemory()), 2631 new Long(m_memoryCurrent.getFreeMemory()), 2632 new Long(m_memoryCurrent.getUsedMemory()), 2633 new Long(m_memoryCurrent.getUsage()), 2634 new Integer(m_maxUsagePercent)})); 2635 } else { 2636 m_logCount++; 2637 LOG.info( 2638 Messages.get().getBundle().key( 2639 Messages.LOG_MM_LOG_INFO_2, 2640 OpenCms.getSystemInfo().getServerName().toUpperCase(), 2641 String.valueOf(m_logCount))); 2642 2643 List<String> keyList = new ArrayList<String>(m_monitoredObjects.keySet()); 2644 Collections.sort(keyList); 2645 long totalSize = 0; 2646 for (Iterator<String> keys = keyList.iterator(); keys.hasNext();) { 2647 String key = keys.next(); 2648 Object obj = m_monitoredObjects.get(key); 2649 2650 long size = getKeySize(obj) + getValueSize(obj) + getCosts(obj); 2651 totalSize += size; 2652 2653 PrintfFormat name1 = new PrintfFormat("%-80s"); 2654 PrintfFormat name2 = new PrintfFormat("%-50s"); 2655 PrintfFormat form = new PrintfFormat("%9s"); 2656 LOG.info( 2657 Messages.get().getBundle().key( 2658 Messages.LOG_MM_NOWARN_STATUS_5, 2659 new Object[] { 2660 name1.sprintf(key), 2661 name2.sprintf(obj.getClass().getName()), 2662 form.sprintf(getItems(obj)), 2663 form.sprintf(getLimit(obj)), 2664 form.sprintf(Long.toString(size))})); 2665 } 2666 2667 LOG.info( 2668 Messages.get().getBundle().key( 2669 Messages.LOG_MM_WARNING_MEM_STATUS_6, 2670 new Object[] { 2671 new Long(m_memoryCurrent.getMaxMemory()), 2672 new Long(m_memoryCurrent.getTotalMemory()), 2673 new Long(m_memoryCurrent.getFreeMemory()), 2674 new Long(m_memoryCurrent.getUsedMemory()), 2675 new Long(m_memoryCurrent.getUsage()), 2676 new Integer(m_maxUsagePercent), 2677 new Long(totalSize), 2678 new Long(totalSize / 1048576)}) 2679 2680 ); 2681 LOG.info( 2682 Messages.get().getBundle().key( 2683 Messages.LOG_MM_WARNING_MEM_STATUS_AVG_6, 2684 new Object[] { 2685 new Long(m_memoryAverage.getMaxMemory()), 2686 new Long(m_memoryAverage.getTotalMemory()), 2687 new Long(m_memoryAverage.getFreeMemory()), 2688 new Long(m_memoryAverage.getUsedMemory()), 2689 new Long(m_memoryAverage.getUsage()), 2690 new Integer(m_memoryAverage.getCount())})); 2691 2692 CmsSessionManager sm = OpenCms.getSessionManager(); 2693 2694 if (sm != null) { 2695 LOG.info( 2696 Messages.get().getBundle().key( 2697 Messages.LOG_MM_SESSION_STAT_3, 2698 String.valueOf(sm.getSessionCountAuthenticated()), 2699 String.valueOf(sm.getSessionCountCurrent()), 2700 String.valueOf(sm.getSessionCountTotal()))); 2701 } 2702 sm = null; 2703 2704 for (Iterator<String> i = OpenCms.getSqlManager().getDbPoolUrls().iterator(); i.hasNext();) { 2705 String poolname = i.next(); 2706 try { 2707 LOG.info( 2708 Messages.get().getBundle().key( 2709 Messages.LOG_MM_CONNECTIONS_3, 2710 poolname, 2711 Integer.toString(OpenCms.getSqlManager().getActiveConnections(poolname)), 2712 Integer.toString(OpenCms.getSqlManager().getIdleConnections(poolname)))); 2713 } catch (Exception exc) { 2714 LOG.info( 2715 Messages.get().getBundle().key( 2716 Messages.LOG_MM_CONNECTIONS_3, 2717 poolname, 2718 Integer.toString(-1), 2719 Integer.toString(-1))); 2720 } 2721 } 2722 2723 LOG.info( 2724 Messages.get().getBundle().key( 2725 Messages.LOG_MM_STARTUP_TIME_2, 2726 CmsDateUtil.getDateTimeShort(OpenCms.getSystemInfo().getStartupTime()), 2727 CmsStringUtil.formatRuntime(OpenCms.getSystemInfo().getRuntime()))); 2728 } 2729 } 2730 2731 /** 2732 * Updates the memory information of the memory monitor.<p> 2733 */ 2734 protected void updateStatus() { 2735 2736 m_memoryCurrent.update(); 2737 m_memoryAverage.calculateAverage(m_memoryCurrent); 2738 } 2739}