001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH & Co. KG (https://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, please see the 018 * company website: https://www.alkacon.com 019 * 020 * For further information about OpenCms, please see the 021 * project website: https://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.xml.containerpage; 029 030import org.opencms.ade.configuration.CmsADEConfigData; 031import org.opencms.ade.configuration.CmsADEManager; 032import org.opencms.ade.containerpage.shared.CmsContainerElement; 033import org.opencms.ade.containerpage.shared.CmsContainerElement.ModelGroupState; 034import org.opencms.ade.containerpage.shared.CmsFormatterConfig; 035import org.opencms.ade.containerpage.shared.CmsInheritanceInfo; 036import org.opencms.file.CmsFile; 037import org.opencms.file.CmsObject; 038import org.opencms.file.CmsResource; 039import org.opencms.file.CmsResourceFilter; 040import org.opencms.file.types.CmsResourceTypeXmlContainerPage; 041import org.opencms.file.types.CmsResourceTypeXmlContent; 042import org.opencms.file.types.I_CmsResourceType; 043import org.opencms.main.CmsException; 044import org.opencms.main.OpenCms; 045import org.opencms.util.CmsNullIgnoringConcurrentMap; 046import org.opencms.util.CmsUUID; 047import org.opencms.xml.CmsXmlContentDefinition; 048import org.opencms.xml.content.CmsXmlContent; 049import org.opencms.xml.content.CmsXmlContentFactory; 050import org.opencms.xml.content.CmsXmlContentPropertyHelper; 051 052import java.util.Arrays; 053import java.util.Collections; 054import java.util.HashMap; 055import java.util.Locale; 056import java.util.Map; 057 058import javax.servlet.ServletRequest; 059 060/** 061 * One element of a container in a container page.<p> 062 * 063 * @since 8.0 064 */ 065public class CmsContainerElementBean implements Cloneable { 066 067 /** Prevent caching in ADE session cache. */ 068 private boolean m_doNotCache; 069 070 /** Flag indicating if a new element should be created replacing the given one on first edit of a container-page. */ 071 private final boolean m_createNew; 072 073 /** The client ADE editor hash. */ 074 private transient String m_editorHash; 075 076 /** The element's structure id. */ 077 private CmsUUID m_elementId; 078 079 /** The formatter's structure id. */ 080 private CmsUUID m_formatterId; 081 082 /** The configured properties. */ 083 private Map<String, String> m_individualSettings; 084 085 /** The inheritance info of this element. */ 086 private CmsInheritanceInfo m_inheritanceInfo; 087 088 /** Indicates whether the represented resource is in memory only and not in the VFS. */ 089 private boolean m_inMemoryOnly; 090 091 /** True if the element is used for a historical content. */ 092 private boolean m_isHistory; 093 094 /** Indicating if the element resource is released and not expired. */ 095 private boolean m_releasedAndNotExpired; 096 097 /** The resource of this element. */ 098 private transient CmsResource m_resource; 099 100 /** The settings of this element containing also default values. */ 101 private transient Map<String, String> m_settings; 102 103 /** The element site path, only set while rendering. */ 104 private String m_sitePath; 105 106 /** Indicates the element bean has a temporary file content set. */ 107 private boolean m_temporaryContent; 108 109 /** 110 * Creates a new container page element bean.<p> 111 * 112 * @param file the element's file 113 * @param formatterId the formatter's structure id, could be <code>null</code> 114 * @param individualSettings the element settings as a map of name/value pairs 115 * @param inMemoryOnly the in memory flag 116 * @param editorHash the editor hash to use 117 * @param createNew <code>true</code> if a new element should be created replacing the given one on first edit of a container-page 118 **/ 119 public CmsContainerElementBean( 120 CmsFile file, 121 CmsUUID formatterId, 122 Map<String, String> individualSettings, 123 boolean inMemoryOnly, 124 String editorHash, 125 boolean createNew) { 126 127 this(file.getStructureId(), formatterId, individualSettings, createNew); 128 m_inMemoryOnly = inMemoryOnly; 129 m_editorHash = editorHash; 130 m_resource = file; 131 } 132 133 /** 134 * Creates a new container page element bean.<p> 135 * 136 * @param elementId the element's structure id 137 * @param formatterId the formatter's structure id, could be <code>null</code> 138 * @param individualSettings the element settings as a map of name/value pairs 139 * @param createNew <code>true</code> if a new element should be created replacing the given one on first edit of a container-page 140 **/ 141 public CmsContainerElementBean( 142 CmsUUID elementId, 143 CmsUUID formatterId, 144 Map<String, String> individualSettings, 145 boolean createNew) { 146 147 m_elementId = elementId; 148 m_formatterId = formatterId; 149 Map<String, String> newSettings = (individualSettings == null 150 ? new HashMap<String, String>() 151 : new HashMap<String, String>(individualSettings)); 152 if (!newSettings.containsKey(CmsContainerElement.ELEMENT_INSTANCE_ID)) { 153 newSettings.put(CmsContainerElement.ELEMENT_INSTANCE_ID, new CmsUUID().toString()); 154 } 155 newSettings.values().removeAll(Collections.singletonList(null)); 156 m_individualSettings = Collections.unmodifiableMap(newSettings); 157 m_editorHash = m_elementId.toString() + getSettingsHash(); 158 m_createNew = createNew; 159 } 160 161 /** 162 * Constructor to enable wrapped elements.<p> 163 */ 164 protected CmsContainerElementBean() { 165 166 m_elementId = null; 167 m_createNew = false; 168 } 169 170 /** 171 * Cloning constructor.<p> 172 * 173 * @param createNew create new flag 174 * @param elementId element id 175 * @param formatterId formatter id 176 * @param individualSettings individual settings 177 * @param inheritanceInfo inheritance info 178 * @param inMemoryOnly in memory only flag 179 * @param temporaryContent temporary content flag 180 * @param releasedAndNotExpired released and not expired flag 181 * @param resource the resource/file object 182 * @param settings the settings 183 * @param sitePath the site path 184 */ 185 private CmsContainerElementBean( 186 boolean createNew, 187 CmsUUID elementId, 188 CmsUUID formatterId, 189 Map<String, String> individualSettings, 190 CmsInheritanceInfo inheritanceInfo, 191 boolean inMemoryOnly, 192 boolean temporaryContent, 193 boolean releasedAndNotExpired, 194 CmsResource resource, 195 Map<String, String> settings, 196 String sitePath) { 197 198 m_createNew = createNew; 199 m_elementId = elementId; 200 m_formatterId = formatterId; 201 m_individualSettings = Collections.unmodifiableMap(individualSettings); 202 m_inheritanceInfo = inheritanceInfo; 203 m_inMemoryOnly = inMemoryOnly; 204 m_releasedAndNotExpired = releasedAndNotExpired; 205 m_resource = resource; 206 setSettings(settings); 207 m_sitePath = sitePath; 208 m_temporaryContent = temporaryContent; 209 } 210 211 /** 212 * Clones the given element bean with a different formatter.<p> 213 * 214 * @param source the element to clone 215 * @param formatterId the new formatter id 216 * 217 * @return the element bean 218 */ 219 public static CmsContainerElementBean cloneWithFormatter(CmsContainerElementBean source, CmsUUID formatterId) { 220 221 CmsContainerElementBean result = source.clone(); 222 result.m_formatterId = formatterId; 223 return result; 224 } 225 226 /** 227 * Clones the given element bean with a different set of settings.<p> 228 * 229 * @param source the element to clone 230 * @param settings the new settings 231 * 232 * @return the element bean 233 */ 234 public static CmsContainerElementBean cloneWithSettings( 235 CmsContainerElementBean source, 236 Map<String, String> settings) { 237 238 boolean createNew = source.m_createNew; 239 if (settings.containsKey(CmsContainerElement.CREATE_AS_NEW)) { 240 createNew = Boolean.valueOf(settings.get(CmsContainerElement.CREATE_AS_NEW)).booleanValue(); 241 settings = new HashMap<String, String>(settings); 242 settings.remove(CmsContainerElement.CREATE_AS_NEW); 243 } 244 CmsContainerElementBean result = new CmsContainerElementBean( 245 source.m_elementId, 246 source.m_formatterId, 247 settings, 248 createNew); 249 result.m_resource = source.m_resource; 250 result.m_sitePath = source.m_sitePath; 251 result.m_inMemoryOnly = source.m_inMemoryOnly; 252 result.m_inheritanceInfo = source.m_inheritanceInfo; 253 if (result.m_inMemoryOnly) { 254 String editorHash = source.m_editorHash; 255 if (editorHash.contains(CmsADEManager.CLIENT_ID_SEPERATOR)) { 256 editorHash = editorHash.substring(0, editorHash.indexOf(CmsADEManager.CLIENT_ID_SEPERATOR)); 257 } 258 editorHash += result.getSettingsHash(); 259 result.m_editorHash = editorHash; 260 } 261 return result; 262 } 263 264 /** 265 * Creates an element bean for the given resource type.<p> 266 * <b>The represented resource will be in memory only and not in the VFS!!!.</b><p> 267 * 268 * @param cms the CMS context 269 * @param resourceType the resource type 270 * @param targetFolder the parent folder of the resource 271 * @param individualSettings the element settings as a map of name/value pairs 272 * @param isCopyModels if this element when used in models should be copied instead of reused 273 * @param locale the locale to use 274 * 275 * @return the created element bean 276 * @throws CmsException if something goes wrong creating the element 277 * @throws IllegalArgumentException if the resource type not instance of {@link org.opencms.file.types.CmsResourceTypeXmlContent} 278 */ 279 public static CmsContainerElementBean createElementForResourceType( 280 CmsObject cms, 281 I_CmsResourceType resourceType, 282 String targetFolder, 283 Map<String, String> individualSettings, 284 boolean isCopyModels, 285 Locale locale) 286 throws CmsException { 287 288 if (!(resourceType instanceof CmsResourceTypeXmlContent)) { 289 throw new IllegalArgumentException(); 290 } 291 292 byte[] content = new byte[0]; 293 String schema = ((CmsResourceTypeXmlContent)resourceType).getSchema(); 294 if (schema != null) { 295 // must set URI of OpenCms user context to parent folder of created resource, 296 // in order to allow reading of properties for default values 297 CmsObject newCms = OpenCms.initCmsObject(cms); 298 newCms.getRequestContext().setUri(targetFolder); 299 // unmarshal the content definition for the new resource 300 CmsXmlContentDefinition contentDefinition = CmsXmlContentDefinition.unmarshal(cms, schema); 301 CmsXmlContent xmlContent = CmsXmlContentFactory.createDocument( 302 newCms, 303 locale, 304 OpenCms.getSystemInfo().getDefaultEncoding(), 305 contentDefinition); 306 // adding all other available locales 307 for (Locale otherLocale : OpenCms.getLocaleManager().getAvailableLocales()) { 308 if (!locale.equals(otherLocale)) { 309 xmlContent.addLocale(newCms, otherLocale); 310 } 311 } 312 content = xmlContent.marshal(); 313 } 314 @SuppressWarnings("deprecation") 315 CmsFile file = new CmsFile( 316 CmsUUID.getNullUUID(), 317 CmsUUID.getNullUUID(), 318 targetFolder + "~", 319 resourceType.getTypeId(), 320 0, 321 cms.getRequestContext().getCurrentProject().getUuid(), 322 CmsResource.STATE_NEW, 323 0, 324 cms.getRequestContext().getCurrentUser().getId(), 325 0, 326 cms.getRequestContext().getCurrentUser().getId(), 327 CmsResource.DATE_RELEASED_DEFAULT, 328 CmsResource.DATE_EXPIRED_DEFAULT, 329 1, 330 content.length, 331 0, 332 0, 333 content); 334 CmsContainerElementBean elementBean = new CmsContainerElementBean( 335 file, 336 null, 337 individualSettings, 338 true, 339 resourceType.getTypeName() + getSettingsHash(individualSettings, isCopyModels), 340 isCopyModels); 341 return elementBean; 342 } 343 344 /** 345 * Gets the hash code for the element settings.<p> 346 * 347 * @param individualSettings the individual settings 348 * @param createNew the create new flag 349 * 350 * @return the hash code for the element settings 351 */ 352 private static String getSettingsHash(Map<String, String> individualSettings, boolean createNew) { 353 354 if (!individualSettings.isEmpty() || createNew) { 355 int hash = (individualSettings.toString() + createNew).hashCode(); 356 return CmsADEManager.CLIENT_ID_SEPERATOR + hash; 357 } 358 return ""; 359 } 360 361 /** 362 * Adds a formatter setting.<p> 363 * 364 * @param containerName the container name 365 * @param formatterId the formatter id 366 */ 367 public void addFormatterSetting(String containerName, String formatterId) { 368 369 Map<String, String> newSettings = new HashMap<String, String>(m_individualSettings); 370 newSettings.put(CmsFormatterConfig.getSettingsKeyForContainer(containerName), formatterId); 371 m_individualSettings = Collections.unmodifiableMap(newSettings); 372 if (m_inMemoryOnly) { 373 String editorHash = m_editorHash; 374 if (editorHash.contains(CmsADEManager.CLIENT_ID_SEPERATOR)) { 375 editorHash = editorHash.substring(0, editorHash.indexOf(CmsADEManager.CLIENT_ID_SEPERATOR)); 376 } 377 editorHash += getSettingsHash(); 378 m_editorHash = editorHash; 379 } else { 380 m_editorHash = m_elementId.toString() + getSettingsHash(); 381 } 382 } 383 384 /** 385 * @see java.lang.Object#clone() 386 */ 387 @Override 388 public CmsContainerElementBean clone() { 389 390 return new CmsContainerElementBean( 391 m_createNew, 392 m_elementId, 393 m_formatterId, 394 m_individualSettings == null ? null : new HashMap<>(m_individualSettings), 395 m_inheritanceInfo, 396 m_inMemoryOnly, 397 m_temporaryContent, 398 m_releasedAndNotExpired, 399 m_resource, 400 m_settings == null ? null : new HashMap<>(m_settings), 401 m_sitePath); 402 } 403 404 /** 405 * Returns the ADE client editor has value.<p> 406 * 407 * @return the ADE client editor has value 408 */ 409 public String editorHash() { 410 411 if (m_editorHash == null) { 412 m_editorHash = m_elementId.toString() + getSettingsHash(); 413 } 414 return m_editorHash; 415 } 416 417 /** 418 * Ensures the element has a new element instance id.<p> 419 */ 420 public void ensureNewInstanceId() { 421 422 Map<String, String> newSettings = new HashMap<String, String>(m_individualSettings); 423 newSettings.put(CmsContainerElement.ELEMENT_INSTANCE_ID, new CmsUUID().toString()); 424 m_individualSettings = Collections.unmodifiableMap(newSettings); 425 m_editorHash = m_elementId.toString() + getSettingsHash(); 426 } 427 428 /** 429 * @see java.lang.Object#equals(java.lang.Object) 430 */ 431 @Override 432 public boolean equals(Object obj) { 433 434 if (!(obj instanceof CmsContainerElementBean)) { 435 return false; 436 } 437 return editorHash().equals(((CmsContainerElementBean)obj).editorHash()); 438 } 439 440 /** 441 * Returns the structure id of the formatter of this element.<p> 442 * 443 * @return the structure id of the formatter of this element 444 */ 445 public CmsUUID getFormatterId() { 446 447 return m_formatterId; 448 } 449 450 /** 451 * Helper method for getting a formatter key from the settings, for a particular container name. 452 * 453 * <p>First tries the setting formatterSettings#ContainerName, then formatterSettings# as a fallback. 454 * The second case can occur when dealing with elements from the user's favorite/recent list. 455 * 456 * @param containerName the container name 457 * @return the formatter key, or null 458 */ 459 public String getFormatterKey(String containerName) { 460 461 if (getIndividualSettings() == null) { 462 return null; 463 } 464 for (String name : Arrays.asList(containerName, "")) { 465 String key = CmsFormatterConfig.getSettingsKeyForContainer(name); 466 String formatter = getIndividualSettings().get(key); 467 if (formatter != null) { 468 return formatter; 469 } 470 } 471 return null; 472 } 473 474 /** 475 * Returns the structure id of the resource of this element.<p> 476 * 477 * @return the structure id of the resource of this element 478 */ 479 public CmsUUID getId() { 480 481 return m_elementId; 482 } 483 484 /** 485 * Returns the settings of this element.<p> 486 * 487 * @return the settings of this element 488 */ 489 public Map<String, String> getIndividualSettings() { 490 491 return m_individualSettings; 492 } 493 494 /** 495 * Returns the inheritance info.<p> 496 * 497 * @return the inheritance info or <code>null</code> if not available 498 */ 499 public CmsInheritanceInfo getInheritanceInfo() { 500 501 return m_inheritanceInfo; 502 } 503 504 /** 505 * Returns the element instance id.<p> 506 * 507 * @return the element instance id 508 */ 509 public String getInstanceId() { 510 511 return getIndividualSettings().get(CmsContainerElement.ELEMENT_INSTANCE_ID); 512 } 513 514 /** 515 * Returns the resource of this element.<p> 516 * 517 * It is required to call {@link #initResource(CmsObject)} before this method can be used.<p> 518 * 519 * @return the resource of this element 520 * 521 * @see #initResource(CmsObject) 522 */ 523 public CmsResource getResource() { 524 525 return m_resource; 526 } 527 528 /** 529 * Returns the element settings including default values for settings not set.<p> 530 * Will return <code>null</code> if the element bean has not been initialized with {@link #initResource(org.opencms.file.CmsObject)}.<p> 531 * 532 * @return the element settings 533 */ 534 public Map<String, String> getSettings() { 535 536 return m_settings; 537 } 538 539 /** 540 * Returns the site path of the resource of this element.<p> 541 * 542 * It is required to call {@link #initResource(CmsObject)} before this method can be used.<p> 543 * 544 * @return the site path of the resource of this element 545 * 546 * @see #initResource(CmsObject) 547 */ 548 public String getSitePath() { 549 550 return m_sitePath; 551 } 552 553 /** 554 * Returns the resource type name.<p> 555 * 556 * @return the type name 557 */ 558 public String getTypeName() { 559 560 if (getResource() != null) { 561 return OpenCms.getResourceManager().getResourceType(getResource()).getTypeName(); 562 } else { 563 return "unknown"; 564 } 565 } 566 567 /** 568 * @see java.lang.Object#hashCode() 569 */ 570 @Override 571 public int hashCode() { 572 573 return m_editorHash.hashCode(); 574 } 575 576 /** 577 * Initializes the resource and the site path of this element.<p> 578 * 579 * @param cms the CMS context 580 * 581 * @throws CmsException if something goes wrong reading the element resource 582 */ 583 public void initResource(CmsObject cms) throws CmsException { 584 585 if (m_resource == null) { 586 m_resource = cms.readResource(getId(), CmsResourceFilter.IGNORE_EXPIRATION); 587 m_releasedAndNotExpired = m_resource.isReleasedAndNotExpired(cms.getRequestContext().getRequestTime()); 588 } else if (!isInMemoryOnly()) { 589 CmsUUID id = m_resource.getStructureId(); 590 if (id == null) { 591 id = getId(); 592 } 593 // the resource object may have a wrong root path, e.g. if it was created before the resource was moved 594 if (cms.getRequestContext().getCurrentProject().isOnlineProject()) { 595 m_resource = cms.readResource(id, CmsResourceFilter.IGNORE_EXPIRATION); 596 m_releasedAndNotExpired = m_resource.isReleasedAndNotExpired(cms.getRequestContext().getRequestTime()); 597 } else { 598 if (!isTemporaryContent()) { 599 m_resource = cms.readResource(getId(), CmsResourceFilter.IGNORE_EXPIRATION); 600 } 601 m_releasedAndNotExpired = m_resource.isReleasedAndNotExpired(cms.getRequestContext().getRequestTime()); 602 } 603 } 604 if (m_settings == null) { 605 setSettings(new HashMap<String, String>(getIndividualSettings())); 606 } 607 // redo on every init call to ensure sitepath is calculated for current site 608 m_sitePath = cms.getSitePath(m_resource); 609 } 610 611 /** 612 * Initializes the element settings.<p> 613 * 614 * @param cms the CMS context 615 * @param formatterBean the formatter configuration bean 616 * @param locale the content locale 617 * @param request the current request, if available 618 * @param presets the presets for container element settings 619 */ 620 public void initSettings( 621 CmsObject cms, 622 CmsADEConfigData config, 623 I_CmsFormatterBean formatterBean, 624 Locale locale, 625 ServletRequest request, 626 Map<String, String> presets) { 627 628 Map<String, String> mergedSettings; 629 if (formatterBean == null) { 630 mergedSettings = CmsXmlContentPropertyHelper.mergeDefaults( 631 cms, 632 config, 633 m_resource, 634 getIndividualSettings(), 635 locale, 636 request); 637 } else { 638 mergedSettings = CmsXmlContentPropertyHelper.mergeDefaults( 639 cms, 640 OpenCms.getADEManager().getFormatterSettings( 641 cms, 642 config, 643 formatterBean, 644 getResource(), 645 locale, 646 request), 647 getIndividualSettings()); 648 } 649 if ((presets != null) && (presets.size() > 0)) { 650 mergedSettings.putAll(presets); 651 } 652 if (m_settings == null) { 653 setSettings(mergedSettings); 654 } else { 655 m_settings.putAll(mergedSettings); 656 } 657 } 658 659 /** 660 * Returns if the given element should be used as a copy model.<p> 661 * 662 * @return <code>true</code> if the given element should be used as a copy model 663 */ 664 public boolean isCopyModel() { 665 666 return Boolean.valueOf(getIndividualSettings().get(CmsContainerElement.USE_AS_COPY_MODEL)).booleanValue(); 667 } 668 669 /** 670 * Returns if a new element should be created replacing the given one on first edit of a container-page.<p> 671 * 672 * @return <code>true</code> if a new element should be created replacing the given one on first edit of a container-page 673 */ 674 public boolean isCreateNew() { 675 676 return m_createNew; 677 } 678 679 /** 680 * Checks if the element is uncacheable. 681 * 682 * @return true if the element is uncacheable 683 */ 684 public boolean isDoNotCache() { 685 686 return m_doNotCache; 687 } 688 689 /** 690 * Tests whether this element refers to a group container.<p> 691 * 692 * @param cms the CmsObject used for VFS operations 693 * 694 * @return <code>true</code> if the container element refers to a group container 695 * 696 * @throws CmsException if something goes wrong 697 */ 698 public boolean isGroupContainer(CmsObject cms) throws CmsException { 699 700 if (m_resource == null) { 701 initResource(cms); 702 } 703 return CmsResourceTypeXmlContainerPage.GROUP_CONTAINER_TYPE_NAME.equals( 704 OpenCms.getResourceManager().getResourceType(m_resource).getTypeName()); 705 } 706 707 /** 708 * Checks if the element is used for displaying a historical content (usually from the history dialog). 709 * 710 * @return true if the element is used for displaying a historical content 711 */ 712 public boolean isHistoryContent() { 713 714 return m_isHistory; 715 } 716 717 /** 718 * Returns whether this element refers to an inherited container element.<p> 719 * 720 * @param cms the CmsObject used for VFS operations 721 * 722 * @return <code>true</code> if the container element refers to an inherited container 723 * 724 * @throws CmsException if something goes wrong 725 */ 726 @SuppressWarnings("deprecation") 727 public boolean isInheritedContainer(CmsObject cms) throws CmsException { 728 729 if (m_resource == null) { 730 initResource(cms); 731 } 732 return OpenCms.getResourceManager().getResourceType( 733 CmsResourceTypeXmlContainerPage.INHERIT_CONTAINER_TYPE_NAME).getTypeId() == m_resource.getTypeId(); 734 } 735 736 /** 737 * Returns if the represented resource is in memory only and not persisted in the VFS.<p> 738 * 739 * @return <code>true</code> if the represented resource is in memory only and not persisted in the VFS 740 */ 741 public boolean isInMemoryOnly() { 742 743 return m_inMemoryOnly; 744 } 745 746 /** 747 * Returns if the given element is a model group.<p> 748 * 749 * @return <code>true</code> if the given element is a model group 750 */ 751 public boolean isModelGroup() { 752 753 ModelGroupState state = ModelGroupState.evaluate( 754 getIndividualSettings().get(CmsContainerElement.MODEL_GROUP_STATE)); 755 return state == ModelGroupState.isModelGroup; 756 } 757 758 /** 759 * Returns if all instances of this element should be replaced within a copy model.<p> 760 * 761 * @return <code>true</code> if all instances of this element should be replaced within a copy model 762 */ 763 public boolean isModelGroupAlwaysReplace() { 764 765 return Boolean.parseBoolean(getIndividualSettings().get(CmsContainerElement.IS_MODEL_GROUP_ALWAYS_REPLACE)); 766 } 767 768 /** 769 * Returns if the element resource is released and not expired.<p> 770 * 771 * @return <code>true</code> if the element resource is released and not expired 772 */ 773 public boolean isReleasedAndNotExpired() { 774 775 return isInMemoryOnly() || m_releasedAndNotExpired; 776 } 777 778 /** 779 * Returns if the element resource contains temporary file content.<p> 780 * 781 * @return <code>true</code> if the element resource contains temporary file content 782 */ 783 public boolean isTemporaryContent() { 784 785 return m_temporaryContent; 786 } 787 788 /** 789 * Enables / disables 'do not cache' status, which prevents the element from being cached in the session cache. 790 * 791 * @param doNotCache the new value 792 */ 793 public void setDoNotCache(boolean doNotCache) { 794 795 m_doNotCache = doNotCache; 796 } 797 798 /** 799 * Sets the formatter id.<p> 800 * 801 * @param formatterId the formatter id 802 */ 803 public void setFormatterId(CmsUUID formatterId) { 804 805 m_formatterId = formatterId; 806 } 807 808 /** 809 * Sets a historical file.<p> 810 * 811 * @param file the historical file 812 */ 813 public void setHistoryFile(CmsFile file) { 814 815 m_resource = file; 816 m_inMemoryOnly = true; 817 m_isHistory = true; 818 } 819 820 /** 821 * Sets the inheritance info for this element.<p> 822 * 823 * @param inheritanceInfo the inheritance info 824 */ 825 public void setInheritanceInfo(CmsInheritanceInfo inheritanceInfo) { 826 827 m_inheritanceInfo = inheritanceInfo; 828 } 829 830 /** 831 * Sets the element resource as a temporary file.<p> 832 * 833 * @param elementFile the temporary file 834 */ 835 public void setTemporaryFile(CmsFile elementFile) { 836 837 m_resource = elementFile; 838 m_temporaryContent = true; 839 } 840 841 /** 842 * @see java.lang.Object#toString() 843 */ 844 @Override 845 public String toString() { 846 847 return editorHash(); 848 } 849 850 /** 851 * Updates the individual settings.<p> 852 * 853 * This causes all merged settings (from defaults etc.) to be lost. 854 * 855 * @param newSettings the new settings 856 */ 857 public void updateIndividualSettings(Map<String, String> newSettings) { 858 859 m_individualSettings = Collections.unmodifiableMap(newSettings); 860 setSettings(getIndividualSettings()); 861 } 862 863 /** 864 * Gets the hash code for the element settings.<p> 865 * 866 * @return the hash code for the element settings 867 */ 868 private String getSettingsHash() { 869 870 String instanceId = getInstanceId(); 871 if (instanceId == null) { 872 throw new RuntimeException("Missing instance id"); 873 } 874 return CmsADEManager.CLIENT_ID_SEPERATOR 875 + getInstanceId() 876 + "_" 877 + getIndividualSettings().get(CmsContainerElement.SETTING_PAGE_ID); 878 } 879 880 /** 881 * Sets the settings map.<p> 882 * 883 * @param settings the settings 884 */ 885 private void setSettings(Map<String, String> settings) { 886 887 if (settings == null) { 888 m_settings = null; 889 } else { 890 m_settings = new CmsNullIgnoringConcurrentMap<String, String>(settings); 891 } 892 } 893}