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, 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.jsp.util; 029 030import org.opencms.ade.configuration.CmsADEConfigData; 031import org.opencms.ade.configuration.CmsADEManager; 032import org.opencms.ade.configuration.CmsFunctionReference; 033import org.opencms.ade.configuration.CmsResourceTypeConfig; 034import org.opencms.ade.configuration.plugins.CmsTemplatePlugin; 035import org.opencms.ade.configuration.plugins.CmsTemplatePluginFinder; 036import org.opencms.ade.containerpage.CmsContainerpageService; 037import org.opencms.ade.containerpage.CmsDetailOnlyContainerUtil; 038import org.opencms.ade.containerpage.CmsModelGroupHelper; 039import org.opencms.ade.containerpage.shared.CmsFormatterConfig; 040import org.opencms.ade.containerpage.shared.CmsInheritanceInfo; 041import org.opencms.ade.detailpage.CmsDetailPageInfo; 042import org.opencms.ade.detailpage.CmsDetailPageResourceHandler; 043import org.opencms.file.CmsFile; 044import org.opencms.file.CmsObject; 045import org.opencms.file.CmsProperty; 046import org.opencms.file.CmsPropertyDefinition; 047import org.opencms.file.CmsRequestContext; 048import org.opencms.file.CmsResource; 049import org.opencms.file.CmsResourceFilter; 050import org.opencms.file.CmsVfsResourceNotFoundException; 051import org.opencms.file.history.CmsHistoryResourceHandler; 052import org.opencms.file.types.CmsResourceTypeXmlContainerPage; 053import org.opencms.file.types.I_CmsResourceType; 054import org.opencms.flex.CmsFlexController; 055import org.opencms.flex.CmsFlexRequest; 056import org.opencms.gwt.shared.CmsGwtConstants; 057import org.opencms.i18n.CmsEncoder; 058import org.opencms.i18n.CmsLocaleGroupService; 059import org.opencms.i18n.CmsMessageToBundleIndex; 060import org.opencms.i18n.CmsResourceBundleLoader; 061import org.opencms.i18n.CmsVfsResourceBundle; 062import org.opencms.jsp.CmsJspBean; 063import org.opencms.jsp.CmsJspResourceWrapper; 064import org.opencms.jsp.CmsJspTagContainer; 065import org.opencms.jsp.CmsJspTagEditable; 066import org.opencms.jsp.Messages; 067import org.opencms.jsp.jsonpart.CmsJsonPartFilter; 068import org.opencms.jsp.search.config.parser.simplesearch.CmsConfigParserUtils; 069import org.opencms.loader.CmsLoaderException; 070import org.opencms.loader.CmsTemplateContextManager; 071import org.opencms.main.CmsException; 072import org.opencms.main.CmsLog; 073import org.opencms.main.CmsRuntimeException; 074import org.opencms.main.CmsSystemInfo; 075import org.opencms.main.OpenCms; 076import org.opencms.main.OpenCmsServlet; 077import org.opencms.relations.CmsCategory; 078import org.opencms.relations.CmsCategoryService; 079import org.opencms.search.galleries.CmsGalleryNameMacroResolver; 080import org.opencms.site.CmsSite; 081import org.opencms.ui.CmsVaadinUtils; 082import org.opencms.ui.apps.A_CmsWorkplaceApp; 083import org.opencms.ui.apps.CmsEditor; 084import org.opencms.ui.apps.CmsEditorConfiguration; 085import org.opencms.ui.editors.messagebundle.CmsMessageBundleEditor; 086import org.opencms.util.CmsCollectionsGenericWrapper; 087import org.opencms.util.CmsFileUtil; 088import org.opencms.util.CmsMacroResolver; 089import org.opencms.util.CmsStringUtil; 090import org.opencms.util.CmsUUID; 091import org.opencms.workplace.galleries.CmsAjaxDownloadGallery; 092import org.opencms.workplace.galleries.CmsAjaxImageGallery; 093import org.opencms.xml.containerpage.CmsADESessionCache; 094import org.opencms.xml.containerpage.CmsContainerBean; 095import org.opencms.xml.containerpage.CmsContainerElementBean; 096import org.opencms.xml.containerpage.CmsContainerPageBean; 097import org.opencms.xml.containerpage.CmsDynamicFunctionBean; 098import org.opencms.xml.containerpage.CmsDynamicFunctionParser; 099import org.opencms.xml.containerpage.CmsFormatterConfiguration; 100import org.opencms.xml.containerpage.CmsMetaMapping; 101import org.opencms.xml.containerpage.CmsXmlContainerPage; 102import org.opencms.xml.containerpage.CmsXmlContainerPageFactory; 103import org.opencms.xml.containerpage.I_CmsFormatterBean; 104import org.opencms.xml.content.CmsXmlContent; 105import org.opencms.xml.content.CmsXmlContentFactory; 106import org.opencms.xml.content.CmsXmlContentProperty; 107import org.opencms.xml.templatemapper.CmsTemplateMapper; 108import org.opencms.xml.types.I_CmsXmlContentValue; 109 110import java.lang.reflect.Constructor; 111import java.lang.reflect.Method; 112import java.util.ArrayList; 113import java.util.Arrays; 114import java.util.Collection; 115import java.util.Collections; 116import java.util.Comparator; 117import java.util.HashMap; 118import java.util.List; 119import java.util.Locale; 120import java.util.Map; 121import java.util.ResourceBundle; 122import java.util.Set; 123import java.util.function.Predicate; 124import java.util.stream.Collectors; 125 126import javax.servlet.ServletRequest; 127import javax.servlet.http.HttpServletRequest; 128 129import org.apache.commons.collections.Transformer; 130import org.apache.commons.lang3.LocaleUtils; 131import org.apache.commons.logging.Log; 132 133import com.google.common.collect.ComparisonChain; 134import com.google.common.collect.Multimap; 135 136/** 137 * Allows convenient access to the most important OpenCms functions on a JSP page, 138 * indented to be used from a JSP with the JSTL or EL.<p> 139 * 140 * This bean is available by default in the context of an OpenCms managed JSP.<p> 141 * 142 * @since 8.0 143 */ 144public final class CmsJspStandardContextBean { 145 146 /** 147 * Container element wrapper to add some API methods.<p> 148 */ 149 public class CmsContainerElementWrapper extends CmsContainerElementBean { 150 151 /** Cache for the wrapped element parent. */ 152 private CmsContainerElementWrapper m_parent; 153 154 /** Cache for the wrapped element type name. */ 155 private String m_resourceTypeName; 156 157 /** The wrapped element instance. */ 158 private CmsContainerElementBean m_wrappedElement; 159 160 /** Cache for the wrapped element settings. */ 161 private Map<String, CmsJspElementSettingValueWrapper> m_wrappedSettings; 162 163 /** 164 * Constructor.<p> 165 * 166 * @param element the element to wrap 167 */ 168 protected CmsContainerElementWrapper(CmsContainerElementBean element) { 169 170 m_wrappedElement = element; 171 172 } 173 174 /** 175 * @see org.opencms.xml.containerpage.CmsContainerElementBean#clone() 176 */ 177 @Override 178 public CmsContainerElementBean clone() { 179 180 return m_wrappedElement.clone(); 181 } 182 183 /** 184 * @see org.opencms.xml.containerpage.CmsContainerElementBean#editorHash() 185 */ 186 @Override 187 public String editorHash() { 188 189 return m_wrappedElement.editorHash(); 190 } 191 192 /** 193 * @see org.opencms.xml.containerpage.CmsContainerElementBean#equals(java.lang.Object) 194 */ 195 @Override 196 public boolean equals(Object obj) { 197 198 return m_wrappedElement.equals(obj); 199 } 200 201 /** 202 * @see org.opencms.xml.containerpage.CmsContainerElementBean#getFormatterId() 203 */ 204 @Override 205 public CmsUUID getFormatterId() { 206 207 return m_wrappedElement.getFormatterId(); 208 } 209 210 /** 211 * @see org.opencms.xml.containerpage.CmsContainerElementBean#getId() 212 */ 213 @Override 214 public CmsUUID getId() { 215 216 return m_wrappedElement.getId(); 217 } 218 219 /** 220 * @see org.opencms.xml.containerpage.CmsContainerElementBean#getIndividualSettings() 221 */ 222 @Override 223 public Map<String, String> getIndividualSettings() { 224 225 return m_wrappedElement.getIndividualSettings(); 226 } 227 228 /** 229 * @see org.opencms.xml.containerpage.CmsContainerElementBean#getInheritanceInfo() 230 */ 231 @Override 232 public CmsInheritanceInfo getInheritanceInfo() { 233 234 return m_wrappedElement.getInheritanceInfo(); 235 } 236 237 /** 238 * @see org.opencms.xml.containerpage.CmsContainerElementBean#getInstanceId() 239 */ 240 @Override 241 public String getInstanceId() { 242 243 return m_wrappedElement.getInstanceId(); 244 } 245 246 /** 247 * Returns the parent element if present.<p> 248 * 249 * @return the parent element or <code>null</code> if not available 250 */ 251 public CmsContainerElementWrapper getParent() { 252 253 if (m_parent == null) { 254 CmsContainerElementBean parent = getParentElement(m_wrappedElement); 255 m_parent = (parent != null) ? new CmsContainerElementWrapper(getParentElement(m_wrappedElement)) : null; 256 } 257 return m_parent; 258 } 259 260 /** 261 * @see org.opencms.xml.containerpage.CmsContainerElementBean#getResource() 262 */ 263 @Override 264 public CmsResource getResource() { 265 266 return m_wrappedElement.getResource(); 267 } 268 269 /** 270 * Returns the resource type name of the element resource.<p> 271 * 272 * @return the resource type name 273 */ 274 public String getResourceTypeName() { 275 276 if (m_resourceTypeName == null) { 277 m_resourceTypeName = ""; 278 try { 279 m_resourceTypeName = OpenCms.getResourceManager().getResourceType( 280 m_wrappedElement.getResource()).getTypeName(); 281 } catch (Exception e) { 282 CmsJspStandardContextBean.LOG.error(e.getLocalizedMessage(), e); 283 } 284 } 285 return m_resourceTypeName; 286 } 287 288 /** 289 * Returns a lazy initialized setting map.<p> 290 * 291 * The values returned in the map are instances of {@link A_CmsJspValueWrapper}. 292 * 293 * @return the wrapped settings 294 */ 295 public Map<String, CmsJspElementSettingValueWrapper> getSetting() { 296 297 if (m_wrappedSettings == null) { 298 m_wrappedSettings = CmsCollectionsGenericWrapper.createLazyMap( 299 new SettingsTransformer(m_wrappedElement)); 300 } 301 return m_wrappedSettings; 302 } 303 304 /** 305 * @see org.opencms.xml.containerpage.CmsContainerElementBean#getSettings() 306 */ 307 @Override 308 public Map<String, String> getSettings() { 309 310 return m_wrappedElement.getSettings(); 311 } 312 313 /** 314 * @see org.opencms.xml.containerpage.CmsContainerElementBean#getSitePath() 315 */ 316 @Override 317 public String getSitePath() { 318 319 return m_wrappedElement.getSitePath(); 320 } 321 322 /** 323 * @see org.opencms.xml.containerpage.CmsContainerElementBean#hashCode() 324 */ 325 @Override 326 public int hashCode() { 327 328 return m_wrappedElement.hashCode(); 329 } 330 331 /** 332 * @see org.opencms.xml.containerpage.CmsContainerElementBean#initResource(org.opencms.file.CmsObject) 333 */ 334 @Override 335 public void initResource(CmsObject cms) throws CmsException { 336 337 m_wrappedElement.initResource(cms); 338 } 339 340 /** 341 * @see org.opencms.xml.containerpage.CmsContainerElementBean#initSettings(org.opencms.file.CmsObject, org.opencms.ade.configuration.CmsADEConfigData, org.opencms.xml.containerpage.I_CmsFormatterBean, java.util.Locale, javax.servlet.ServletRequest, java.util.Map) 342 */ 343 @Override 344 public void initSettings( 345 CmsObject cms, 346 CmsADEConfigData config, 347 I_CmsFormatterBean formatterBean, 348 Locale locale, 349 ServletRequest request, 350 Map<String, String> settingPresets) { 351 352 m_wrappedElement.initSettings(cms, config, formatterBean, locale, request, settingPresets); 353 } 354 355 /** 356 * @see org.opencms.xml.containerpage.CmsContainerElementBean#isCreateNew() 357 */ 358 @Override 359 public boolean isCreateNew() { 360 361 return m_wrappedElement.isCreateNew(); 362 } 363 364 /** 365 * @see org.opencms.xml.containerpage.CmsContainerElementBean#isGroupContainer(org.opencms.file.CmsObject) 366 */ 367 @Override 368 public boolean isGroupContainer(CmsObject cms) throws CmsException { 369 370 return m_wrappedElement.isGroupContainer(cms); 371 } 372 373 /** 374 * @see org.opencms.xml.containerpage.CmsContainerElementBean#isHistoryContent() 375 */ 376 @Override 377 public boolean isHistoryContent() { 378 379 return m_wrappedElement.isHistoryContent(); 380 } 381 382 /** 383 * @see org.opencms.xml.containerpage.CmsContainerElementBean#isInheritedContainer(org.opencms.file.CmsObject) 384 */ 385 @Override 386 public boolean isInheritedContainer(CmsObject cms) throws CmsException { 387 388 return m_wrappedElement.isInheritedContainer(cms); 389 } 390 391 /** 392 * @see org.opencms.xml.containerpage.CmsContainerElementBean#isInMemoryOnly() 393 */ 394 @Override 395 public boolean isInMemoryOnly() { 396 397 return m_wrappedElement.isInMemoryOnly(); 398 } 399 400 /** 401 * @see org.opencms.xml.containerpage.CmsContainerElementBean#isReleasedAndNotExpired() 402 */ 403 @Override 404 public boolean isReleasedAndNotExpired() { 405 406 return m_wrappedElement.isReleasedAndNotExpired(); 407 } 408 409 /** 410 * @see org.opencms.xml.containerpage.CmsContainerElementBean#isTemporaryContent() 411 */ 412 @Override 413 public boolean isTemporaryContent() { 414 415 return m_wrappedElement.isTemporaryContent(); 416 } 417 418 /** 419 * @see org.opencms.xml.containerpage.CmsContainerElementBean#setFormatterId(org.opencms.util.CmsUUID) 420 */ 421 @Override 422 public void setFormatterId(CmsUUID formatterId) { 423 424 m_wrappedElement.setFormatterId(formatterId); 425 } 426 427 /** 428 * @see org.opencms.xml.containerpage.CmsContainerElementBean#setHistoryFile(org.opencms.file.CmsFile) 429 */ 430 @Override 431 public void setHistoryFile(CmsFile file) { 432 433 m_wrappedElement.setHistoryFile(file); 434 } 435 436 /** 437 * @see org.opencms.xml.containerpage.CmsContainerElementBean#setInheritanceInfo(org.opencms.ade.containerpage.shared.CmsInheritanceInfo) 438 */ 439 @Override 440 public void setInheritanceInfo(CmsInheritanceInfo inheritanceInfo) { 441 442 m_wrappedElement.setInheritanceInfo(inheritanceInfo); 443 } 444 445 /** 446 * @see org.opencms.xml.containerpage.CmsContainerElementBean#setTemporaryFile(org.opencms.file.CmsFile) 447 */ 448 @Override 449 public void setTemporaryFile(CmsFile elementFile) { 450 451 m_wrappedElement.setTemporaryFile(elementFile); 452 } 453 454 /** 455 * @see org.opencms.xml.containerpage.CmsContainerElementBean#toString() 456 */ 457 @Override 458 public String toString() { 459 460 return m_wrappedElement.toString(); 461 } 462 } 463 464 /** 465 * Provides a lazy initialized Map that provides the detail page link as a value when given the name of a 466 * (named) dynamic function or resource type as a key.<p> 467 */ 468 public class CmsDetailLookupTransformer implements Transformer { 469 470 /** The selected prefix. */ 471 private String m_prefix; 472 473 /** 474 * Constructor with a prefix.<p> 475 * 476 * The prefix is used to distinguish between type detail pages and function detail pages.<p> 477 * 478 * @param prefix the prefix to use 479 */ 480 public CmsDetailLookupTransformer(String prefix) { 481 482 m_prefix = prefix; 483 } 484 485 /** 486 * @see org.apache.commons.collections.Transformer#transform(java.lang.Object) 487 */ 488 @Override 489 public Object transform(Object input) { 490 491 String prefix = m_prefix; 492 CmsObject cms = m_cms; 493 String inputStr = String.valueOf(input); 494 495 return getFunctionDetailLink(cms, prefix, inputStr, false); 496 } 497 498 } 499 500 /** 501 * The element setting transformer.<p> 502 */ 503 public class SettingsTransformer implements Transformer { 504 505 /** The element formatter config. */ 506 private I_CmsFormatterBean m_formatter; 507 508 /** The configured formatter settings. */ 509 private Map<String, CmsXmlContentProperty> m_formatterSettingsConfig; 510 511 /** The element. */ 512 private CmsContainerElementBean m_transformElement; 513 514 /** 515 * Constructor.<p> 516 * 517 * @param element the element 518 */ 519 SettingsTransformer(CmsContainerElementBean element) { 520 521 m_transformElement = element; 522 m_formatter = getElementFormatter(element); 523 } 524 525 /** 526 * @see org.apache.commons.collections.Transformer#transform(java.lang.Object) 527 */ 528 @Override 529 public Object transform(Object settingName) { 530 531 boolean exists; 532 if (m_formatter != null) { 533 if (m_formatterSettingsConfig == null) { 534 m_formatterSettingsConfig = OpenCms.getADEManager().getFormatterSettings( 535 m_cms, 536 m_config, 537 m_formatter, 538 m_transformElement.getResource(), 539 getLocale(), 540 m_request); 541 } 542 exists = m_formatterSettingsConfig.get(settingName) != null; 543 } else { 544 exists = m_transformElement.getSettings().get(settingName) != null; 545 } 546 return new CmsJspElementSettingValueWrapper( 547 CmsJspStandardContextBean.this, 548 m_transformElement.getSettings().get(settingName), 549 exists); 550 } 551 } 552 553 /** 554 * Bean containing a template name and URI.<p> 555 */ 556 public static class TemplateBean { 557 558 /** True if the template context was manually selected. */ 559 private boolean m_forced; 560 561 /** The template name. */ 562 private String m_name; 563 564 /** The template resource. */ 565 private CmsResource m_resource; 566 567 /** The template uri, if no resource is set. */ 568 private String m_uri; 569 570 /** 571 * Creates a new instance.<p> 572 * 573 * @param name the template name 574 * @param resource the template resource 575 */ 576 public TemplateBean(String name, CmsResource resource) { 577 578 m_resource = resource; 579 m_name = name; 580 } 581 582 /** 583 * Creates a new instance with an URI instead of a resoure.<p> 584 * 585 * @param name the template name 586 * @param uri the template uri 587 */ 588 public TemplateBean(String name, String uri) { 589 590 m_name = name; 591 m_uri = uri; 592 } 593 594 /** 595 * Gets the template name.<p> 596 * 597 * @return the template name 598 */ 599 public String getName() { 600 601 return m_name; 602 } 603 604 /** 605 * Gets the template resource.<p> 606 * 607 * @return the template resource 608 */ 609 public CmsResource getResource() { 610 611 return m_resource; 612 } 613 614 /** 615 * Gets the template uri.<p> 616 * 617 * @return the template URI. 618 */ 619 public String getUri() { 620 621 if (m_resource != null) { 622 return m_resource.getRootPath(); 623 } else { 624 return m_uri; 625 } 626 } 627 628 /** 629 * Returns true if the template context was manually selected.<p> 630 * 631 * @return true if the template context was manually selected 632 */ 633 public boolean isForced() { 634 635 return m_forced; 636 } 637 638 /** 639 * Sets the 'forced' flag to a new value.<p> 640 * 641 * @param forced the new value 642 */ 643 public void setForced(boolean forced) { 644 645 m_forced = forced; 646 } 647 648 } 649 650 /** 651 * The meta mappings transformer.<p> 652 */ 653 class MetaLookupTranformer implements Transformer { 654 655 /** 656 * @see org.apache.commons.collections.Transformer#transform(java.lang.Object) 657 */ 658 public Object transform(Object arg0) { 659 660 String result = null; 661 if ((m_metaMappings != null) && m_metaMappings.containsKey(arg0)) { 662 MetaMapping mapping = m_metaMappings.get(arg0); 663 CmsGalleryNameMacroResolver resolver = null; 664 try { 665 CmsResourceFilter filter = getIsEditMode() 666 ? CmsResourceFilter.IGNORE_EXPIRATION 667 : CmsResourceFilter.DEFAULT; 668 CmsResource res = m_cms.readResource(mapping.m_contentId, filter); 669 CmsXmlContent content = CmsXmlContentFactory.unmarshal(m_cms, res, m_request); 670 resolver = new CmsGalleryNameMacroResolver(m_cms, content, getLocale()); 671 if (content.hasLocale(getLocale())) { 672 I_CmsXmlContentValue val = content.getValue(mapping.m_elementXPath, getLocale()); 673 if (val != null) { 674 result = val.getStringValue(m_cms); 675 } 676 } 677 678 } catch (CmsException e) { 679 LOG.error(e.getLocalizedMessage(), e); 680 } 681 if (result == null) { 682 result = mapping.m_defaultValue; 683 } 684 if ((resolver != null) && (result != null)) { 685 result = resolver.resolveMacros(result); 686 } 687 } 688 return result; 689 } 690 691 } 692 693 /** The meta mapping data. */ 694 class MetaMapping { 695 696 /** The mapping content structure id. */ 697 CmsUUID m_contentId; 698 699 /** The default value. */ 700 String m_defaultValue; 701 702 /** The mapping value xpath. */ 703 String m_elementXPath; 704 705 /** The mapping key. */ 706 String m_key; 707 708 /** The mapping order. */ 709 int m_order; 710 } 711 712 /** The attribute name of the cms object.*/ 713 public static final String ATTRIBUTE_CMS_OBJECT = "__cmsObject"; 714 715 /** The attribute name of the standard JSP context bean. */ 716 public static final String ATTRIBUTE_NAME = "cms"; 717 718 /** The logger instance for this class. */ 719 protected static final Log LOG = CmsLog.getLog(CmsJspStandardContextBean.class); 720 721 /** OpenCms user context. */ 722 protected CmsObject m_cms; 723 724 /** The sitemap configuration. */ 725 protected CmsADEConfigData m_config; 726 727 /** The meta mapping configuration. */ 728 Map<String, MetaMapping> m_metaMappings; 729 730 /** The current request. */ 731 ServletRequest m_request; 732 733 /** Lazily initialized map from a category path to all sub-categories of that category. */ 734 private Map<String, CmsJspCategoryAccessBean> m_allSubCategories; 735 736 /** Lazily initialized nested map for reading either attributes or properties (first key: file name, second key: attribute / property name). */ 737 private Map<String, Map<String, CmsJspObjectValueWrapper>> m_attributesOrProperties; 738 739 /** Lazily initialized map from a category path to the path's category object. */ 740 private Map<String, CmsCategory> m_categories; 741 742 /** The container the currently rendered element is part of. */ 743 private CmsContainerBean m_container; 744 745 /** The current detail content resource if available. */ 746 private CmsResource m_detailContentResource; 747 748 /** The detail function page. */ 749 private CmsResource m_detailFunctionPage; 750 751 /** The detail only page references containers that are only displayed in detail view. */ 752 private CmsContainerPageBean m_detailOnlyPage; 753 754 /** Flag to indicate if element was just edited. */ 755 private boolean m_edited; 756 757 /** The currently rendered element. */ 758 private CmsContainerElementBean m_element; 759 760 /** The elements of the current page. */ 761 private Map<String, CmsContainerElementBean> m_elementInstances; 762 763 /** Flag to force edit mode to be disabled. */ 764 private boolean m_forceDisableEditMode; 765 766 /** The lazy initialized map which allows access to the dynamic function beans. */ 767 private Map<String, CmsDynamicFunctionBeanWrapper> m_function; 768 769 /** The lazy initialized map for the function detail pages. */ 770 private Map<String, String> m_functionDetailPage; 771 772 /** The lazy initialized map for the function detail pages. */ 773 private Map<String, String> m_functionDetailPageExact; 774 775 /** Indicates if in drag mode. */ 776 private boolean m_isDragMode; 777 778 /** Stores the edit mode info. */ 779 private Boolean m_isEditMode; 780 781 /** Lazily initialized map from the locale to the localized title property. */ 782 private Map<String, String> m_localeTitles; 783 784 /** The currently displayed container page. */ 785 private CmsContainerPageBean m_page; 786 787 /** The current container page resource, lazy initialized. */ 788 private CmsJspResourceWrapper m_pageResource; 789 790 /** The parent containers to the given element instance ids. */ 791 private Map<String, CmsContainerBean> m_parentContainers; 792 793 /** Lazily initialized map from a category path to all categories on that path. */ 794 private Map<String, List<CmsCategory>> m_pathCategories; 795 796 /** Lazily initialized map from the root path of a resource to all categories assigned to the resource. */ 797 private Map<String, CmsJspCategoryAccessBean> m_resourceCategories; 798 799 /** Map from root paths to site relative paths. */ 800 private Map<String, String> m_sitePaths; 801 802 /** The template plugins. */ 803 private Map<String, List<CmsTemplatePluginWrapper>> m_templatePlugins; 804 805 /** The lazy initialized map for the detail pages. */ 806 private Map<String, String> m_typeDetailPage; 807 808 /** The VFS content access bean. */ 809 private CmsJspVfsAccessBean m_vfsBean; 810 811 /** 812 * Creates an empty instance.<p> 813 */ 814 private CmsJspStandardContextBean() { 815 816 } 817 818 /** 819 * Creates a new standard JSP context bean. 820 * 821 * @param req the current servlet request 822 */ 823 private CmsJspStandardContextBean(ServletRequest req) { 824 825 this(); 826 CmsFlexController controller = CmsFlexController.getController(req); 827 m_request = req; 828 CmsObject cms; 829 if (controller != null) { 830 cms = controller.getCmsObject(); 831 } else { 832 cms = (CmsObject)req.getAttribute(ATTRIBUTE_CMS_OBJECT); 833 } 834 if (cms == null) { 835 // cms object unavailable - this request was not initialized properly 836 throw new CmsRuntimeException( 837 Messages.get().container(Messages.ERR_MISSING_CMS_CONTROLLER_1, CmsJspBean.class.getName())); 838 } 839 updateCmsObject(cms); 840 m_detailContentResource = CmsDetailPageResourceHandler.getDetailResource(req); 841 m_detailFunctionPage = CmsDetailPageResourceHandler.getDetailFunctionPage(req); 842 } 843 844 /** 845 * Gets the link to a function detail page. 846 * 847 * @param cms the CMS context 848 * @param prefix the function detail prefix 849 * @param functionName the function name 850 * @param fullLink true if links should be generated with server prefix 851 * 852 * @return the link 853 */ 854 public static String getFunctionDetailLink(CmsObject cms, String prefix, String functionName, boolean fullLink) { 855 856 String type = prefix + functionName; 857 858 CmsADEConfigData config = OpenCms.getADEManager().lookupConfiguration( 859 cms, 860 cms.addSiteRoot(cms.getRequestContext().getUri())); 861 List<CmsDetailPageInfo> detailPages = config.getDetailPagesForType(type); 862 CmsDetailPageInfo detailPage = null; 863 if ((detailPages == null) || (detailPages.size() == 0)) { 864 detailPage = config.getDefaultDetailPage(); 865 } else { 866 detailPage = detailPages.get(0); 867 } 868 if (detailPage == null) { 869 return "[No detail page configured for type =" + type + "=]"; 870 } 871 872 CmsUUID id = detailPage.getId(); 873 try { 874 CmsResource r = cms.readResource(id); 875 boolean originalForceAbsoluteLinks = cms.getRequestContext().isForceAbsoluteLinks(); 876 try { 877 cms.getRequestContext().setForceAbsoluteLinks(fullLink || originalForceAbsoluteLinks); 878 String link = OpenCms.getLinkManager().substituteLink(cms, r); 879 return link; 880 } finally { 881 cms.getRequestContext().setForceAbsoluteLinks(originalForceAbsoluteLinks); 882 } 883 } catch (CmsException e) { 884 LOG.warn(e.getLocalizedMessage(), e); 885 return "[Error reading detail page for type =" + type + "=]"; 886 } 887 } 888 889 /** 890 * Gets the link to a function detail page. 891 * 892 * <p>This just returns null if no function detail page is defined, it does not use the default detail page as a fallback. 893 * 894 * @param cms the CMS context 895 * @param functionName the function name 896 * 897 * @return the link 898 */ 899 public static String getFunctionDetailLinkExact(CmsObject cms, String functionName) { 900 901 String type = CmsDetailPageInfo.FUNCTION_PREFIX + functionName; 902 903 CmsADEConfigData config = OpenCms.getADEManager().lookupConfigurationWithCache( 904 cms, 905 cms.addSiteRoot(cms.getRequestContext().getUri())); 906 List<CmsDetailPageInfo> detailPages = config.getDetailPagesForType(type); 907 908 CmsDetailPageInfo detailPage = null; 909 if ((detailPages == null) || (detailPages.size() == 0)) { 910 return null; 911 } 912 detailPage = detailPages.get(0); 913 if (detailPage.isDefaultDetailPage()) { 914 return null; 915 } 916 917 CmsUUID id = detailPage.getId(); 918 try { 919 CmsResource r = cms.readResource(id); 920 String link = OpenCms.getLinkManager().substituteLink(cms, r); 921 return link; 922 } catch (CmsException e) { 923 LOG.warn(e.getLocalizedMessage(), e); 924 return null; 925 } 926 927 } 928 929 /** 930 * Creates a new instance of the standard JSP context bean.<p> 931 * 932 * To prevent multiple creations of the bean during a request, the OpenCms request context 933 * attributes are used to cache the created VFS access utility bean.<p> 934 * 935 * @param req the current servlet request 936 * 937 * @return a new instance of the standard JSP context bean 938 */ 939 public static CmsJspStandardContextBean getInstance(ServletRequest req) { 940 941 Object attribute = req.getAttribute(ATTRIBUTE_NAME); 942 CmsJspStandardContextBean result; 943 if ((attribute != null) && (attribute instanceof CmsJspStandardContextBean)) { 944 result = (CmsJspStandardContextBean)attribute; 945 } else { 946 result = new CmsJspStandardContextBean(req); 947 req.setAttribute(ATTRIBUTE_NAME, result); 948 } 949 return result; 950 } 951 952 /** 953 * Returns a copy of this JSP context bean.<p> 954 * 955 * @return a copy of this JSP context bean 956 */ 957 public CmsJspStandardContextBean createCopy() { 958 959 CmsJspStandardContextBean result = new CmsJspStandardContextBean(); 960 result.m_container = m_container; 961 if (m_detailContentResource != null) { 962 result.m_detailContentResource = m_detailContentResource.getCopy(); 963 } 964 result.m_element = m_element; 965 result.m_forceDisableEditMode = m_forceDisableEditMode; 966 result.setPage(m_page); 967 return result; 968 } 969 970 /** 971 * Uses the default text encryption method to decrypt an encrypted string. 972 * 973 * @param text the encrypted stirng 974 * @return the decrypted string 975 */ 976 public String decrypt(String text) { 977 978 try { 979 return OpenCms.getTextEncryptions().get("default").decrypt(text); 980 } catch (Exception e) { 981 return null; 982 } 983 984 } 985 986 /** 987 * Returns a caching hash specific to the element, it's properties and the current container width.<p> 988 * 989 * @return the caching hash 990 */ 991 public String elementCachingHash() { 992 993 String result = ""; 994 if (m_element != null) { 995 result = m_element.editorHash(); 996 if (m_container != null) { 997 result += "w:" 998 + m_container.getWidth() 999 + "cName:" 1000 + m_container.getName() 1001 + "cType:" 1002 + m_container.getType(); 1003 } 1004 } 1005 return result; 1006 } 1007 1008 /** 1009 * Uses the default text encryption to encrypt an input text. 1010 * 1011 * @param text the input text 1012 * @return the encrypted text 1013 */ 1014 public String encrypt(String text) { 1015 1016 try { 1017 return OpenCms.getTextEncryptions().get("default").encrypt(text); 1018 } catch (Exception e) { 1019 return null; 1020 } 1021 } 1022 1023 /** 1024 * Checks if the resource with the given path exists. 1025 * 1026 * @param path a path 1027 * @return true if the resource exists 1028 */ 1029 public boolean exists(String path) { 1030 1031 Boolean exists = getVfs().getExists().get(path); 1032 return exists != null ? exists.booleanValue() : false; 1033 1034 } 1035 1036 /** 1037 * Returns the locales available for the currently requested URI. 1038 * 1039 * @return the locales available for the currently requested URI. 1040 */ 1041 public List<Locale> getAvailableLocales() { 1042 1043 return OpenCms.getLocaleManager().getAvailableLocales(m_cms, getRequestContext().getUri()); 1044 } 1045 1046 /** 1047 * Helper for easy instantiation and initialization of custom context beans that returns 1048 * an instance of the class specified via <code>className</code>, with the current context already set. 1049 * 1050 * @param className name of the class to instantiate. Must be a subclass of {@link A_CmsJspCustomContextBean}. 1051 * @return an instance of the provided class with the current context already set. 1052 */ 1053 public Object getBean(String className) { 1054 1055 try { 1056 Class<?> clazz = Class.forName(className); 1057 if (A_CmsJspCustomContextBean.class.isAssignableFrom(clazz)) { 1058 Constructor<?> constructor = clazz.getConstructor(); 1059 Object instance = constructor.newInstance(); 1060 Method setContextMethod = clazz.getMethod("setContext", CmsJspStandardContextBean.class); 1061 setContextMethod.invoke(instance, this); 1062 return instance; 1063 } else { 1064 throw new Exception(); 1065 } 1066 } catch (Exception e) { 1067 LOG.error(Messages.get().container(Messages.ERR_NO_CUSTOM_BEAN_1, className)); 1068 } 1069 return null; 1070 1071 } 1072 1073 /** 1074 * Finds the folder to use for binary uploads, based on the list configuration given as an argument or 1075 * the current sitemap configuration. 1076 * 1077 * @param content the list configuration content 1078 * 1079 * @return the binary upload folder 1080 */ 1081 public String getBinaryUploadFolder(CmsJspContentAccessBean content) { 1082 1083 String keyToFind = CmsADEConfigData.ATTR_BINARY_UPLOAD_TARGET; 1084 String baseValue = null; 1085 if (content != null) { 1086 for (CmsJspContentAccessValueWrapper wrapper : content.getValueList().get( 1087 CmsConfigParserUtils.N_PARAMETER)) { 1088 String paramKey = wrapper.getValue().get(CmsConfigParserUtils.N_KEY).getToString(); 1089 String paramValue = wrapper.getValue().get(CmsConfigParserUtils.N_VALUE).getToString(); 1090 if (paramKey.equals(keyToFind)) { 1091 LOG.debug("Found upload folder in configuration: " + paramValue); 1092 baseValue = paramValue; 1093 break; 1094 } 1095 } 1096 1097 if (baseValue == null) { 1098 List<CmsJspContentAccessValueWrapper> folderEntries = content.getValueList().get( 1099 CmsConfigParserUtils.N_SEARCH_FOLDER); 1100 if (folderEntries.size() == 1) { 1101 CmsResource resource = folderEntries.get(0).getToResource(); 1102 List<String> galleryTypes = Arrays.asList( 1103 CmsAjaxDownloadGallery.GALLERYTYPE_NAME, 1104 CmsAjaxImageGallery.GALLERYTYPE_NAME); 1105 if ((resource != null) && (null != findAncestor(m_cms, resource, (ancestor) -> { 1106 return galleryTypes.stream().anyMatch( 1107 type -> OpenCms.getResourceManager().matchResourceType(type, ancestor.getTypeId())); 1108 }))) { 1109 baseValue = m_cms.getSitePath(resource); 1110 LOG.debug( 1111 "Using single download gallery from search folder configuration as upload folder: " 1112 + baseValue); 1113 1114 } 1115 } 1116 } 1117 } 1118 1119 if (baseValue == null) { 1120 baseValue = m_config.getAttribute(keyToFind, null); 1121 if (baseValue != null) { 1122 LOG.debug("Found upload folder in sitemap configuration: " + baseValue); 1123 } 1124 } 1125 1126 CmsMacroResolver resolver = new CmsMacroResolver(); 1127 resolver.setCmsObject(getCmsObject()); 1128 resolver.addMacro("subsitepath", CmsFileUtil.removeTrailingSeparator(getSubSitePath())); 1129 resolver.addMacro("sitepath", "/"); 1130 1131 // if baseValue is still null, then resolveMacros will just return null 1132 String result = resolver.resolveMacros(baseValue); 1133 1134 LOG.debug("Final value for upload folder : " + result); 1135 return result; 1136 } 1137 1138 /** 1139 * Generates a link to the bundle editor to edit the provided message key. 1140 * The back link for the editor is the current uri. 1141 * 1142 * If the bundle for the key could not be found, <code>null</code> is returned. 1143 * 1144 * @param messageKey the message key to open the bundle editor for. 1145 * 1146 * @return a link to the bundle editor for editing the provided key, or <code>null</code> if the bundle for the key could not be found. 1147 */ 1148 public String getBundleEditorLink(String messageKey) { 1149 1150 return getBundleEditorLink(messageKey, null); 1151 } 1152 1153 /** 1154 * Generates a link to the bundle editor to edit the provided message key. 1155 * The back link for the editor is the current uri with the provided backLinkAnchor added as anchor.. 1156 * 1157 * If the bundle for the key could not be found, <code>null</code> is returned. 1158 * 1159 * @param messageKey the message key to open the bundle editor for. 1160 * @param backLinkAnchor the anchor id to add to the backlink to the page. If <code>null</code> no anchor is added to the backlink. 1161 * 1162 * @return a link to the bundle editor for editing the provided key, or <code>null</code> if the bundle for the key could not be found. 1163 */ 1164 public String getBundleEditorLink(String messageKey, String backLinkAnchor) { 1165 1166 return getBundleEditorLink(messageKey, backLinkAnchor, null); 1167 } 1168 1169 /** 1170 * Generates a link to the bundle editor to edit the provided message key. 1171 * The back link for the editor is the current uri with the provided backLinkAnchor added as anchor. 1172 * 1173 * If the bundle resource for the key could not be found, <code>null</code> is returned. 1174 * 1175 * @param messageKey the message key to open the bundle editor for. 1176 * @param backLinkAnchor the anchor id to add to the backlink to the page. If <code>null</code> no anchor is added to the backlink. 1177 * @param backLinkParams request parameters to add to the backlink without leading '?', e.g. "param1=a¶m2=b". 1178 * 1179 * @return a link to the bundle editor for editing the provided key, or <code>null</code> if the bundle for the key could not be found. 1180 */ 1181 public String getBundleEditorLink(String messageKey, String backLinkAnchor, String backLinkParams) { 1182 1183 return getBundleEditorLink(messageKey, backLinkAnchor, backLinkParams, null); 1184 } 1185 1186 /** 1187 * Generates a link to the bundle editor to edit the provided message key. 1188 * The back link for the editor is the current uri with the provided backLinkAnchor added as anchor. 1189 * 1190 * If the bundle resource for the key could not be found, <code>null</code> is returned. 1191 * 1192 * @param messageKey the message key to open the bundle editor for. 1193 * @param backLinkAnchor the anchor id to add to the backlink to the page. If <code>null</code> no anchor is added to the backlink. 1194 * @param backLinkParams request parameters to add to the backlink without leading '?', e.g. "param1=a¶m2=b". 1195 * @param bundleName the name of the bundle to search the key in. If <code>null</code> the bundle is detected automatically. 1196 * 1197 * @return a link to the bundle editor for editing the provided key, or <code>null</code> if the bundle for the key could not be found. 1198 */ 1199 public String getBundleEditorLink( 1200 String messageKey, 1201 String backLinkAnchor, 1202 String backLinkParams, 1203 String bundleName) { 1204 1205 if (!m_cms.getRequestContext().getCurrentProject().isOnlineProject()) { 1206 String filePath = null; 1207 if (null == bundleName) { 1208 filePath = getBundleRootPath(messageKey); 1209 } else { 1210 ResourceBundle bundle = CmsResourceBundleLoader.getBundle( 1211 bundleName, 1212 m_cms.getRequestContext().getLocale()); 1213 if (bundle instanceof CmsVfsResourceBundle) { 1214 CmsVfsResourceBundle vfsBundle = (CmsVfsResourceBundle)bundle; 1215 filePath = vfsBundle.getParameters().getBasePath(); 1216 } 1217 } 1218 try { 1219 if (null == filePath) { 1220 throw new Exception("Could not determine the VFS root path of the bundle."); 1221 } 1222 CmsUUID structureId = m_cms.readResource(filePath).getStructureId(); 1223 String backLink = OpenCms.getLinkManager().getServerLink(m_cms, m_cms.getRequestContext().getUri()); 1224 if (!((null == backLinkParams) || backLinkParams.isEmpty())) { 1225 backLink = backLink + "?" + backLinkParams; 1226 } 1227 if (!((null == backLinkAnchor) || backLinkAnchor.isEmpty())) { 1228 backLink = backLink + "#" + backLinkAnchor; 1229 } 1230 String appState = CmsEditor.getEditState(structureId, false, backLink); 1231 if (null != messageKey) { 1232 appState = A_CmsWorkplaceApp.addParamToState( 1233 appState, 1234 CmsMessageBundleEditor.PARAM_KEYFILTER, 1235 messageKey); 1236 } 1237 String link = CmsVaadinUtils.getWorkplaceLink(CmsEditorConfiguration.APP_ID, appState); 1238 return link; 1239 } catch (Throwable t) { 1240 if (LOG.isWarnEnabled()) { 1241 String message = "Failed to open bundle editor for key '" 1242 + messageKey 1243 + "' and bundle with name '" 1244 + bundleName 1245 + "'."; 1246 if (LOG.isDebugEnabled()) { 1247 LOG.debug(message, t); 1248 } else { 1249 LOG.warn(message); 1250 } 1251 } 1252 } 1253 } 1254 return null; 1255 } 1256 1257 /** 1258 * Gets the root path for the VFS-based message bundle containing the given message key. 1259 * 1260 * <p>If no VFS-based message bundle contains the given key, null is returned. If multiple message bundles contain it, 1261 * one of them is arbitrarily chosen (but a warning is logged). 1262 * 1263 * <p>Note: This uses the online (published) state of message bundles, so if you have unpublished bundle changes, they will not be reflected in 1264 * the result. 1265 * 1266 * @param messageKey the message key 1267 * @return the root path of the bundle containing the message key 1268 */ 1269 public String getBundleRootPath(String messageKey) { 1270 1271 CmsObject cms = getCmsObject(); 1272 try { 1273 CmsMessageToBundleIndex bundleIndex = null; 1274 OpenCmsServlet.RequestCache context = OpenCmsServlet.getRequestCache(); 1275 if (context != null) { 1276 bundleIndex = (CmsMessageToBundleIndex)context.getAttribute( 1277 CmsMessageToBundleIndex.class.getName() + "_" + cms.getRequestContext().getLocale(), 1278 k -> { 1279 try { 1280 CmsMessageToBundleIndex result = CmsMessageToBundleIndex.read(getCmsObject()); 1281 return result; 1282 } catch (Exception e) { 1283 throw new RuntimeException(e); 1284 } 1285 }); 1286 1287 } else { 1288 bundleIndex = CmsMessageToBundleIndex.read(getCmsObject()); 1289 } 1290 return bundleIndex.getBundlePathForKey(messageKey); 1291 } catch (Exception e) { 1292 LOG.error(e.getLocalizedMessage(), e); 1293 return null; 1294 } 1295 } 1296 1297 /** 1298 * Returns the container the currently rendered element is part of.<p> 1299 * 1300 * @return the container the currently rendered element is part of 1301 */ 1302 public CmsContainerBean getContainer() { 1303 1304 return m_container; 1305 } 1306 1307 /** 1308 * Gets information about a given container type. 1309 * 1310 * @param containerType the container type 1311 * 1312 * @return the bean with the information about the container type 1313 */ 1314 public CmsContainerTypeInfoWrapper getContainerTypeInfo(String containerType) { 1315 1316 return new CmsContainerTypeInfoWrapper(this, m_cms, m_config, containerType); 1317 } 1318 1319 /** 1320 * Gets the CmsObject from the current Flex controller. 1321 * 1322 * @return the CmsObject from the current Flex controller 1323 */ 1324 public CmsObject getControllerCms() { 1325 1326 return CmsFlexController.getController(m_request).getCmsObject(); 1327 } 1328 1329 /** 1330 * Returns the current detail content, or <code>null</code> if no detail content is requested.<p> 1331 * 1332 * @return the current detail content, or <code>null</code> if no detail content is requested.<p> 1333 */ 1334 public CmsJspResourceWrapper getDetailContent() { 1335 1336 return CmsJspResourceWrapper.wrap(m_cms, m_detailContentResource); 1337 } 1338 1339 /** 1340 * Returns the structure id of the current detail content, or <code>null</code> if no detail content is requested.<p> 1341 * 1342 * @return the structure id of the current detail content, or <code>null</code> if no detail content is requested.<p> 1343 */ 1344 public CmsUUID getDetailContentId() { 1345 1346 return m_detailContentResource == null ? null : m_detailContentResource.getStructureId(); 1347 } 1348 1349 /** 1350 * Returns the detail content site path, or <code>null</code> if not available.<p> 1351 * 1352 * @return the detail content site path 1353 */ 1354 public String getDetailContentSitePath() { 1355 1356 return ((m_cms == null) || (m_detailContentResource == null)) 1357 ? null 1358 : m_cms.getSitePath(m_detailContentResource); 1359 } 1360 1361 /** 1362 * Returns the detail function page.<p> 1363 * 1364 * @return the detail function page 1365 */ 1366 public CmsJspResourceWrapper getDetailFunctionPage() { 1367 1368 return CmsJspResourceWrapper.wrap(m_cms, m_detailFunctionPage); 1369 } 1370 1371 /** 1372 * Returns the detail only page.<p> 1373 * 1374 * @return the detail only page 1375 */ 1376 public CmsContainerPageBean getDetailOnlyPage() { 1377 1378 if ((null == m_detailOnlyPage) && (null != m_detailContentResource)) { 1379 String pageRootPath = m_cms.getRequestContext().addSiteRoot(m_cms.getRequestContext().getUri()); 1380 m_detailOnlyPage = CmsDetailOnlyContainerUtil.getDetailOnlyPage(m_cms, m_request, pageRootPath, false); 1381 } 1382 return m_detailOnlyPage; 1383 } 1384 1385 /** 1386 * Returns the currently rendered element.<p> 1387 * 1388 * @return the currently rendered element 1389 */ 1390 public CmsContainerElementWrapper getElement() { 1391 1392 return m_element != null ? new CmsContainerElementWrapper(m_element) : null; 1393 } 1394 1395 /** 1396 * Returns a lazy initialized map of wrapped container elements beans by container name suffix.<p> 1397 * 1398 * So in case there is more than one container where the name end with the given suffix, 1399 * a joined list of container elements beans is returned.<p> 1400 * 1401 * @return a lazy initialized map of wrapped container elements beans by container name suffix 1402 * 1403 * @see #getElementsInContainer() 1404 */ 1405 public Map<String, List<CmsContainerElementWrapper>> getElementBeansInContainers() { 1406 1407 return CmsCollectionsGenericWrapper.createLazyMap(obj -> { 1408 if (obj instanceof String) { 1409 List<CmsContainerElementBean> containerElements = new ArrayList<>(); 1410 for (CmsContainerBean container : getPage().getContainers().values()) { 1411 if (container.getName().endsWith("-" + obj)) { 1412 for (CmsContainerElementBean element : container.getElements()) { 1413 try { 1414 element.initResource(m_cms); 1415 containerElements.add(new CmsContainerElementWrapper(element)); 1416 } catch (Exception e) { 1417 LOG.error(e.getLocalizedMessage(), e); 1418 } 1419 } 1420 } 1421 } 1422 return containerElements; 1423 } else { 1424 return null; 1425 } 1426 }); 1427 1428 } 1429 1430 /** 1431 * Returns a lazy initialized map of wrapped element resources by container name.<p> 1432 * 1433 * @return the lazy map of element resource wrappers 1434 */ 1435 public Map<String, List<CmsJspResourceWrapper>> getElementsInContainer() { 1436 1437 return CmsCollectionsGenericWrapper.createLazyMap(obj -> { 1438 if (obj instanceof String) { 1439 List<CmsJspResourceWrapper> elements = new ArrayList<>(); 1440 CmsContainerBean container = getPage().getContainers().get(obj); 1441 if (container != null) { 1442 for (CmsContainerElementBean element : container.getElements()) { 1443 try { 1444 element.initResource(m_cms); 1445 elements.add(CmsJspResourceWrapper.wrap(m_cms, element.getResource())); 1446 } catch (Exception e) { 1447 LOG.error(e.getLocalizedMessage(), e); 1448 } 1449 } 1450 } 1451 return elements; 1452 } else { 1453 return null; 1454 } 1455 }); 1456 1457 } 1458 1459 /** 1460 * Returns a lazy initialized map of wrapped element resources by container name suffix.<p> 1461 * 1462 * So in case there is more than one container where the name end with the given suffix, 1463 * a joined list of elements is returned.<p> 1464 * 1465 * @return the lazy map of element resource wrappers 1466 * 1467 * @see #getElementBeansInContainers() 1468 */ 1469 public Map<String, List<CmsJspResourceWrapper>> getElementsInContainers() { 1470 1471 return CmsCollectionsGenericWrapper.createLazyMap(obj -> { 1472 if (obj instanceof String) { 1473 List<CmsJspResourceWrapper> elements = new ArrayList<>(); 1474 for (CmsContainerBean container : getPage().getContainers().values()) { 1475 if (container.getName().endsWith("-" + obj)) { 1476 for (CmsContainerElementBean element : container.getElements()) { 1477 try { 1478 element.initResource(m_cms); 1479 elements.add(CmsJspResourceWrapper.wrap(m_cms, element.getResource())); 1480 } catch (Exception e) { 1481 LOG.error(e.getLocalizedMessage(), e); 1482 } 1483 } 1484 } 1485 } 1486 return elements; 1487 } else { 1488 return null; 1489 } 1490 }); 1491 1492 } 1493 1494 /** 1495 * Alternative method name for getReloadMarker(). 1496 * 1497 * @see org.opencms.jsp.util.CmsJspStandardContextBean#getReloadMarker() 1498 * 1499 * @return the reload marker 1500 */ 1501 public String getEnableReload() { 1502 1503 return getReloadMarker(); 1504 } 1505 1506 /** 1507 * Gets the formatter info wrapper for the given formatter key. 1508 * 1509 * @param formatterKey a formatter key 1510 * @return the formatter information for the formatter key, or null if no formatter was found 1511 */ 1512 public CmsFormatterInfoWrapper getFormatterInfo(String formatterKey) { 1513 1514 CmsObject cms = m_cms; 1515 CmsADEConfigData config = m_config; 1516 I_CmsFormatterBean formatter = config.findFormatter(formatterKey); 1517 if (formatter == null) { 1518 return null; 1519 } 1520 return new CmsFormatterInfoWrapper(cms, config, formatter); 1521 1522 } 1523 1524 /** 1525 * Gets the formatter bean for active formatters with a given container type. 1526 * 1527 * @param containerType the container type 1528 * @return the wrapped formatters 1529 */ 1530 public List<CmsFormatterInfoWrapper> getFormatterInfoForContainer(String containerType) { 1531 1532 return wrapFormatters(m_config.getActiveFormattersWithContainerType(containerType)); 1533 1534 } 1535 1536 /** 1537 * Gets the formatter beans for active formatters with a given display type. 1538 * 1539 * @param displayType the display type 1540 * @return the wrapped formatters 1541 */ 1542 public List<CmsFormatterInfoWrapper> getFormatterInfoForDisplay(String displayType) { 1543 1544 CmsADEConfigData config = m_config; 1545 return wrapFormatters(config.getActiveFormattersWithDisplayType(displayType)); 1546 } 1547 1548 /** 1549 * Returns a lazy initialized Map which allows access to the dynamic function beans using the JSP EL.<p> 1550 * 1551 * When given a key, the returned map will look up the corresponding dynamic function bean in the module configuration.<p> 1552 * 1553 * @return a lazy initialized Map which allows access to the dynamic function beans using the JSP EL 1554 */ 1555 public Map<String, CmsDynamicFunctionBeanWrapper> getFunction() { 1556 1557 if (m_function == null) { 1558 1559 Transformer transformer = new Transformer() { 1560 1561 @Override 1562 public Object transform(Object input) { 1563 1564 try { 1565 CmsDynamicFunctionBean dynamicFunction = readDynamicFunctionBean((String)input); 1566 CmsDynamicFunctionBeanWrapper wrapper = new CmsDynamicFunctionBeanWrapper( 1567 m_cms, 1568 dynamicFunction); 1569 return wrapper; 1570 1571 } catch (CmsException e) { 1572 LOG.debug(e.getLocalizedMessage(), e); 1573 return new CmsDynamicFunctionBeanWrapper(m_cms, null); 1574 } 1575 } 1576 }; 1577 m_function = CmsCollectionsGenericWrapper.createLazyMap(transformer); 1578 } 1579 return m_function; 1580 1581 } 1582 1583 /** 1584 * Deprecated method to access function detail pages using the EL.<p> 1585 * 1586 * @return a lazy initialized Map that provides the detail page link as a value when given the name of a 1587 * (named) dynamic function as a key 1588 * 1589 * @deprecated use {@link #getFunctionDetailPage()} instead 1590 */ 1591 @Deprecated 1592 public Map<String, String> getFunctionDetail() { 1593 1594 return getFunctionDetailPage(); 1595 } 1596 1597 /** 1598 * Returns a lazy initialized Map that provides the detail page link as a value when given the name of a 1599 * (named) dynamic function as a key.<p> 1600 * 1601 * The provided Map key is assumed to be a String that represents a named dynamic function.<p> 1602 * 1603 * Usage example on a JSP with the JSTL:<pre> 1604 * <a href=${cms.functionDetailPage['search']} /> 1605 * </pre> 1606 * 1607 * @return a lazy initialized Map that provides the detail page link as a value when given the name of a 1608 * (named) dynamic function as a key 1609 * 1610 * @see #getTypeDetailPage() 1611 */ 1612 public Map<String, String> getFunctionDetailPage() { 1613 1614 if (m_functionDetailPage == null) { 1615 m_functionDetailPage = CmsCollectionsGenericWrapper.createLazyMap( 1616 new CmsDetailLookupTransformer(CmsDetailPageInfo.FUNCTION_PREFIX)); 1617 } 1618 return m_functionDetailPage; 1619 } 1620 1621 /** 1622 * Returns a lazy initialized Map that provides the detail page link as a value when given the name of a 1623 * (named) dynamic function as a key.<p> 1624 * 1625 * The provided Map key is assumed to be a String that represents a named dynamic function.<p> 1626 * 1627 * Usage example on a JSP with the JSTL:<pre> 1628 * <a href=${cms.functionDetailPage['search']} /> 1629 * </pre> 1630 * 1631 * @return a lazy initialized Map that provides the detail page link as a value when given the name of a 1632 * (named) dynamic function as a key 1633 * 1634 * @see #getTypeDetailPage() 1635 */ 1636 public Map<String, String> getFunctionDetailPageExact() { 1637 1638 if (m_functionDetailPageExact == null) { 1639 m_functionDetailPageExact = CmsCollectionsGenericWrapper.createLazyMap( 1640 name -> getFunctionDetailLinkExact(m_cms, (String)name)); 1641 } 1642 return m_functionDetailPageExact; 1643 } 1644 1645 /** 1646 * Returns a lazy map which creates a wrapper object for a dynamic function format when given an XML content 1647 * as a key.<p> 1648 * 1649 * @return a lazy map for accessing function formats for a content 1650 */ 1651 public Map<CmsJspContentAccessBean, CmsDynamicFunctionFormatWrapper> getFunctionFormatFromContent() { 1652 1653 Transformer transformer = new Transformer() { 1654 1655 @Override 1656 public Object transform(Object contentAccess) { 1657 1658 CmsXmlContent content = (CmsXmlContent)(((CmsJspContentAccessBean)contentAccess).getRawContent()); 1659 CmsDynamicFunctionParser parser = new CmsDynamicFunctionParser(); 1660 CmsDynamicFunctionBean functionBean = null; 1661 try { 1662 functionBean = parser.parseFunctionBean(m_cms, content); 1663 } catch (CmsException e) { 1664 LOG.debug(e.getLocalizedMessage(), e); 1665 return new CmsDynamicFunctionFormatWrapper(m_cms, null); 1666 } 1667 String type = getContainer().getType(); 1668 String width = getContainer().getWidth(); 1669 int widthNum = -1; 1670 try { 1671 widthNum = Integer.parseInt(width); 1672 } catch (NumberFormatException e) { 1673 LOG.debug(e.getLocalizedMessage(), e); 1674 } 1675 CmsDynamicFunctionBean.Format format = functionBean.getFormatForContainer(m_cms, type, widthNum); 1676 CmsDynamicFunctionFormatWrapper wrapper = new CmsDynamicFunctionFormatWrapper(m_cms, format); 1677 return wrapper; 1678 } 1679 }; 1680 return CmsCollectionsGenericWrapper.createLazyMap(transformer); 1681 } 1682 1683 /** 1684 * Returns <code>true</code> if the current page is a detail page.<p> 1685 * 1686 * @return <code>true</code> if the current page is a detail page 1687 */ 1688 public boolean getIsDetailPage() { 1689 1690 CmsJspResourceWrapper page = getPageResource(); 1691 return OpenCms.getADEManager().isDetailPage(m_cms, page); 1692 } 1693 1694 /** 1695 * Returns <code>true</code> if the current request is direct edit enabled.<p> 1696 * 1697 * Online-, history-requests, previews and temporary files will not be editable.<p> 1698 * 1699 * @return <code>true</code> if the current request is direct edit enabled 1700 */ 1701 public boolean getIsEditMode() { 1702 1703 if (m_isEditMode == null) { 1704 m_isEditMode = Boolean.valueOf(CmsJspTagEditable.isEditableRequest(m_request)); 1705 } 1706 return m_isEditMode.booleanValue() && !m_forceDisableEditMode; 1707 } 1708 1709 /** 1710 * Returns <code>true</code> if the current request is a JSON request.<p> 1711 * 1712 * @return <code>true</code> if we are in a JSON request 1713 */ 1714 public boolean getIsJSONRequest() { 1715 1716 return CmsJsonPartFilter.isJsonRequest(m_request); 1717 } 1718 1719 /** 1720 * Returns <code>true</code> if the current project is the online project.<p> 1721 * 1722 * @return <code>true</code> if the current project is the online project 1723 */ 1724 public boolean getIsOnlineProject() { 1725 1726 return m_cms.getRequestContext().getCurrentProject().isOnlineProject(); 1727 } 1728 1729 /** 1730 * Returns true if the current request is in direct edit preview mode.<p> 1731 * 1732 * This is the case if the request is not in edit mode and in the online project.<p> 1733 * 1734 * @return <code>true</code> if the current request is in direct edit preview mode 1735 */ 1736 public boolean getIsPreviewMode() { 1737 1738 return !getIsOnlineProject() && !getIsEditMode(); 1739 } 1740 1741 /** 1742 * Returns the current locale.<p> 1743 * 1744 * @return the current locale 1745 */ 1746 public Locale getLocale() { 1747 1748 return getRequestContext().getLocale(); 1749 } 1750 1751 /** 1752 * Gets a map providing access to the locale variants of the current page.<p> 1753 * 1754 * Note that all available locales for the site / subsite are used as keys, not just the ones for which a locale 1755 * variant actually exists. 1756 * 1757 * Usage in JSPs: ${cms.localeResource['de']] 1758 * 1759 * @return the map from locale strings to locale variant resources 1760 */ 1761 public Map<String, CmsJspResourceWrapper> getLocaleResource() { 1762 1763 Map<String, CmsJspResourceWrapper> result = getPageResource().getLocaleResource(); 1764 List<Locale> locales = CmsLocaleGroupService.getPossibleLocales(m_cms, getPageResource()); 1765 for (Locale locale : locales) { 1766 if (!result.containsKey(locale.toString())) { 1767 result.put(locale.toString(), null); 1768 } 1769 } 1770 return result; 1771 } 1772 1773 /** 1774 * Gets the main locale for the current page's locale group.<p> 1775 * 1776 * @return the main locale for the current page's locale group 1777 */ 1778 public Locale getMainLocale() { 1779 1780 return getPageResource().getMainLocale(); 1781 } 1782 1783 /** 1784 * Returns the meta mappings map.<p> 1785 * 1786 * @return the meta mappings 1787 */ 1788 public Map<String, String> getMeta() { 1789 1790 initMetaMappings(); 1791 return CmsCollectionsGenericWrapper.createLazyMap(new MetaLookupTranformer()); 1792 } 1793 1794 /** 1795 * Returns the currently displayed container page.<p> 1796 * 1797 * @return the currently displayed container page 1798 */ 1799 public CmsContainerPageBean getPage() { 1800 1801 if (null == m_page) { 1802 try { 1803 initPage(); 1804 } catch (CmsException e) { 1805 if (LOG.isWarnEnabled()) { 1806 LOG.warn(e, e); 1807 } 1808 } 1809 } 1810 return m_page; 1811 } 1812 1813 /** 1814 * Returns the container page bean for the give page and locale.<p> 1815 * 1816 * @param page the container page resource as id, path or already as resource 1817 * @param locale the content locale as locale or string 1818 * 1819 * @return the container page bean 1820 */ 1821 public CmsContainerPageBean getPage(Object page, Object locale) { 1822 1823 CmsResource pageResource = null; 1824 CmsContainerPageBean result = null; 1825 if (m_cms != null) { 1826 try { 1827 pageResource = CmsJspElFunctions.convertRawResource(m_cms, page); 1828 Locale l = CmsJspElFunctions.convertLocale(locale); 1829 result = getPage(pageResource); 1830 if (result != null) { 1831 CmsADEConfigData adeConfig = OpenCms.getADEManager().lookupConfiguration( 1832 m_cms, 1833 pageResource.getRootPath()); 1834 for (CmsContainerBean container : result.getContainers().values()) { 1835 for (CmsContainerElementBean element : container.getElements()) { 1836 boolean isGroupContainer = element.isGroupContainer(m_cms); 1837 boolean isInheritedContainer = element.isInheritedContainer(m_cms); 1838 I_CmsFormatterBean formatterConfig = null; 1839 if (!isGroupContainer && !isInheritedContainer) { 1840 element.initResource(m_cms); 1841 // ensure that the formatter configuration id is added to the element settings, so it will be persisted on save 1842 formatterConfig = CmsJspTagContainer.getFormatterConfigurationForElement( 1843 m_cms, 1844 element, 1845 adeConfig, 1846 container.getName(), 1847 "", 1848 0); 1849 if (formatterConfig != null) { 1850 element.initSettings(m_cms, adeConfig, formatterConfig, l, m_request, null); 1851 } 1852 } 1853 } 1854 } 1855 } 1856 } catch (Exception e) { 1857 LOG.warn(e.getLocalizedMessage(), e); 1858 } 1859 1860 } 1861 return result; 1862 } 1863 1864 /** 1865 * Returns the current container page resource.<p> 1866 * 1867 * @return the current container page resource 1868 */ 1869 public CmsJspResourceWrapper getPageResource() { 1870 1871 try { 1872 if (m_pageResource == null) { 1873 // get the container page itself, checking the history first 1874 m_pageResource = CmsJspResourceWrapper.wrap( 1875 m_cms, 1876 (CmsResource)CmsHistoryResourceHandler.getHistoryResource(m_request)); 1877 if (m_pageResource == null) { 1878 m_pageResource = CmsJspResourceWrapper.wrap( 1879 m_cms, 1880 m_cms.readResource( 1881 m_cms.getRequestContext().getUri(), 1882 CmsResourceFilter.ignoreExpirationOffline(m_cms))); 1883 } 1884 } 1885 } catch (CmsException e) { 1886 LOG.error(e.getLocalizedMessage(), e); 1887 } 1888 return m_pageResource; 1889 } 1890 1891 /** 1892 * Returns the parent container to the current container if available.<p> 1893 * 1894 * @return the parent container 1895 */ 1896 public CmsContainerBean getParentContainer() { 1897 1898 CmsContainerBean result = null; 1899 if ((getContainer() != null) && (getContainer().getParentInstanceId() != null)) { 1900 result = m_parentContainers.get(getContainer().getParentInstanceId()); 1901 } 1902 return result; 1903 } 1904 1905 /** 1906 * Returns the instance id parent container mapping.<p> 1907 * 1908 * @return the instance id parent container mapping 1909 */ 1910 public Map<String, CmsContainerBean> getParentContainers() { 1911 1912 if (m_parentContainers == null) { 1913 initPageData(); 1914 } 1915 return Collections.unmodifiableMap(m_parentContainers); 1916 } 1917 1918 /** 1919 * Returns the parent element to the current element if available.<p> 1920 * 1921 * @return the parent element or null 1922 */ 1923 public CmsContainerElementBean getParentElement() { 1924 1925 return getParentElement(getElement()); 1926 } 1927 1928 /** 1929 * Gets the set of plugin group names. 1930 * 1931 * @return the set of plugin group names 1932 */ 1933 public Set<String> getPluginGroups() { 1934 1935 return getPlugins().keySet(); 1936 } 1937 1938 /** 1939 * Gets the map of plugins by group. 1940 * 1941 * @return the map of active plugins by group 1942 */ 1943 public Map<String, List<CmsTemplatePluginWrapper>> getPlugins() { 1944 1945 if (m_templatePlugins == null) { 1946 final Multimap<String, CmsTemplatePlugin> templatePluginsMultimap = new CmsTemplatePluginFinder( 1947 this).getTemplatePlugins(); 1948 Map<String, List<CmsTemplatePluginWrapper>> templatePlugins = new HashMap<>(); 1949 for (String key : templatePluginsMultimap.keySet()) { 1950 List<CmsTemplatePluginWrapper> wrappers = new ArrayList<>(); 1951 for (CmsTemplatePlugin plugin : templatePluginsMultimap.get(key)) { 1952 wrappers.add(new CmsTemplatePluginWrapper(m_cms, plugin)); 1953 } 1954 templatePlugins.put(key, Collections.unmodifiableList(wrappers)); 1955 } 1956 m_templatePlugins = templatePlugins; 1957 } 1958 return m_templatePlugins; 1959 } 1960 1961 /** 1962 * JSP EL accessor method for retrieving the preview formatters.<p> 1963 * 1964 * @return a lazy map for accessing preview formatters 1965 */ 1966 public Map<String, String> getPreviewFormatter() { 1967 1968 Transformer transformer = new Transformer() { 1969 1970 @Override 1971 public Object transform(Object uri) { 1972 1973 try { 1974 String rootPath = m_cms.getRequestContext().addSiteRoot((String)uri); 1975 CmsResource resource = m_cms.readResource((String)uri); 1976 CmsADEManager adeManager = OpenCms.getADEManager(); 1977 CmsADEConfigData configData = adeManager.lookupConfiguration(m_cms, rootPath); 1978 CmsFormatterConfiguration formatterConfig = configData.getFormatters(m_cms, resource); 1979 if (formatterConfig == null) { 1980 return ""; 1981 } 1982 I_CmsFormatterBean previewFormatter = formatterConfig.getPreviewFormatter(); 1983 if (previewFormatter == null) { 1984 return ""; 1985 } 1986 CmsUUID structureId = previewFormatter.getJspStructureId(); 1987 m_cms.readResource(structureId); 1988 CmsResource formatterResource = m_cms.readResource(structureId); 1989 String formatterSitePath = m_cms.getRequestContext().removeSiteRoot( 1990 formatterResource.getRootPath()); 1991 return formatterSitePath; 1992 } catch (CmsException e) { 1993 LOG.warn(e.getLocalizedMessage(), e); 1994 return ""; 1995 } 1996 } 1997 }; 1998 return CmsCollectionsGenericWrapper.createLazyMap(transformer); 1999 } 2000 2001 /** 2002 * Reads all sub-categories below the provided category. 2003 * @return The map from the provided category to it's sub-categories in a {@link CmsJspCategoryAccessBean}. 2004 */ 2005 public Map<String, CmsJspCategoryAccessBean> getReadAllSubCategories() { 2006 2007 if (null == m_allSubCategories) { 2008 m_allSubCategories = CmsCollectionsGenericWrapper.createLazyMap(new Transformer() { 2009 2010 @Override 2011 public Object transform(Object categoryPath) { 2012 2013 try { 2014 List<CmsCategory> categories = CmsCategoryService.getInstance().readCategories( 2015 m_cms, 2016 (String)categoryPath, 2017 true, 2018 m_cms.getRequestContext().getUri()); 2019 CmsJspCategoryAccessBean result = new CmsJspCategoryAccessBean( 2020 m_cms, 2021 categories, 2022 (String)categoryPath); 2023 return result; 2024 } catch (CmsException e) { 2025 LOG.warn(e.getLocalizedMessage(), e); 2026 return null; 2027 } 2028 } 2029 2030 }); 2031 } 2032 return m_allSubCategories; 2033 } 2034 2035 /** 2036 * Lazily reads the given attribute from the current sitemap or a property of the same name from the given resource. 2037 * 2038 * <p>Usage example: ${cms.readAttributeOrProperty['/index.html']['attr']} 2039 * 2040 * @return a lazy loading map for accessing attributes / properties 2041 */ 2042 public Map<String, Map<String, CmsJspObjectValueWrapper>> getReadAttributeOrProperty() { 2043 2044 if (m_attributesOrProperties == null) { 2045 m_attributesOrProperties = CmsCollectionsGenericWrapper.createLazyMap(pathObj -> { 2046 return CmsCollectionsGenericWrapper.createLazyMap(keyObj -> { 2047 2048 String path = (String)pathObj; 2049 String key = (String)keyObj; 2050 2051 CmsObject cms = getCmsObject(); 2052 String result = m_config.getAttribute(key, null); 2053 if (result == null) { 2054 try { 2055 CmsProperty prop = cms.readPropertyObject(path, key, /*search=*/true); 2056 result = prop.getValue(); 2057 } catch (CmsVfsResourceNotFoundException e) { 2058 LOG.info(e.getLocalizedMessage(), e); 2059 } catch (Exception e) { 2060 LOG.error(e.getLocalizedMessage(), e); 2061 } 2062 } 2063 return CmsJspObjectValueWrapper.createWrapper(cms, result); 2064 }); 2065 }); 2066 } 2067 return m_attributesOrProperties; 2068 } 2069 2070 /** 2071 * Reads the categories assigned to the currently requested URI. 2072 * @return the categories assigned to the currently requested URI. 2073 */ 2074 public CmsJspCategoryAccessBean getReadCategories() { 2075 2076 return getReadResourceCategories().get(getRequestContext().getRootUri()); 2077 } 2078 2079 /** 2080 * Transforms the category path of a category to the category. 2081 * @return a map from root or site path to category. 2082 */ 2083 public Map<String, CmsCategory> getReadCategory() { 2084 2085 if (null == m_categories) { 2086 m_categories = CmsCollectionsGenericWrapper.createLazyMap(new Transformer() { 2087 2088 public Object transform(Object categoryPath) { 2089 2090 try { 2091 CmsCategoryService catService = CmsCategoryService.getInstance(); 2092 return catService.localizeCategory( 2093 m_cms, 2094 catService.readCategory(m_cms, (String)categoryPath, getRequestContext().getUri()), 2095 m_cms.getRequestContext().getLocale()); 2096 } catch (CmsException e) { 2097 LOG.warn(e.getLocalizedMessage(), e); 2098 return null; 2099 } 2100 } 2101 2102 }); 2103 } 2104 return m_categories; 2105 } 2106 2107 /** 2108 * Transforms the category path to the list of all categories on that path.<p> 2109 * 2110 * Example: For path <code>"location/europe/"</code> 2111 * the list <code>[getReadCategory.get("location/"),getReadCategory.get("location/europe/")]</code> 2112 * is returned. 2113 * @return a map from a category path to list of categories on that path. 2114 */ 2115 public Map<String, List<CmsCategory>> getReadPathCategories() { 2116 2117 if (null == m_pathCategories) { 2118 m_pathCategories = CmsCollectionsGenericWrapper.createLazyMap(new Transformer() { 2119 2120 public Object transform(Object categoryPath) { 2121 2122 List<CmsCategory> result = new ArrayList<CmsCategory>(); 2123 2124 String path = (String)categoryPath; 2125 2126 if ((null == path) || (path.length() <= 1)) { 2127 return result; 2128 } 2129 2130 //cut last slash 2131 path = path.substring(0, path.length() - 1); 2132 2133 List<String> pathParts = Arrays.asList(path.split("/")); 2134 2135 String currentPath = ""; 2136 for (String part : pathParts) { 2137 currentPath += part + "/"; 2138 CmsCategory category = getReadCategory().get(currentPath); 2139 if (null != category) { 2140 result.add(category); 2141 } 2142 } 2143 return CmsCategoryService.getInstance().localizeCategories( 2144 m_cms, 2145 result, 2146 m_cms.getRequestContext().getLocale()); 2147 } 2148 2149 }); 2150 } 2151 return m_pathCategories; 2152 } 2153 2154 /** 2155 * Reads the categories assigned to a resource. 2156 * 2157 * @return map from the resource path (root path) to the assigned categories 2158 */ 2159 public Map<String, CmsJspCategoryAccessBean> getReadResourceCategories() { 2160 2161 if (null == m_resourceCategories) { 2162 m_resourceCategories = CmsCollectionsGenericWrapper.createLazyMap(new Transformer() { 2163 2164 public Object transform(Object resourceName) { 2165 2166 try { 2167 CmsResource resource = m_cms.readResource( 2168 getRequestContext().removeSiteRoot((String)resourceName)); 2169 return new CmsJspCategoryAccessBean(m_cms, resource); 2170 } catch (CmsException e) { 2171 LOG.warn(e.getLocalizedMessage(), e); 2172 return null; 2173 } 2174 } 2175 }); 2176 } 2177 return m_resourceCategories; 2178 } 2179 2180 /** 2181 * Returns a HTML comment string that will cause the container page editor to reload the page if the element or its settings 2182 * were edited.<p> 2183 * 2184 * @return the reload marker 2185 */ 2186 public String getReloadMarker() { 2187 2188 if (m_cms.getRequestContext().getCurrentProject().isOnlineProject()) { 2189 return ""; // reload marker is not needed in Online mode 2190 } else { 2191 return CmsGwtConstants.FORMATTER_RELOAD_MARKER; 2192 } 2193 } 2194 2195 /** 2196 * Gets the stored request. 2197 * 2198 * @return the stored request 2199 */ 2200 public ServletRequest getRequest() { 2201 2202 return m_request; 2203 } 2204 2205 /** 2206 * Returns the request context.<p> 2207 * 2208 * @return the request context 2209 */ 2210 public CmsRequestContext getRequestContext() { 2211 2212 return m_cms.getRequestContext(); 2213 } 2214 2215 /** 2216 * Gets information about a specific resource type for use in JSPs. 2217 * 2218 * <p>If no type with the given name exists, null is returned. 2219 * 2220 * @param typeName the type name 2221 * @return the bean representing the resource type 2222 */ 2223 public CmsResourceTypeInfoWrapper getResourceTypeInfo(String typeName) { 2224 2225 try { 2226 I_CmsResourceType type = OpenCms.getResourceManager().getResourceType(typeName); 2227 return new CmsResourceTypeInfoWrapper(this, m_cms, m_config, type); 2228 } catch (CmsLoaderException e) { 2229 LOG.info(e.getLocalizedMessage(), e); 2230 return null; 2231 } 2232 } 2233 2234 /** 2235 * Returns the current site.<p> 2236 * 2237 * @return the current site 2238 */ 2239 public CmsSite getSite() { 2240 2241 return OpenCms.getSiteManager().getSiteForSiteRoot(m_cms.getRequestContext().getSiteRoot()); 2242 } 2243 2244 /** 2245 * Gets the wrapper for the sitemap configuration. 2246 * 2247 * @return the wrapper object for the sitemap configuration 2248 */ 2249 public CmsJspSitemapConfigWrapper getSitemapConfig() { 2250 2251 return new CmsJspSitemapConfigWrapper(this); 2252 } 2253 2254 /** 2255 * Transforms root paths to site paths. 2256 * 2257 * @return lazy map from root paths to site paths. 2258 * 2259 * @see CmsRequestContext#removeSiteRoot(String) 2260 */ 2261 public Map<String, String> getSitePath() { 2262 2263 if (m_sitePaths == null) { 2264 m_sitePaths = CmsCollectionsGenericWrapper.createLazyMap(new Transformer() { 2265 2266 public Object transform(Object rootPath) { 2267 2268 if (rootPath instanceof String) { 2269 return getRequestContext().removeSiteRoot((String)rootPath); 2270 } 2271 return null; 2272 } 2273 }); 2274 } 2275 return m_sitePaths; 2276 } 2277 2278 /** 2279 * Returns the subsite path for the currently requested URI.<p> 2280 * 2281 * @return the subsite path 2282 */ 2283 public String getSubSitePath() { 2284 2285 return m_cms.getRequestContext().removeSiteRoot( 2286 OpenCms.getADEManager().getSubSiteRoot(m_cms, m_cms.getRequestContext().getRootUri())); 2287 } 2288 2289 /** 2290 * Returns the system information.<p> 2291 * 2292 * @return the system information 2293 */ 2294 public CmsSystemInfo getSystemInfo() { 2295 2296 return OpenCms.getSystemInfo(); 2297 } 2298 2299 /** 2300 * Gets a bean containing information about the current template.<p> 2301 * 2302 * @return the template information bean 2303 */ 2304 public TemplateBean getTemplate() { 2305 2306 TemplateBean templateBean = getRequestAttribute(CmsTemplateContextManager.ATTR_TEMPLATE_BEAN); 2307 if (templateBean == null) { 2308 templateBean = new TemplateBean("", ""); 2309 } 2310 return templateBean; 2311 } 2312 2313 /** 2314 * Returns the title of a page delivered from OpenCms, usually used for the <code><title></code> tag of 2315 * a HTML page.<p> 2316 * 2317 * If no title information has been found, the empty String "" is returned.<p> 2318 * 2319 * @return the title of the current page 2320 */ 2321 public String getTitle() { 2322 2323 return getLocaleSpecificTitle(null); 2324 2325 } 2326 2327 /** 2328 * Get the title and read the Title property according the provided locale. 2329 * @return The map from locales to the locale specific titles. 2330 */ 2331 public Map<String, String> getTitleLocale() { 2332 2333 if (m_localeTitles == null) { 2334 m_localeTitles = CmsCollectionsGenericWrapper.createLazyMap(new Transformer() { 2335 2336 public Object transform(Object inputLocale) { 2337 2338 Locale locale = null; 2339 if (null != inputLocale) { 2340 if (inputLocale instanceof Locale) { 2341 locale = (Locale)inputLocale; 2342 } else if (inputLocale instanceof String) { 2343 try { 2344 locale = LocaleUtils.toLocale((String)inputLocale); 2345 } catch (IllegalArgumentException | NullPointerException e) { 2346 // do nothing, just go on without locale 2347 } 2348 } 2349 } 2350 return getLocaleSpecificTitle(locale); 2351 } 2352 2353 }); 2354 } 2355 return m_localeTitles; 2356 } 2357 2358 /** 2359 * Returns a lazy initialized Map that provides the detail page link as a value when given the name of a 2360 * resource type as a key.<p> 2361 * 2362 * The provided Map key is assumed to be the name of a resource type that has a detail page configured.<p> 2363 * 2364 * Usage example on a JSP with the JSTL:<pre> 2365 * <a href=${cms.typeDetailPage['bs-blog']} /> 2366 * </pre> 2367 * 2368 * @return a lazy initialized Map that provides the detail page link as a value when given the name of a 2369 * resource type as a key 2370 * 2371 * @see #getFunctionDetailPage() 2372 */ 2373 public Map<String, String> getTypeDetailPage() { 2374 2375 if (m_typeDetailPage == null) { 2376 m_typeDetailPage = CmsCollectionsGenericWrapper.createLazyMap(new CmsDetailLookupTransformer("")); 2377 } 2378 return m_typeDetailPage; 2379 } 2380 2381 /** 2382 * Returns an initialized VFS access bean.<p> 2383 * 2384 * @return an initialized VFS access bean 2385 */ 2386 public CmsJspVfsAccessBean getVfs() { 2387 2388 if (m_vfsBean == null) { 2389 // create a new VVFS access bean 2390 m_vfsBean = CmsJspVfsAccessBean.create(m_cms); 2391 } 2392 return m_vfsBean; 2393 } 2394 2395 /** 2396 * Returns the workplace locale from the current user's settings.<p> 2397 * 2398 * @return returns the workplace locale from the current user's settings 2399 */ 2400 public Locale getWorkplaceLocale() { 2401 2402 return OpenCms.getWorkplaceManager().getWorkplaceLocale(m_cms); 2403 } 2404 2405 /** 2406 * Returns an EL access wrapper map for the given object.<p> 2407 * 2408 * If the object is a {@link CmsResource}, then a {@link CmsJspResourceWrapper} is returned. 2409 * Otherwise the object is wrapped in a {@link CmsJspObjectValueWrapper}.<p> 2410 * 2411 * If the object is already is a wrapper, it is returned unchanged.<p> 2412 * 2413 * @return an EL access wrapper map for the given object 2414 */ 2415 public Map<Object, Object> getWrap() { 2416 2417 return CmsCollectionsGenericWrapper.createLazyMap(obj -> wrap(obj)); 2418 } 2419 2420 /** 2421 * Initializes the requested container page.<p> 2422 * 2423 * @throws CmsException in case reading the requested resource fails 2424 */ 2425 public void initPage() throws CmsException { 2426 2427 if ((m_page == null) && (m_cms != null)) { 2428 String requestUri = m_cms.getRequestContext().getUri(); 2429 // get the container page itself, checking the history first 2430 CmsResource pageResource = (CmsResource)CmsHistoryResourceHandler.getHistoryResource(m_request); 2431 if (pageResource == null) { 2432 pageResource = m_cms.readResource(requestUri, CmsResourceFilter.ignoreExpirationOffline(m_cms)); 2433 } 2434 m_config = OpenCms.getADEManager().lookupConfigurationWithCache(m_cms, pageResource.getRootPath()); 2435 m_page = getPage(pageResource); 2436 m_page = CmsTemplateMapper.get(m_request).transformContainerpageBean( 2437 m_cms, 2438 m_page, 2439 pageResource.getRootPath()); 2440 2441 } 2442 } 2443 2444 /** 2445 * Returns <code>true</code in case a detail page is available for the current element.<p> 2446 * 2447 * @return <code>true</code in case a detail page is available for the current element 2448 */ 2449 public boolean isDetailPageAvailable() { 2450 2451 boolean result = false; 2452 if ((m_cms != null) 2453 && (m_element != null) 2454 && !m_element.isInMemoryOnly() 2455 && (m_element.getResource() != null)) { 2456 try { 2457 String detailPage = OpenCms.getADEManager().getDetailPageHandler().getDetailPage( 2458 m_cms, 2459 m_element.getResource().getRootPath(), 2460 m_cms.getRequestContext().getUri(), 2461 null); 2462 result = detailPage != null; 2463 } catch (Exception e) { 2464 LOG.warn(e.getLocalizedMessage(), e); 2465 } 2466 } 2467 return result; 2468 } 2469 2470 /** 2471 * Returns <code>true</code> if this is a request to a detail resource, <code>false</code> otherwise.<p> 2472 * 2473 * Same as to check if {@link #getDetailContent()} is <code>null</code>.<p> 2474 * 2475 * @return <code>true</code> if this is a request to a detail resource, <code>false</code> otherwise 2476 */ 2477 public boolean isDetailRequest() { 2478 2479 return m_detailContentResource != null; 2480 } 2481 2482 /** 2483 * Returns if the page is in drag mode.<p> 2484 * 2485 * @return if the page is in drag mode 2486 */ 2487 public boolean isDragMode() { 2488 2489 return m_isDragMode; 2490 } 2491 2492 /** 2493 * Returns the flag to indicate if in drag and drop mode.<p> 2494 * 2495 * @return <code>true</code> if in drag and drop mode 2496 */ 2497 public boolean isEdited() { 2498 2499 return m_edited; 2500 } 2501 2502 /** 2503 * Checks if the flag that forces edit mode to be disabled is set. 2504 * 2505 * @return true if the flag that disables edit mode is set 2506 */ 2507 public boolean isForceDisableEditMode() { 2508 2509 return m_forceDisableEditMode; 2510 } 2511 2512 /** 2513 * Returns if the current element is a model group.<p> 2514 * 2515 * @return <code>true</code> if the current element is a model group 2516 */ 2517 public boolean isModelGroupElement() { 2518 2519 return (m_element != null) && !m_element.isInMemoryOnly() && isModelGroupPage() && m_element.isModelGroup(); 2520 } 2521 2522 /** 2523 * Returns if the current page is used to manage model groups.<p> 2524 * 2525 * @return <code>true</code> if the current page is used to manage model groups 2526 */ 2527 public boolean isModelGroupPage() { 2528 2529 CmsResource page = getPageResource(); 2530 return (page != null) && CmsContainerpageService.isEditingModelGroups(m_cms, page); 2531 2532 } 2533 2534 /** 2535 * Gets the link wrapper for the given path. 2536 * 2537 * @param path the path 2538 * @return the link wrapper 2539 */ 2540 public CmsJspLinkWrapper link(String path) { 2541 2542 return CmsJspObjectValueWrapper.createWrapper(m_cms, path).getToLink(); 2543 2544 } 2545 2546 /** 2547 * Gets the resource wrapper for a given path or id. 2548 * 2549 * @param str a path or structure id 2550 * @return the wrapper for the resource with the given path or id 2551 */ 2552 public CmsJspResourceWrapper readResource(String str) { 2553 2554 return getVfs().getReadResource().get(str); 2555 2556 } 2557 2558 /** 2559 * Reads an XML content and returns it as a content access bean 2560 * @param str path or id 2561 * @return the content access bean for the content with the given path or id 2562 */ 2563 public CmsJspContentAccessBean readXml(String str) { 2564 2565 return getVfs().getReadXml().get(str); 2566 } 2567 2568 /** 2569 * Renders the elements of container in a container page wrapper as HTML (without a surrounding element). 2570 * 2571 * @param page the page wrapper 2572 * @param name the name or name prefix of the container 2573 * @return the rendered HTML 2574 */ 2575 public String renderContainer(CmsJspContainerPageWrapper page, String name) { 2576 2577 String result = page.renderContainer(this, name); 2578 return result; 2579 } 2580 2581 /** 2582 * Sets the container the currently rendered element is part of.<p> 2583 * 2584 * @param container the container the currently rendered element is part of 2585 */ 2586 public void setContainer(CmsContainerBean container) { 2587 2588 m_container = container; 2589 } 2590 2591 /** 2592 * Sets the detail only page.<p> 2593 * 2594 * @param detailOnlyPage the detail only page to set 2595 */ 2596 public void setDetailOnlyPage(CmsContainerPageBean detailOnlyPage) { 2597 2598 m_detailOnlyPage = detailOnlyPage; 2599 clearPageData(); 2600 } 2601 2602 /** 2603 * Sets if the page is in drag mode.<p> 2604 * 2605 * @param isDragMode if the page is in drag mode 2606 */ 2607 public void setDragMode(boolean isDragMode) { 2608 2609 m_isDragMode = isDragMode; 2610 } 2611 2612 /** 2613 * Sets the flag to indicate if in drag and drop mode.<p> 2614 * 2615 * @param edited <code>true</code> if in drag and drop mode 2616 */ 2617 public void setEdited(boolean edited) { 2618 2619 m_edited = edited; 2620 } 2621 2622 /** 2623 * In edit mode, creates a meta tag that tells the form-based content editor to use the stylesheet with the given path as a default. 2624 * 2625 * <p>Does nothing outside of edit mode. 2626 * 2627 * @param path the site path of a style sheet 2628 * @return the meta tag 2629 */ 2630 public String setEditorCssPath(String path) { 2631 2632 if (getIsEditMode()) { 2633 return "\n<meta name=\"" 2634 + CmsGwtConstants.META_EDITOR_STYLESHEET 2635 + "\" content=\"" 2636 + CmsEncoder.escapeXml(path) 2637 + "\">\n"; 2638 } else { 2639 return ""; 2640 } 2641 } 2642 2643 /** 2644 * Sets the currently rendered element.<p> 2645 * 2646 * @param element the currently rendered element to set 2647 */ 2648 public void setElement(CmsContainerElementBean element) { 2649 2650 m_element = element; 2651 } 2652 2653 /** 2654 * Enables / disables the flag that forces edit mode to be disabled. 2655 * 2656 * @param forceDisableEditMode the new value for the flag 2657 */ 2658 public void setForceDisableEditMode(boolean forceDisableEditMode) { 2659 2660 m_forceDisableEditMode = forceDisableEditMode; 2661 } 2662 2663 /** 2664 * Sets the currently displayed container page.<p> 2665 * 2666 * @param page the currently displayed container page to set 2667 */ 2668 public void setPage(CmsContainerPageBean page) { 2669 2670 m_page = page; 2671 clearPageData(); 2672 } 2673 2674 /** 2675 * Converts the given object to a resource wrapper and returns it, or returns null if the conversion fails 2676 * @param obj the object to convert 2677 * @return the resource wrapper 2678 */ 2679 public CmsJspResourceWrapper toResource(Object obj) { 2680 2681 Object wrapper = wrap(obj); 2682 try { 2683 if (obj instanceof A_CmsJspValueWrapper) { 2684 return ((A_CmsJspValueWrapper)obj).getToResource(); 2685 } else if (obj instanceof CmsJspResourceWrapper) { 2686 return ((CmsJspResourceWrapper)obj).getToResource(); 2687 } else { 2688 // in case we add another wrapper with a getToResource method that doesn't extend A_CmsJspValueWrapper 2689 return (CmsJspResourceWrapper)wrapper.getClass().getMethod("getToResource").invoke(wrapper); 2690 } 2691 } catch (Exception e) { 2692 LOG.debug(e.getLocalizedMessage(), e); 2693 return null; 2694 } 2695 } 2696 2697 /** 2698 * Updates the internally stored OpenCms user context.<p> 2699 * 2700 * @param cms the new OpenCms user context 2701 */ 2702 public void updateCmsObject(CmsObject cms) { 2703 2704 try { 2705 m_cms = OpenCms.initCmsObject(cms); 2706 } catch (CmsException e) { 2707 LOG.error(e.getLocalizedMessage(), e); 2708 m_cms = cms; 2709 } 2710 try { 2711 m_config = OpenCms.getADEManager().lookupConfigurationWithCache(cms, cms.getRequestContext().getRootUri()); 2712 } catch (Exception e) { 2713 LOG.error(e.getLocalizedMessage(), e); 2714 } 2715 } 2716 2717 /** 2718 * Updates the standard context bean from the request.<p> 2719 * 2720 * @param cmsFlexRequest the request from which to update the data 2721 */ 2722 public void updateRequestData(CmsFlexRequest cmsFlexRequest) { 2723 2724 CmsResource detailRes = CmsDetailPageResourceHandler.getDetailResource(cmsFlexRequest); 2725 m_detailContentResource = detailRes; 2726 m_request = cmsFlexRequest; 2727 } 2728 2729 /** 2730 * Gets the path of either the detail content (if this is a detail request) or the current page if it's not a detail request. 2731 * 2732 * @return the URI of the page or detail content 2733 */ 2734 public String uri() { 2735 2736 return isDetailRequest() ? getDetailContent().getSitePath() : getRequestContext().getUri(); 2737 } 2738 2739 /** 2740 * Returns an EL access wrapper map for the given object.<p> 2741 * 2742 * If the object is a {@link CmsResource}, then a {@link CmsJspResourceWrapper} is returned. 2743 * Otherwise the object is wrapped in a {@link CmsJspObjectValueWrapper}.<p> 2744 * 2745 * If the object is already is a wrapper, it is returned unchanged.<p> 2746 * 2747 * @param obj the object to wrap 2748 * @return an EL access wrapper map for the given object 2749 */ 2750 public Object wrap(Object obj) { 2751 2752 if ((obj instanceof A_CmsJspValueWrapper) || (obj instanceof CmsJspResourceWrapper)) { 2753 return obj; 2754 } else if (obj instanceof CmsResource) { 2755 return CmsJspResourceWrapper.wrap(m_cms, (CmsResource)obj); 2756 } else { 2757 return CmsJspObjectValueWrapper.createWrapper(m_cms, obj); 2758 } 2759 } 2760 2761 /** 2762 * Accessor for the CmsObject. 2763 * 2764 * @return the CmsObject 2765 */ 2766 protected CmsObject getCmsObject() { 2767 2768 return m_cms; 2769 } 2770 2771 /** 2772 * Returns the formatter configuration to the given element.<p> 2773 * 2774 * @param element the element 2775 * 2776 * @return the formatter configuration 2777 */ 2778 protected I_CmsFormatterBean getElementFormatter(CmsContainerElementBean element) { 2779 2780 if (m_elementInstances == null) { 2781 initPageData(); 2782 } 2783 I_CmsFormatterBean formatter = null; 2784 CmsContainerBean container = m_parentContainers.get(element.getInstanceId()); 2785 if (container == null) { 2786 // use the current container 2787 container = getContainer(); 2788 } 2789 if (container != null) { 2790 String containerName = container.getName(); 2791 Map<String, String> settings = element.getSettings(); 2792 if (settings != null) { 2793 String formatterConfigId = settings.get(CmsFormatterConfig.getSettingsKeyForContainer(containerName)); 2794 I_CmsFormatterBean dynamicFmt = m_config.findFormatter(formatterConfigId); 2795 if (dynamicFmt != null) { 2796 formatter = dynamicFmt; 2797 } 2798 } 2799 if (formatter == null) { 2800 try { 2801 CmsResource resource = m_cms.readResource(m_cms.getRequestContext().getUri()); 2802 2803 CmsADEConfigData config = OpenCms.getADEManager().lookupConfiguration( 2804 m_cms, 2805 resource.getRootPath()); 2806 CmsFormatterConfiguration formatters = config.getFormatters(m_cms, resource); 2807 int width = -2; 2808 try { 2809 width = Integer.parseInt(container.getWidth()); 2810 } catch (Exception e) { 2811 LOG.debug(e.getLocalizedMessage(), e); 2812 } 2813 formatter = formatters.getDefaultSchemaFormatter(container.getType(), width); 2814 } catch (CmsException e1) { 2815 if (LOG.isWarnEnabled()) { 2816 LOG.warn(e1.getLocalizedMessage(), e1); 2817 } 2818 } 2819 } 2820 } 2821 return formatter; 2822 } 2823 2824 /** 2825 * Returns the title according to the given locale. 2826 * @param locale the locale for which the title should be read. 2827 * @return the title according to the given locale 2828 */ 2829 protected String getLocaleSpecificTitle(Locale locale) { 2830 2831 String result = null; 2832 2833 try { 2834 2835 if (isDetailRequest()) { 2836 // this is a request to a detail page 2837 CmsResource res = getDetailContent(); 2838 CmsFile file = m_cms.readFile(res); 2839 CmsXmlContent content = CmsXmlContentFactory.unmarshal(m_cms, file); 2840 result = content.getHandler().getTitleMapping(m_cms, content, m_cms.getRequestContext().getLocale()); 2841 if (result == null) { 2842 // title not found, maybe no mapping OR not available in the current locale 2843 // read the title of the detail resource as fall back (may contain mapping from another locale) 2844 result = m_cms.readPropertyObject( 2845 res, 2846 CmsPropertyDefinition.PROPERTY_TITLE, 2847 false, 2848 locale).getValue(); 2849 } 2850 } 2851 if (result == null) { 2852 // read the title of the requested resource as fall back 2853 result = m_cms.readPropertyObject( 2854 m_cms.getRequestContext().getUri(), 2855 CmsPropertyDefinition.PROPERTY_TITLE, 2856 true, 2857 locale).getValue(); 2858 } 2859 } catch (CmsException e) { 2860 LOG.debug(e.getLocalizedMessage(), e); 2861 } 2862 if (CmsStringUtil.isEmptyOrWhitespaceOnly(result)) { 2863 result = ""; 2864 } 2865 2866 return result; 2867 } 2868 2869 /** 2870 * Returns the parent element if available.<p> 2871 * 2872 * @param element the element 2873 * 2874 * @return the parent element or null 2875 */ 2876 protected CmsContainerElementBean getParentElement(CmsContainerElementBean element) { 2877 2878 if (m_elementInstances == null) { 2879 initPageData(); 2880 } 2881 CmsContainerElementBean parent = null; 2882 CmsContainerBean cont = m_parentContainers.get(element.getInstanceId()); 2883 if ((cont != null) && cont.isNestedContainer()) { 2884 parent = m_elementInstances.get(cont.getParentInstanceId()); 2885 } 2886 return parent; 2887 } 2888 2889 /** 2890 * Accessor for the sitemap configuration. 2891 * 2892 * @return the sitemap configuration 2893 */ 2894 protected CmsADEConfigData getSitemapConfigInternal() { 2895 2896 return m_config; 2897 } 2898 2899 /** 2900 * Reads a dynamic function bean, given its name in the module configuration.<p> 2901 * 2902 * @param configuredName the name of the dynamic function in the module configuration 2903 * @return the dynamic function bean for the dynamic function configured under that name 2904 * 2905 * @throws CmsException if something goes wrong 2906 */ 2907 protected CmsDynamicFunctionBean readDynamicFunctionBean(String configuredName) throws CmsException { 2908 2909 CmsADEConfigData config = OpenCms.getADEManager().lookupConfiguration( 2910 m_cms, 2911 m_cms.addSiteRoot(m_cms.getRequestContext().getUri())); 2912 CmsFunctionReference functionRef = config.getFunctionReference(configuredName); 2913 if (functionRef == null) { 2914 return null; 2915 } 2916 CmsDynamicFunctionParser parser = new CmsDynamicFunctionParser(); 2917 CmsResource functionResource = m_cms.readResource(functionRef.getStructureId()); 2918 CmsDynamicFunctionBean result = parser.parseFunctionBean(m_cms, functionResource); 2919 return result; 2920 } 2921 2922 /** 2923 * Wraps a list of formatter beans for use in JSPs. 2924 * 2925 * @param formatters the formatters to wrap 2926 * @return the wrapped formatters 2927 */ 2928 protected List<CmsFormatterInfoWrapper> wrapFormatters(Collection<? extends I_CmsFormatterBean> formatters) { 2929 2930 List<I_CmsFormatterBean> formattersToSort = new ArrayList<>(formatters); 2931 List<CmsResourceTypeConfig> types = m_config.getResourceTypes(); 2932 2933 // we want to 'group' the returned formatters by resource type, which is slightly 2934 // complicated by the fact that formatters can support multiple resource types. 2935 2936 // first build a map that records the positions of the resource types configured in the sitemap configuration 2937 Map<String, Integer> typePositionsByTypeName = new HashMap<>(); 2938 for (int i = 0; i < types.size(); i++) { 2939 CmsResourceTypeConfig singleType = types.get(i); 2940 typePositionsByTypeName.put(singleType.getTypeName(), Integer.valueOf(i)); 2941 } 2942 // for each formatter, save the lowest position of any resource type it supports 2943 Map<String, Integer> lowestResourceTypePositionsByFormatterId = new HashMap<>(); 2944 for (I_CmsFormatterBean formatter : formatters) { 2945 int pos = Integer.MAX_VALUE; 2946 for (String typeName : formatter.getResourceTypeNames()) { 2947 Integer typeOrder = typePositionsByTypeName.get(typeName); 2948 if (typeOrder != null) { 2949 pos = Math.min(pos, typeOrder.intValue()); 2950 } 2951 } 2952 lowestResourceTypePositionsByFormatterId.put(formatter.getId(), Integer.valueOf(pos)); 2953 } 2954 2955 // now we can group the formatters by types using sorting, and inside the groups we sort by formatter rank 2956 Collections.sort(formattersToSort, new Comparator<I_CmsFormatterBean>() { 2957 2958 public int compare(I_CmsFormatterBean o1, I_CmsFormatterBean o2) { 2959 2960 return ComparisonChain.start().compare(getTypePosition(o1), getTypePosition(o2)).compare( 2961 o2.getRank(), 2962 o1.getRank()).result(); 2963 } 2964 2965 public int getTypePosition(I_CmsFormatterBean formatter) { 2966 2967 return lowestResourceTypePositionsByFormatterId.computeIfAbsent( 2968 formatter.getId(), 2969 id -> Integer.valueOf(Integer.MAX_VALUE)); 2970 } 2971 2972 }); 2973 return formattersToSort.stream().map( 2974 formatter -> new CmsFormatterInfoWrapper(m_cms, m_config, formatter)).collect(Collectors.toList()); 2975 2976 } 2977 2978 /** 2979 * Adds the mappings of the given formatter configuration.<p> 2980 * 2981 * @param formatterBean the formatter bean 2982 * @param elementId the element content structure id 2983 * @param resolver The macro resolver used on key and default value of the mappings 2984 * @param isDetailContent in case of a detail content 2985 */ 2986 private void addMappingsForFormatter( 2987 I_CmsFormatterBean formatterBean, 2988 CmsUUID elementId, 2989 CmsMacroResolver resolver, 2990 boolean isDetailContent) { 2991 2992 if ((formatterBean != null) && (formatterBean.getMetaMappings() != null)) { 2993 for (CmsMetaMapping map : formatterBean.getMetaMappings()) { 2994 String key = map.getKey(); 2995 key = resolver.resolveMacros(key); 2996 // the detail content mapping overrides other mappings 2997 if (isDetailContent 2998 || !m_metaMappings.containsKey(key) 2999 || (m_metaMappings.get(key).m_order <= map.getOrder())) { 3000 MetaMapping mapping = new MetaMapping(); 3001 mapping.m_key = key; 3002 mapping.m_elementXPath = map.getElement(); 3003 mapping.m_defaultValue = resolver.resolveMacros(map.getDefaultValue()); 3004 mapping.m_order = map.getOrder(); 3005 mapping.m_contentId = elementId; 3006 m_metaMappings.put(key, mapping); 3007 } 3008 } 3009 } 3010 } 3011 3012 /** 3013 * Clears the page element data.<p> 3014 */ 3015 private void clearPageData() { 3016 3017 m_elementInstances = null; 3018 m_parentContainers = null; 3019 } 3020 3021 /** 3022 * Finds the first ancestor of a resource matching a given predicate. 3023 * 3024 * @param cms the CMS context 3025 * @param resource the resource 3026 * @param predicate the predicate to test 3027 * 3028 * @return the first ancestor matching the predicate (which may possibly be the given resource itself), or null if no matching ancestor is found 3029 * @throws CmsException 3030 */ 3031 private CmsResource findAncestor(CmsObject cms, CmsResource resource, Predicate<CmsResource> predicate) { 3032 3033 try { 3034 CmsObject rootCms = OpenCms.initCmsObject(cms); 3035 rootCms.getRequestContext().setSiteRoot(""); 3036 CmsResource ancestor = resource; 3037 while (ancestor != null) { 3038 if (predicate.test(ancestor)) { 3039 return ancestor; 3040 } 3041 String parentFolder = CmsResource.getParentFolder(ancestor.getRootPath()); 3042 if (parentFolder == null) { 3043 break; 3044 } 3045 try { 3046 ancestor = rootCms.readResource(parentFolder, CmsResourceFilter.IGNORE_EXPIRATION); 3047 } catch (CmsException e) { 3048 LOG.info(e.getLocalizedMessage(), e); 3049 break; 3050 } 3051 } 3052 } catch (CmsException e) { 3053 LOG.error(e.getLocalizedMessage(), e); 3054 } 3055 return null; 3056 } 3057 3058 /** 3059 * Returns the container page bean for the give resource.<p> 3060 * 3061 * @param pageResource the resource 3062 * 3063 * @return the container page bean 3064 * 3065 * @throws CmsException in case reading the page bean fails 3066 */ 3067 private CmsContainerPageBean getPage(CmsResource pageResource) throws CmsException { 3068 3069 CmsContainerPageBean result = null; 3070 if ((pageResource != null) && CmsResourceTypeXmlContainerPage.isContainerPage(pageResource)) { 3071 CmsXmlContainerPage xmlContainerPage = CmsXmlContainerPageFactory.unmarshal(m_cms, pageResource, m_request); 3072 result = xmlContainerPage.getContainerPage(m_cms); 3073 CmsModelGroupHelper modelHelper = new CmsModelGroupHelper( 3074 m_cms, 3075 OpenCms.getADEManager().lookupConfiguration(m_cms, pageResource.getRootPath()), 3076 CmsJspTagEditable.isEditableRequest(m_request) && (m_request instanceof HttpServletRequest) 3077 ? CmsADESessionCache.getCache((HttpServletRequest)m_request, m_cms) 3078 : null, 3079 CmsContainerpageService.isEditingModelGroups(m_cms, pageResource)); 3080 result = modelHelper.readModelGroups(xmlContainerPage.getContainerPage(m_cms)); 3081 } 3082 return result; 3083 } 3084 3085 /** 3086 * Convenience method for getting a request attribute without an explicit cast.<p> 3087 * 3088 * @param name the attribute name 3089 * @return the request attribute 3090 */ 3091 @SuppressWarnings("unchecked") 3092 private <A> A getRequestAttribute(String name) { 3093 3094 Object attribute = m_request.getAttribute(name); 3095 3096 return attribute != null ? (A)attribute : null; 3097 } 3098 3099 /** 3100 * Initializes the mapping configuration.<p> 3101 */ 3102 private void initMetaMappings() { 3103 3104 if (m_metaMappings == null) { 3105 m_metaMappings = new HashMap<String, MetaMapping>(); 3106 try { 3107 initPage(); 3108 CmsMacroResolver resolver = new CmsMacroResolver(); 3109 resolver.setKeepEmptyMacros(true); 3110 resolver.setCmsObject(m_cms); 3111 resolver.setMessages(OpenCms.getWorkplaceManager().getMessages(getLocale())); 3112 CmsResourceFilter filter = getIsEditMode() 3113 ? CmsResourceFilter.IGNORE_EXPIRATION 3114 : CmsResourceFilter.DEFAULT; 3115 for (CmsContainerBean container : m_page.getContainers().values()) { 3116 for (CmsContainerElementBean element : container.getElements()) { 3117 String settingsKey = CmsFormatterConfig.getSettingsKeyForContainer(container.getName()); 3118 String formatterConfigId = element.getSettings() != null 3119 ? element.getSettings().get(settingsKey) 3120 : null; 3121 I_CmsFormatterBean formatterBean = null; 3122 formatterBean = m_config.findFormatter(formatterConfigId); 3123 if ((formatterBean != null) 3124 && formatterBean.useMetaMappingsForNormalElements() 3125 && m_cms.existsResource(element.getId(), filter)) { 3126 addMappingsForFormatter(formatterBean, element.getId(), resolver, false); 3127 } 3128 3129 } 3130 } 3131 if (getDetailContentId() != null) { 3132 try { 3133 CmsResource detailContent = m_cms.readResource( 3134 getDetailContentId(), 3135 CmsResourceFilter.ignoreExpirationOffline(m_cms)); 3136 CmsFormatterConfiguration config = OpenCms.getADEManager().lookupConfiguration( 3137 m_cms, 3138 m_cms.getRequestContext().getRootUri()).getFormatters(m_cms, detailContent); 3139 for (I_CmsFormatterBean formatter : config.getDetailFormatters()) { 3140 addMappingsForFormatter(formatter, getDetailContentId(), resolver, true); 3141 } 3142 } catch (CmsException e) { 3143 LOG.error( 3144 Messages.get().getBundle().key( 3145 Messages.ERR_READING_REQUIRED_RESOURCE_1, 3146 getDetailContentId()), 3147 e); 3148 } 3149 } 3150 } catch (Exception e) { 3151 LOG.error(e.getLocalizedMessage(), e); 3152 } 3153 } 3154 } 3155 3156 /** 3157 * Initializes the page element data.<p> 3158 */ 3159 private void initPageData() { 3160 3161 m_elementInstances = new HashMap<String, CmsContainerElementBean>(); 3162 m_parentContainers = new HashMap<String, CmsContainerBean>(); 3163 if (m_page != null) { 3164 for (CmsContainerBean container : m_page.getContainers().values()) { 3165 for (CmsContainerElementBean element : container.getElements()) { 3166 m_elementInstances.put(element.getInstanceId(), element); 3167 m_parentContainers.put(element.getInstanceId(), container); 3168 try { 3169 if (element.isGroupContainer(m_cms) || element.isInheritedContainer(m_cms)) { 3170 List<CmsContainerElementBean> children; 3171 if (element.isGroupContainer(m_cms)) { 3172 children = CmsJspTagContainer.getGroupContainerElements( 3173 m_cms, 3174 element, 3175 m_request, 3176 container.getType()); 3177 } else { 3178 children = CmsJspTagContainer.getInheritedContainerElements(m_cms, element); 3179 } 3180 for (CmsContainerElementBean childElement : children) { 3181 m_elementInstances.put(childElement.getInstanceId(), childElement); 3182 m_parentContainers.put(childElement.getInstanceId(), container); 3183 } 3184 } 3185 } catch (CmsException e) { 3186 LOG.error(e.getLocalizedMessage(), e); 3187 } 3188 } 3189 } 3190 // also add detail only data 3191 if (m_detailOnlyPage != null) { 3192 for (CmsContainerBean container : m_detailOnlyPage.getContainers().values()) { 3193 for (CmsContainerElementBean element : container.getElements()) { 3194 m_elementInstances.put(element.getInstanceId(), element); 3195 m_parentContainers.put(element.getInstanceId(), container); 3196 } 3197 } 3198 } 3199 } 3200 } 3201 3202}