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