001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (C) Alkacon Software (https://www.alkacon.com) 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * For further information about Alkacon Software, please see the 018 * company website: https://www.alkacon.com 019 * 020 * For further information about OpenCms, please see the 021 * project website: https://www.opencms.org 022 * 023 * You should have received a copy of the GNU Lesser General Public 024 * License along with this library; if not, write to the Free Software 025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 026 */ 027 028package org.opencms.ade.configuration; 029 030import org.opencms.ade.configuration.CmsADEConfigDataInternal.ConfigReference; 031import org.opencms.ade.configuration.CmsADEConfigDataInternal.ConfigReferenceMeta; 032import org.opencms.ade.configuration.formatters.CmsFormatterChangeSet; 033import org.opencms.ade.configuration.formatters.CmsFormatterConfigurationCache; 034import org.opencms.ade.containerpage.shared.CmsCntPageData.ElementDeleteMode; 035import org.opencms.ade.detailpage.CmsDetailPageInfo; 036import org.opencms.ade.galleries.CmsAddContentRestriction; 037import org.opencms.file.CmsFile; 038import org.opencms.file.CmsObject; 039import org.opencms.file.CmsResource; 040import org.opencms.file.CmsResourceFilter; 041import org.opencms.file.types.I_CmsResourceType; 042import org.opencms.gwt.CmsIconUtil; 043import org.opencms.i18n.CmsLocaleManager; 044import org.opencms.main.CmsException; 045import org.opencms.main.CmsLog; 046import org.opencms.main.CmsRuntimeException; 047import org.opencms.main.OpenCms; 048import org.opencms.module.CmsModule; 049import org.opencms.relations.CmsLink; 050import org.opencms.util.CmsFileUtil; 051import org.opencms.util.CmsStringUtil; 052import org.opencms.util.CmsUUID; 053import org.opencms.xml.containerpage.CmsFormatterBean; 054import org.opencms.xml.containerpage.CmsXmlDynamicFunctionHandler; 055import org.opencms.xml.containerpage.I_CmsFormatterBean; 056import org.opencms.xml.content.CmsXmlContent; 057import org.opencms.xml.content.CmsXmlContentFactory; 058import org.opencms.xml.content.CmsXmlContentProperty; 059import org.opencms.xml.content.CmsXmlContentProperty.Visibility; 060import org.opencms.xml.content.CmsXmlContentRootLocation; 061import org.opencms.xml.content.I_CmsXmlContentLocation; 062import org.opencms.xml.content.I_CmsXmlContentValueLocation; 063import org.opencms.xml.types.CmsXmlVarLinkValue; 064import org.opencms.xml.types.CmsXmlVfsFileValue; 065 066import java.util.ArrayList; 067import java.util.HashSet; 068import java.util.LinkedHashMap; 069import java.util.LinkedHashSet; 070import java.util.List; 071import java.util.Locale; 072import java.util.Map; 073import java.util.Set; 074 075import org.apache.commons.logging.Log; 076 077import com.google.common.collect.Lists; 078 079/** 080 * A class to parse ADE sitemap or module configuration files and create configuration objects from them.<p> 081 */ 082public class CmsConfigurationReader { 083 084 /** 085 * Enum describing how to deal with inherited properties. 086 */ 087 enum DiscardPropertiesMode { 088 089 /** Remove properties from parent sitemaps. */ 090 discard("true"), 091 092 /** Inherit properties from parent sitemaps. */ 093 keep("false"), 094 095 /** Remove properties from parent sitemaps, and mark properties defined in this sitemap as 'top', which moves them over the properties which are only defined in opencms-workplace.xml/opencms-modules.xml. */ 096 top("top"); 097 098 /** The value representing the mode in an actual sitemap configuration content. */ 099 private String m_stringValue; 100 101 /** 102 * Creates the enum value. 103 * 104 * @param stringValue the string value from the configuration 105 */ 106 private DiscardPropertiesMode(String stringValue) { 107 108 m_stringValue = stringValue; 109 110 } 111 112 /** 113 * Gets the string value occurring in the sitemap configuration. 114 * 115 * @return the string value 116 */ 117 public String getStringValue() { 118 119 return m_stringValue; 120 } 121 } 122 123 /** The default locale for configuration objects. */ 124 public static final Locale DEFAULT_LOCALE = CmsLocaleManager.getLocale("en"); 125 126 /** The AddContentReplacements node name. */ 127 public static final String N_ADD_CONTENT_RESTRICTION = "AddContentRestriction"; 128 129 /** Node name for added formatters. */ 130 public static final String N_ADD_FORMATTER = "AddFormatter"; 131 132 /** Node name for the nested content with the added formatters. */ 133 public static final String N_ADD_FORMATTERS = "AddFormatters"; 134 135 /** The AddPlugin node name. */ 136 public static final String N_ADD_PLUGIN = "AddPlugin"; 137 138 /** The AddPlugins node name. */ 139 public static final String N_ADD_PLUGINS = "AddPlugins"; 140 141 /** The Attribute node name. */ 142 public static final String N_ATTRIBUTE = "Attribute"; 143 144 /** Node name for the attribute editor configuration reference. */ 145 public static final String N_ATTRIBUTE_EDITOR_CONFIG = "AttributeEditorConfig"; 146 147 /** Node name for the 'Check reuse' option. */ 148 public static final String N_CHECK_REUSE = "CheckReuse"; 149 150 public static final String N_CONTENT_FOLDER = "ContentFolder"; 151 152 /** The CopyInModels node name. */ 153 public static final String N_COPY_IN_MODELS = "CopyInModels"; 154 155 /** The create content locally node name. */ 156 public static final String N_CREATE_CONTENTS_LOCALLY = "CreateContentsLocally"; 157 158 /** The default node name. */ 159 public static final String N_DEFAULT = "Default"; 160 161 /** The description node name. */ 162 public static final String N_DESCRIPTION = "Description"; 163 164 /** The detail page node name. */ 165 public static final String N_DETAIL_PAGE = "DetailPage"; 166 167 /** The detail pages disabled node name. */ 168 public static final String N_DETAIL_PAGES_DISABLED = "DetailPagesDisabled"; 169 170 /** The disabled node name. */ 171 public static final String N_DISABLED = "Disabled"; 172 173 /** The DisabledFunctionsMode node name. */ 174 public static final String N_DISABLED_FUNCTIONS_MODE = "DisabledFunctionsMode"; 175 176 /** The DisabledTypesMode node name. */ 177 public static final String N_DISABLED_TYPES_MODE = "DisabledTypesMode"; 178 179 /** The discard model pages node name. */ 180 public static final String N_DISCARD_MODEL_PAGES = "DiscardModelPages"; 181 182 /** The discard properties node name. */ 183 public static final String N_DISCARD_PROPERTIES = "DiscardProperties"; 184 185 /** The discard types node name. */ 186 public static final String N_DISCARD_TYPES = "DiscardTypes"; 187 188 /** The display name node name. */ 189 public static final String N_DISPLAY_NAME = "DisplayName"; 190 191 /** The element view node name. */ 192 public static final String N_ELEMENT_VIEW = "ElementView"; 193 194 /** The error node name. */ 195 public static final String N_ERROR = "Error"; 196 197 /** The 'exclude external detail contents' node name. */ 198 public static final String N_EXCLUDE_EXTERNAL_DETAIL_CONTENTS = "ExcludeExternalDetailContents"; 199 200 /** The folder node name. */ 201 public static final String N_FOLDER = "Folder"; 202 203 /** The formatter node name. */ 204 public static final String N_FORMATTER = "Formatter"; 205 206 /** The function node name. */ 207 public static final String N_FUNCTION = "Function"; 208 209 /** The function node name. */ 210 public static final String N_FUNCTION_DEFAULT_PAGE = "FunctionDefaultPage"; 211 212 /** The function reference node name. */ 213 public static final String N_FUNCTION_REF = "FunctionRef"; 214 215 /** The 'include in site selector' node name. */ 216 public static final String N_INCLUDE_IN_SITE_SELECTOR = "IncludeInSiteSelector"; 217 218 /** The IncludeName node name. */ 219 public static final String N_INCLUDE_NAME = "IncludeName"; 220 221 /** The is default node name. */ 222 public static final String N_IS_DEFAULT = "IsDefault"; 223 224 /** The is preview node name. */ 225 public static final String N_IS_PREVIEW = "IsPreview"; 226 227 /** The JSP node name. */ 228 public static final String N_JSP = "Jsp"; 229 230 /** The Key node name. */ 231 public static final String N_KEY = "Key"; 232 233 /** The localization node name. */ 234 public static final String N_LOCALIZATION = "Localization"; 235 236 /** The master configuration node name. */ 237 public static final String N_MASTER_CONFIG = "MasterConfig"; 238 239 /** The max width node name. */ 240 public static final String N_MAX_WIDTH = "MaxWidth"; 241 242 /** The min width node name. */ 243 public static final String N_MIN_WIDTH = "MinWidth"; 244 245 /** The model page node name. */ 246 public static final String N_MODEL_PAGE = "ModelPage"; 247 248 /** The folder name node name. */ 249 public static final String N_NAME = "Name"; 250 251 /** The name pattern node name. */ 252 public static final String N_NAME_PATTERN = "NamePattern"; 253 254 /** The order node name. */ 255 public static final String N_ORDER = "Order"; 256 257 /** The page node name. */ 258 public static final String N_PAGE = "Page"; 259 260 /** The PageRelative node name. */ 261 public static final String N_PAGE_RELATIVE = "PageRelative"; 262 263 /** The folder path node name. */ 264 public static final String N_PATH = "Path"; 265 266 /** Placeholder node name. */ 267 public static final String N_PLACEHOLDER = "Placeholder"; 268 269 /** The Plugin node name. */ 270 public static final String N_PLUGIN = "Plugin"; 271 272 /** The PreferDetailPagesForLocalContents node name. */ 273 public static final String N_PREFER_DETAIL_PAGES_FOR_LOCAL_CONTENTS = "PreferDetailPagesForLocalContents"; 274 275 /** The prefer folder node name. */ 276 public static final String N_PREFER_FOLDER = "PreferFolder"; 277 278 /** The property node name. */ 279 public static final String N_PROPERTY = "Property"; 280 281 /** The property name node name. */ 282 public static final String N_PROPERTY_NAME = "PropertyName"; 283 284 /** XML node name. */ 285 public static final String N_PROPERTY_NAME_ALIAS = "PropertyNameAlias"; 286 287 /** Node name for the "Remove all formatters"-option. */ 288 public static final String N_REMOVE_ALL_FORMATTERS = "RemoveAllFormatters"; 289 290 /** Field name for the 'Remove all functions' setting. */ 291 public static final String N_REMOVE_ALL_FUNCTIONS = "RemoveAllFunctions"; 292 293 /** The RemoveAllPlugins node name. */ 294 public static final String N_REMOVE_ALL_PLUGINS = "RemoveAllPlugins"; 295 296 /** The RemoveAllSharedSettingOverrides node name. */ 297 public static final String N_REMOVE_ALL_SHARED_SETTING_OVERRIDES = "RemoveAllSharedSettingOverrides"; 298 299 /** Node name for removed formatters. */ 300 public static final String N_REMOVE_FORMATTER = "RemoveFormatter"; 301 302 /** Node name for the nested content with the removed formatters. */ 303 public static final String N_REMOVE_FORMATTERS = "RemoveFormatters"; 304 305 /** The remove function node name. */ 306 public static final String N_REMOVE_FUNCTIONS = "RemoveFunctions"; 307 308 /** The RemovePlugin node name. */ 309 public static final String N_REMOVE_PLUGIN = "RemovePlugin"; 310 311 /** The RemovePlugins node name. */ 312 public static final String N_REMOVE_PLUGINS = "RemovePlugins"; 313 314 /** The resource type node name. */ 315 public static final String N_RESOURCE_TYPE = "ResourceType"; 316 317 /** The regex rule node name. */ 318 public static final String N_RULE_REGEX = "RuleRegex"; 319 320 /** The rule type node name. */ 321 public static final String N_RULE_TYPE = "RuleType"; 322 323 /** The SharedSettingOverride node name. */ 324 public static final String N_SHARED_SETTING_OVERRIDE = "SharedSettingOverride"; 325 326 /** The ShowInDefaultView node name. */ 327 public static final String N_SHOW_IN_DEFAULT_VIEW = "ShowInDefaultView"; 328 329 /** The type node name. */ 330 public static final String N_TYPE = "Type"; 331 332 /** The type name node name. */ 333 public static final String N_TYPE_NAME = "TypeName"; 334 335 /** The node name for the type ordering mode. */ 336 public static final String N_TYPE_ORDERING_MODE = "TypeOrderingMode"; 337 338 /** Node name. */ 339 public static final String N_USE_FORMATTER_KEYS = "UseFormatterKeys"; 340 341 /** The Value node name. */ 342 public static final String N_VALUE = "Value"; 343 344 /** XML node name. */ 345 public static final String N_VALUE_TRANSLATION = "ValueTranslation"; 346 347 /** The widget node name. */ 348 public static final String N_VISIBILITY = "Visibility"; 349 350 /** The widget node name. */ 351 public static final String N_WIDGET = "Widget"; 352 353 /** The widget configuration node name. */ 354 public static final String N_WIDGET_CONFIG = "WidgetConfig"; 355 356 /** Scheme for explorer type view links. */ 357 public static final String VIEW_SCHEME = "view://"; 358 359 /** The log object for this class. */ 360 private static final Log LOG = CmsLog.getLog(CmsConfigurationReader.class); 361 362 /** The ElementDeleteMode node name. */ 363 private static final String N_ELEMENT_DELETE_MODE = "ElementDeleteMode"; 364 365 /** The CMS context used for reading the configuration data. */ 366 private CmsObject m_cms; 367 368 /** The parsed detail page configuration elements. */ 369 private List<CmsDetailPageInfo> m_detailPageConfigs = new ArrayList<CmsDetailPageInfo>(); 370 371 /** The list of configured function references. */ 372 private List<CmsFunctionReference> m_functionReferences = new ArrayList<CmsFunctionReference>(); 373 374 /** The parsed model page configuration elements. */ 375 private List<CmsModelPageConfigWithoutResource> m_modelPageConfigs = new ArrayList<CmsModelPageConfigWithoutResource>(); 376 377 /** The parsed property configuration elements. */ 378 private List<CmsPropertyConfig> m_propertyConfigs = new ArrayList<CmsPropertyConfig>(); 379 380 /** The resource type configuration objects. */ 381 private List<CmsResourceTypeConfig> m_resourceTypeConfigs = new ArrayList<CmsResourceTypeConfig>(); 382 383 /** 384 * Creates a new configuration reader.<p> 385 * 386 * @param cms the CMS context which should be used to read the configuration data.<p> 387 */ 388 public CmsConfigurationReader(CmsObject cms) { 389 390 m_cms = cms; 391 } 392 393 /** 394 * Gets the string value of an XML content location.<p> 395 * 396 * @param cms the CMS context to use 397 * @param location an XML content location 398 * 399 * @return the string value of that XML content location 400 */ 401 public static String getString(CmsObject cms, I_CmsXmlContentValueLocation location) { 402 403 if (location == null) { 404 return null; 405 } 406 return location.asString(cms); 407 } 408 409 /** 410 * Helper method to parse a property.<p> 411 * 412 * @param cms the CMS context to use 413 * @param field the location of the parent value 414 * 415 * @return the parsed property configuration 416 */ 417 public static CmsPropertyConfig parseProperty(CmsObject cms, I_CmsXmlContentLocation field) { 418 419 String name = getString(cms, field.getSubValue(N_PROPERTY_NAME)); 420 String includeName = getString(cms, field.getSubValue(N_INCLUDE_NAME)); 421 String widget = getString(cms, field.getSubValue(N_WIDGET)); 422 String widgetConfig = getString(cms, field.getSubValue(N_WIDGET_CONFIG)); 423 String ruleRegex = getString(cms, field.getSubValue(N_RULE_REGEX)); 424 String ruleType = getString(cms, field.getSubValue(N_RULE_TYPE)); 425 String default1 = getString(cms, field.getSubValue(N_DEFAULT)); 426 String placeholder = getString(cms, field.getSubValue(N_PLACEHOLDER)); 427 String error = getString(cms, field.getSubValue(N_ERROR)); 428 String niceName = getString(cms, field.getSubValue(N_DISPLAY_NAME)); 429 String description = getString(cms, field.getSubValue(N_DESCRIPTION)); 430 String preferFolder = getString(cms, field.getSubValue(N_PREFER_FOLDER)); 431 String aliasName = getString(cms, field.getSubValue(N_PROPERTY_NAME_ALIAS)); 432 String valueTranslations = getString(cms, field.getSubValue(N_VALUE_TRANSLATION)); 433 434 String disabledStr = getString(cms, field.getSubValue(N_DISABLED)); 435 boolean disabled = ((disabledStr != null) && Boolean.parseBoolean(disabledStr)); 436 437 String orderStr = getString(cms, field.getSubValue(N_ORDER)); 438 int order = I_CmsConfigurationObject.DEFAULT_ORDER; 439 440 try { 441 order = Integer.parseInt(orderStr); 442 } catch (NumberFormatException e) { 443 // noop 444 } 445 446 Visibility visibility; 447 String visibilityStr = getString(cms, field.getSubValue(N_VISIBILITY)); 448 try { 449 // to stay compatible with former visibility option values 450 if ("both".equals(visibilityStr)) { 451 visibilityStr = Visibility.elementAndParentIndividual.name(); 452 } else if ("parent".equals(visibilityStr)) { 453 visibilityStr = Visibility.parentShared.name(); 454 } 455 visibility = Visibility.valueOf(visibilityStr); 456 } catch (Exception e) { 457 visibility = null; 458 } 459 CmsXmlContentProperty prop = new CmsXmlContentProperty( 460 name, 461 aliasName, 462 "string", 463 visibility, 464 widget, 465 widgetConfig, 466 ruleRegex, 467 ruleType, 468 default1, 469 placeholder, 470 niceName, 471 description, 472 error, 473 preferFolder, 474 valueTranslations).withIncludeName(includeName); 475 // since these are real properties, using type vfslist makes no sense, so we always use the "string" type 476 CmsPropertyConfig propConfig = new CmsPropertyConfig(prop, disabled, order); 477 return propConfig; 478 479 } 480 481 /** 482 * Returns the list of function references.<p> 483 * 484 * @return the list of function references 485 */ 486 public List<CmsFunctionReference> getFunctionReferences() { 487 488 return new ArrayList<CmsFunctionReference>(m_functionReferences); 489 } 490 491 /** 492 * Returns the modelPageConfigs.<p> 493 * 494 * @return the modelPageConfigs 495 */ 496 public List<CmsModelPageConfigWithoutResource> getModelPageConfigs() { 497 498 return m_modelPageConfigs; 499 } 500 501 /** 502 * Parses the formatters to add.<p> 503 * 504 * @param node the parent node 505 * @return the set of keys of the formatters to add 506 */ 507 public Set<String> parseAddFormatters(I_CmsXmlContentLocation node) { 508 509 Set<String> addFormatters = new HashSet<String>(); 510 for (I_CmsXmlContentValueLocation addLoc : node.getSubValues(N_ADD_FORMATTERS + "/" + N_ADD_FORMATTER)) { 511 CmsXmlVfsFileValue value = (CmsXmlVfsFileValue)addLoc.getValue(); 512 CmsLink link = value.getLink(m_cms); 513 if (link != null) { 514 CmsUUID structureId = link.getStructureId(); 515 if (structureId != null) { 516 addFormatters.add(structureId.toString()); 517 } 518 } 519 } 520 return addFormatters; 521 } 522 523 /** 524 * Parses a configuration XML content and creates a configuration object from it.<p> 525 * 526 * @param basePath the base path 527 * @param content the XML content 528 * 529 * @return the created configuration object with the data from the XML content 530 * @throws CmsException if something goes wrong 531 */ 532 public CmsADEConfigDataInternal parseConfiguration(String basePath, CmsXmlContent content) throws CmsException { 533 534 m_detailPageConfigs = Lists.newArrayList(); 535 m_functionReferences = Lists.newArrayList(); 536 m_modelPageConfigs = Lists.newArrayList(); 537 m_propertyConfigs = Lists.newArrayList(); 538 m_resourceTypeConfigs = Lists.newArrayList(); 539 CmsUUID baseId = null; 540 if (basePath != null) { 541 try { 542 CmsResource folderRes = m_cms.readResource(basePath, CmsResourceFilter.IGNORE_EXPIRATION); 543 baseId = folderRes.getStructureId(); 544 } catch (Exception e) { 545 LOG.error(e.getLocalizedMessage(), e); 546 } 547 } 548 if (!content.hasLocale(DEFAULT_LOCALE)) { 549 return CmsADEConfigDataInternal.emptyConfiguration(basePath); 550 } 551 CmsXmlContentRootLocation root = new CmsXmlContentRootLocation(content, DEFAULT_LOCALE); 552 for (I_CmsXmlContentValueLocation node : root.getSubValues(N_RESOURCE_TYPE)) { 553 try { 554 parseResourceTypeConfig(basePath, node); 555 } catch (CmsException e) { 556 LOG.warn(e.getLocalizedMessage(), e); 557 } 558 } 559 for (I_CmsXmlContentValueLocation node : root.getSubValues(N_MODEL_PAGE)) { 560 try { 561 parseModelPage(node); 562 } catch (Exception e) { 563 LOG.warn(e.getLocalizedMessage(), e); 564 } 565 } 566 for (I_CmsXmlContentLocation node : root.getSubValues(N_DETAIL_PAGE)) { 567 try { 568 parseDetailPage(node); 569 } catch (Exception e) { 570 LOG.warn(e.getLocalizedMessage(), e); 571 } 572 } 573 574 for (I_CmsXmlContentLocation node : root.getSubValues(N_FUNCTION_REF)) { 575 parseFunctionReference(node); 576 } 577 578 CmsUUID sharedSettingOverride = null; 579 for (I_CmsXmlContentValueLocation node : root.getSubValues(N_SHARED_SETTING_OVERRIDE)) { 580 sharedSettingOverride = ((CmsXmlVfsFileValue)node.getValue()).getLink(m_cms).getStructureId(); 581 } 582 583 boolean removeSharedSettingOverrides = getBoolean(root, N_REMOVE_ALL_SHARED_SETTING_OVERRIDES); 584 585 boolean removeFunctions = false; 586 removeFunctions = getBoolean(root, N_REMOVE_ALL_FUNCTIONS); 587 588 Set<CmsUUID> functions = new LinkedHashSet<>(); 589 for (I_CmsXmlContentValueLocation node : root.getSubValues(N_FUNCTION)) { 590 CmsXmlVfsFileValue value = (CmsXmlVfsFileValue)node.getValue(); 591 CmsLink link = value.getLink(m_cms); 592 if (link != null) { 593 CmsUUID structureId = link.getStructureId(); 594 if (structureId != null) { 595 functions.add(link.getStructureId()); 596 } 597 } 598 } 599 600 Set<CmsUUID> functionsToRemove = new LinkedHashSet<>(); 601 for (I_CmsXmlContentValueLocation parent : root.getSubValues(N_REMOVE_FUNCTIONS)) { 602 for (I_CmsXmlContentValueLocation node : parent.getSubValues(N_FUNCTION)) { 603 CmsXmlVfsFileValue value = (CmsXmlVfsFileValue)node.getValue(); 604 CmsLink link = value.getLink(m_cms); 605 if (link != null) { 606 CmsUUID structureId = link.getStructureId(); 607 if (structureId != null) { 608 functionsToRemove.add(link.getStructureId()); 609 } 610 } 611 } 612 } 613 614 boolean removeAllPlugins = getBoolean(root, N_REMOVE_ALL_PLUGINS); 615 Set<CmsUUID> pluginsToRemove = readInternalLinkListTargetIds(root, N_REMOVE_PLUGINS, N_PLUGIN); 616 Set<CmsUUID> pluginsToAdd = readInternalLinkListTargetIds(root, N_ADD_PLUGINS, N_PLUGIN); 617 618 boolean removeAllFormatters = getBoolean(root, N_REMOVE_ALL_FORMATTERS); 619 CmsFormatterChangeSet formatterChangeSet = parseFormatterChangeSet( 620 basePath, 621 root, 622 removeAllFormatters, 623 removeFunctions, 624 functions, 625 functionsToRemove); 626 boolean discardInheritedTypes = getBoolean(root, N_DISCARD_TYPES); 627 // boolean discardInheritedProperties = getBoolean(root, N_DISCARD_PROPERTIES); 628 I_CmsXmlContentValueLocation discardPropertiesLoc = root.getSubValue(N_DISCARD_PROPERTIES); 629 DiscardPropertiesMode discardPropertiesMode = DiscardPropertiesMode.keep; 630 if (discardPropertiesLoc != null) { 631 String discardPropertiesStr = discardPropertiesLoc.getValue().getStringValue(m_cms); 632 for (DiscardPropertiesMode discardMode : DiscardPropertiesMode.values()) { 633 if (discardMode.getStringValue().contentEquals(discardPropertiesStr)) { 634 discardPropertiesMode = discardMode; 635 } 636 } 637 } 638 for (I_CmsXmlContentLocation node : root.getSubValues(N_PROPERTY)) { 639 parseProperty(node, discardPropertiesMode); 640 } 641 642 boolean discardInheritedModelPages = getBoolean(root, N_DISCARD_MODEL_PAGES); 643 644 boolean createContentsLocally = getBoolean(root, N_CREATE_CONTENTS_LOCALLY); 645 CmsContentFolderOption contentFolderOption = null; 646 for (I_CmsXmlContentValueLocation contentFolderLoc : root.getSubValues(N_CONTENT_FOLDER)) { 647 contentFolderOption = parseContentFolderOption(contentFolderLoc); 648 } 649 boolean preferDetailPagesForLocalContents = getBoolean(root, N_PREFER_DETAIL_PAGES_FOR_LOCAL_CONTENTS); 650 boolean exludeExternalDetailContents = getBoolean(root, N_EXCLUDE_EXTERNAL_DETAIL_CONTENTS); 651 boolean includeInSiteSelector = getBoolean(root, N_INCLUDE_IN_SITE_SELECTOR); 652 653 String galleryDisabledTypesStr = getString(root.getSubValue(N_DISABLED_TYPES_MODE)); 654 CmsGalleryDisabledTypesMode galleryDisabledTypesMode = null; 655 if (galleryDisabledTypesStr != null) { 656 galleryDisabledTypesMode = CmsGalleryDisabledTypesMode.valueOf(galleryDisabledTypesStr); 657 } 658 659 String galleryDisabledFunctionsStr = getString(root.getSubValue(N_DISABLED_FUNCTIONS_MODE)); 660 CmsGalleryDisabledTypesMode galleryDisabledFunctionsMode = null; 661 if (galleryDisabledFunctionsStr != null) { 662 galleryDisabledFunctionsMode = CmsGalleryDisabledTypesMode.valueOf(galleryDisabledFunctionsStr); 663 } 664 665 I_CmsXmlContentValueLocation typeOrderingLoc = root.getSubValue(N_TYPE_ORDERING_MODE); 666 CmsTypeOrderingMode typeOrderingMode = null; 667 if (typeOrderingLoc != null) { 668 boolean byDisplayOrder = Boolean.parseBoolean(typeOrderingLoc.getValue().getStringValue(m_cms)); 669 typeOrderingMode = byDisplayOrder ? CmsTypeOrderingMode.byDisplayOrder : CmsTypeOrderingMode.latestOnTop; 670 } 671 672 I_CmsXmlContentValueLocation useFormatterKeysLoc = root.getSubValue(N_USE_FORMATTER_KEYS); 673 Boolean useFormatterKeys = null; 674 if (useFormatterKeysLoc != null) { 675 useFormatterKeys = Boolean.valueOf(useFormatterKeysLoc.getValue().getStringValue(m_cms)); 676 } 677 678 boolean isModuleConfig = OpenCms.getResourceManager().getResourceType( 679 content.getFile().getTypeId()).getTypeName().equals(CmsADEManager.MODULE_CONFIG_TYPE); 680 681 List<ConfigReference> masterConfigIds = new ArrayList<>(); 682 for (I_CmsXmlContentValueLocation masterConfigLoc : root.getSubValues(N_MASTER_CONFIG)) { 683 CmsXmlVfsFileValue value = (CmsXmlVfsFileValue)masterConfigLoc.getValue(); 684 CmsLink link = value.getUncheckedLink(); 685 ConfigReferenceMeta meta = null; 686 if (link != null) { 687 meta = new ConfigReferenceMeta(link.getParameterMap()); 688 } 689 CmsUUID id = masterConfigLoc.asId(m_cms); 690 if (id != null) { 691 masterConfigIds.add(new ConfigReference(id, meta)); 692 } 693 } 694 695 Map<String, String> attributes = new LinkedHashMap<>(); 696 for (I_CmsXmlContentValueLocation mappingLoc : root.getSubValues(N_ATTRIBUTE)) { 697 String key = getString(mappingLoc.getSubValue(N_KEY)).trim(); 698 String value = getString(mappingLoc.getSubValue(N_VALUE)).trim(); 699 attributes.put(key, value); 700 } 701 702 I_CmsXmlContentValueLocation attributeEditorConfigLoc = root.getSubValue(N_ATTRIBUTE_EDITOR_CONFIG); 703 CmsUUID attributeEditorConfigId = null; 704 if (attributeEditorConfigLoc != null) { 705 attributeEditorConfigId = attributeEditorConfigLoc.asId(m_cms); 706 } 707 708 CmsAddContentRestriction addContentRestriction = CmsAddContentRestriction.read( 709 m_cms, 710 root, 711 N_ADD_CONTENT_RESTRICTION); 712 713 CmsADEConfigDataInternal result = new CmsADEConfigDataInternal( 714 m_cms, 715 content.getFile(), 716 isModuleConfig, 717 basePath, 718 baseId, 719 masterConfigIds, 720 m_resourceTypeConfigs, 721 galleryDisabledTypesMode, 722 galleryDisabledFunctionsMode, 723 discardInheritedTypes, 724 m_propertyConfigs, 725 discardPropertiesMode, 726 m_detailPageConfigs, 727 m_modelPageConfigs, 728 m_functionReferences, 729 discardInheritedModelPages, 730 createContentsLocally, 731 contentFolderOption, 732 preferDetailPagesForLocalContents, 733 exludeExternalDetailContents, 734 includeInSiteSelector, 735 formatterChangeSet, 736 removeFunctions, 737 functions, 738 functionsToRemove, 739 removeAllPlugins, 740 pluginsToAdd, 741 pluginsToRemove, 742 useFormatterKeys, 743 typeOrderingMode, 744 addContentRestriction, 745 sharedSettingOverride, 746 removeSharedSettingOverrides, 747 attributeEditorConfigId, 748 attributes); 749 return result; 750 } 751 752 /** 753 * Parses the content folder configuration. 754 * 755 * @param location the XML content location from which to read the data. 756 * 757 * @return the content folder configuration 758 */ 759 public CmsContentFolderOption parseContentFolderOption(I_CmsXmlContentLocation location) { 760 761 if (location == null) { 762 return null; 763 } 764 I_CmsXmlContentValueLocation defaultLoc = location.getSubValue(N_DEFAULT); 765 I_CmsXmlContentValueLocation pathLoc = location.getSubValue(N_PATH); 766 if (defaultLoc != null) { 767 return new CmsContentFolderOption(null); 768 } 769 if (pathLoc != null) { 770 CmsXmlVfsFileValue value = (CmsXmlVfsFileValue)pathLoc.getValue(); 771 if ((value.getUncheckedLink() != null) && (value.getUncheckedLink().getStructureId() != null)) { 772 773 return new CmsContentFolderOption(value.getUncheckedLink().getStructureId()); 774 } 775 } 776 if (LOG.isWarnEnabled()) { 777 LOG.warn(location.getDocument().getFile().getRootPath() + ": invalid content folder"); 778 } 779 return null; 780 } 781 782 /** 783 * Parses a folder which may either be given as a path or as a folder name.<p> 784 * 785 * @param basePath the base path for the configuration 786 * @param location the XML content node from which to parse the folder 787 * @return the folder bean 788 * 789 * @throws CmsException if something goes wrong 790 */ 791 public CmsContentFolderDescriptor parseFolderOrName(String basePath, I_CmsXmlContentLocation location) 792 throws CmsException { 793 794 if (location == null) { 795 return null; 796 } 797 I_CmsXmlContentValueLocation nameLoc = location.getSubValue(N_NAME); 798 I_CmsXmlContentValueLocation pathLoc = location.getSubValue(N_PATH); 799 I_CmsXmlContentValueLocation pageRelativeLoc = location.getSubValue(N_PAGE_RELATIVE); 800 if (nameLoc != null) { 801 String name = nameLoc.asString(m_cms); 802 return new CmsContentFolderDescriptor( 803 basePath == null ? null : CmsStringUtil.joinPaths(basePath, CmsADEManager.CONTENT_FOLDER_NAME), 804 name); 805 } else if (pathLoc != null) { 806 String path = pathLoc.asString(m_cms); 807 CmsResource folder = m_cms.readResource(path); 808 return new CmsContentFolderDescriptor(folder); 809 } else if (pageRelativeLoc != null) { 810 return CmsContentFolderDescriptor.createPageRelativeFolderDescriptor(); 811 } else { 812 return null; 813 } 814 } 815 816 /** 817 * Parses a formatter bean.<p> 818 * 819 * @param typeName the type name for which the formatter is being parsed 820 * @param node the node from which to parse the formatter data 821 * 822 * @return the formatter bean from the XML 823 */ 824 public CmsFormatterBean parseFormatter(String typeName, I_CmsXmlContentLocation node) { 825 826 String type = getString(node.getSubValue(N_TYPE)); 827 String minWidth = getString(node.getSubValue(N_MIN_WIDTH)); 828 String maxWidth = getString(node.getSubValue(N_MAX_WIDTH)); 829 boolean preview = false; 830 I_CmsXmlContentValueLocation previewLoc = node.getSubValue(N_IS_PREVIEW); 831 preview = (previewLoc != null) && Boolean.parseBoolean(previewLoc.asString(m_cms)); 832 String jsp = m_cms.getRequestContext().addSiteRoot(getString(node.getSubValue(N_JSP))); 833 boolean searchContent = true; 834 CmsFormatterBean formatterBean = new CmsFormatterBean( 835 type, 836 jsp, 837 minWidth, 838 maxWidth, 839 "" + preview, 840 "" + searchContent, 841 null); 842 return formatterBean; 843 844 } 845 846 /** 847 * Parses model page data from the XML content.<p> 848 * 849 * @param node the XML content node 850 */ 851 public void parseModelPage(I_CmsXmlContentLocation node) { 852 853 CmsXmlVfsFileValue pageValue = (CmsXmlVfsFileValue)node.getSubValue(N_PAGE).getValue(); 854 CmsLink link = pageValue.getUncheckedLink(); 855 if ((link == null) || (link.getStructureId() == null)) { 856 return; 857 } 858 I_CmsXmlContentValueLocation disabledLoc = node.getSubValue(N_DISABLED); 859 boolean disabled = (disabledLoc != null) && Boolean.parseBoolean(disabledLoc.asString(m_cms)); 860 I_CmsXmlContentValueLocation defaultLoc = node.getSubValue(N_IS_DEFAULT); 861 boolean isDefault = (defaultLoc != null) && Boolean.parseBoolean(defaultLoc.asString(m_cms)); 862 CmsModelPageConfigWithoutResource modelPage = new CmsModelPageConfigWithoutResource( 863 link.getStructureId(), 864 isDefault, 865 disabled); 866 m_modelPageConfigs.add(modelPage); 867 868 } 869 870 /** 871 * Parses the set of formatters to remove.<p> 872 * 873 * @param node the parent node 874 * @return the set of formatters to remove 875 */ 876 public Set<String> parseRemoveFormatters(I_CmsXmlContentLocation node) { 877 878 Set<String> removeFormatters = new HashSet<String>(); 879 for (I_CmsXmlContentValueLocation removeLoc : node.getSubValues( 880 N_REMOVE_FORMATTERS + "/" + N_REMOVE_FORMATTER)) { 881 CmsXmlVfsFileValue value = (CmsXmlVfsFileValue)removeLoc.getValue(); 882 CmsLink link = value.getLink(m_cms); 883 if (link != null) { 884 CmsUUID structureId = link.getStructureId(); 885 if (structureId != null) { 886 removeFormatters.add(structureId.toString()); 887 } 888 } 889 } 890 return removeFormatters; 891 } 892 893 /** 894 * Parses a resource type configuration element from the XML content.<p> 895 * 896 * @param basePath the base path of the configuration 897 * @param node the XML configuration node 898 * @throws CmsException if something goes wrong 899 */ 900 public void parseResourceTypeConfig(String basePath, I_CmsXmlContentLocation node) throws CmsException { 901 902 I_CmsXmlContentValueLocation typeNameLoc = node.getSubValue(N_TYPE_NAME); 903 String typeName = typeNameLoc.asString(m_cms); 904 CmsContentFolderDescriptor folderOrName = parseFolderOrName(basePath, node.getSubValue(N_FOLDER)); 905 I_CmsXmlContentValueLocation disabledLoc = node.getSubValue(N_DISABLED); 906 boolean disabled = false; 907 boolean addDisabled = false; 908 boolean createDisabled = false; 909 boolean editDisabled = false; 910 boolean listsOnly = false; 911 String disabledStr = disabledLoc == null ? null : disabledLoc.asString(m_cms); 912 boolean availabilityNotSet = false; 913 if (disabledStr != null) { 914 if ("add".equalsIgnoreCase(disabledStr.trim())) { 915 addDisabled = true; 916 } else if ("create".equalsIgnoreCase(disabledStr.trim())) { 917 createDisabled = true; 918 } else if ("createOrEdit".equalsIgnoreCase(disabledStr.trim())) { 919 createDisabled = true; 920 editDisabled = true; 921 } else if ("listsOnly".equalsIgnoreCase(disabledStr.trim())) { 922 listsOnly = true; 923 addDisabled = true; 924 } else { 925 disabled = Boolean.parseBoolean(disabledStr); 926 } 927 } else { 928 availabilityNotSet = true; 929 } 930 931 I_CmsXmlContentValueLocation namePatternLoc = node.getSubValue(N_NAME_PATTERN); 932 String namePattern = null; 933 if (namePatternLoc != null) { 934 namePattern = namePatternLoc.asString(m_cms); 935 } 936 937 boolean detailPagesDisabled = false; 938 I_CmsXmlContentValueLocation detailDisabledLoc = node.getSubValue(N_DETAIL_PAGES_DISABLED); 939 if (detailDisabledLoc != null) { 940 String detailPagesDisabledStr = detailDisabledLoc.asString(m_cms); 941 detailPagesDisabled = Boolean.parseBoolean(detailPagesDisabledStr); 942 } 943 944 Integer order = null; 945 I_CmsXmlContentValueLocation orderLoc = node.getSubValue(N_ORDER); 946 if (orderLoc != null) { 947 try { 948 String orderStr = orderLoc.asString(m_cms); 949 order = Integer.valueOf(orderStr); 950 } catch (NumberFormatException e) { 951 // noop 952 } 953 } 954 955 I_CmsXmlContentValueLocation elementViewLoc = node.getSubValue(N_ELEMENT_VIEW); 956 CmsUUID elementView = null; 957 if (elementViewLoc != null) { 958 try { 959 CmsXmlVarLinkValue elementViewValue = (CmsXmlVarLinkValue)elementViewLoc.getValue(); 960 String stringValue = elementViewValue.getStringValue(m_cms); 961 if ("".equals(stringValue)) { 962 elementView = CmsUUID.getNullUUID(); 963 } else if (stringValue.startsWith(VIEW_SCHEME)) { 964 elementView = new CmsUUID(stringValue.substring(VIEW_SCHEME.length())); 965 } else { 966 elementView = elementViewValue.getLink(m_cms).getStructureId(); 967 } 968 } catch (Exception e) { 969 // in case parsing the link fails, the default element view will be used 970 } 971 } 972 973 I_CmsXmlContentValueLocation locationLoc = node.getSubValue(N_LOCALIZATION); 974 String localization = null; 975 if (locationLoc != null) { 976 CmsXmlVfsFileValue locationValue = (CmsXmlVfsFileValue)locationLoc.getValue(); 977 CmsLink link = locationValue.getLink(m_cms); 978 if (null != link) { 979 String stringValue = link.getSitePath(m_cms); 980 // extract bundle base name from the path to the bundle file 981 int lastSlashIndex = stringValue.lastIndexOf("/"); 982 String fileName = stringValue.substring(lastSlashIndex + 1); 983 if (CmsFileUtil.getExtension(fileName).equals(".properties")) { 984 fileName = fileName.substring(0, fileName.length() - ".properties".length()); 985 } 986 String localeSuffix = CmsStringUtil.getLocaleSuffixForName(fileName); 987 if ((localeSuffix != null) && fileName.endsWith(localeSuffix)) { 988 fileName = fileName.substring(0, fileName.length() - localeSuffix.length() - 1); 989 } 990 localization = fileName; 991 } 992 } 993 994 I_CmsXmlContentValueLocation showDefaultViewLoc = node.getSubValue(N_SHOW_IN_DEFAULT_VIEW); 995 Boolean showInDefaultView = null; 996 if (showDefaultViewLoc != null) { 997 showInDefaultView = Boolean.valueOf( 998 Boolean.parseBoolean(showDefaultViewLoc.getValue().getStringValue(m_cms))); 999 } 1000 1001 I_CmsXmlContentValueLocation copyInModelsLoc = node.getSubValue(N_COPY_IN_MODELS); 1002 Boolean copyInModels = null; 1003 if (copyInModelsLoc != null) { 1004 copyInModels = Boolean.valueOf(Boolean.parseBoolean(copyInModelsLoc.getValue().getStringValue(m_cms))); 1005 } 1006 1007 I_CmsXmlContentValueLocation elementDeleteModeLoc = node.getSubValue(N_ELEMENT_DELETE_MODE); 1008 ElementDeleteMode elementDeleteMode = null; 1009 if (elementDeleteModeLoc != null) { 1010 try { 1011 elementDeleteMode = ElementDeleteMode.valueOf(elementDeleteModeLoc.getValue().getStringValue(m_cms)); 1012 } catch (Exception e) { 1013 LOG.warn(e.getLocalizedMessage(), e); 1014 } 1015 } 1016 1017 I_CmsXmlContentValueLocation checkReuseLoc = node.getSubValue(N_CHECK_REUSE); 1018 Boolean checkReuse = null; 1019 if (checkReuseLoc != null) { 1020 try { 1021 checkReuse = Boolean.valueOf(checkReuseLoc.getValue().getStringValue(m_cms)); 1022 } catch (Exception e) { 1023 LOG.warn(e.getLocalizedMessage(), e); 1024 } 1025 } 1026 1027 List<I_CmsFormatterBean> formatters = new ArrayList<I_CmsFormatterBean>(); 1028 for (I_CmsXmlContentValueLocation formatterLoc : node.getSubValues(N_FORMATTER)) { 1029 CmsFormatterBean formatter = parseFormatter(typeName, formatterLoc); 1030 formatters.add(formatter); 1031 } 1032 1033 CmsResourceTypeConfig typeConfig = new CmsResourceTypeConfig( 1034 typeName, 1035 disabled, 1036 folderOrName, 1037 namePattern, 1038 detailPagesDisabled, 1039 addDisabled, 1040 createDisabled, 1041 editDisabled, 1042 listsOnly, 1043 availabilityNotSet, 1044 elementView, 1045 localization, 1046 showInDefaultView, 1047 copyInModels, 1048 order, 1049 elementDeleteMode, 1050 checkReuse); 1051 m_resourceTypeConfigs.add(typeConfig); 1052 } 1053 1054 /** 1055 * Parses the sitemap configuration given the configuration file and base path.<p> 1056 * 1057 * @param basePath the base path 1058 * @param configRes the configuration file resource 1059 * @return the parsed configuration data 1060 * @throws CmsException if something goes wrong 1061 */ 1062 public CmsADEConfigDataInternal parseSitemapConfiguration(String basePath, CmsResource configRes) 1063 throws CmsException { 1064 1065 LOG.info("Parsing configuration " + configRes.getRootPath()); 1066 CmsFile configFile = m_cms.readFile(configRes); 1067 CmsXmlContent content = CmsXmlContentFactory.unmarshal(m_cms, configFile); 1068 return parseConfiguration(basePath, content); 1069 } 1070 1071 /** 1072 * Reads the configurations of all modules and combines them into a single configuration object.<p> 1073 * 1074 * @return the combined configuration object 1075 */ 1076 public List<CmsADEConfigDataInternal> readModuleConfigurations() { 1077 1078 List<CmsADEConfigDataInternal> configurations = new ArrayList<CmsADEConfigDataInternal>(); 1079 List<CmsModule> modules = OpenCms.getModuleManager().getAllInstalledModules(); 1080 long beginTime = System.currentTimeMillis(); 1081 for (CmsModule module : modules) { 1082 String configPath = module.getConfigurationPath(); 1083 if (m_cms.existsResource(configPath)) { 1084 try { 1085 CmsResource configFile = m_cms.readResource(configPath); 1086 LOG.info("Found module configuration " + configPath + " for module " + module.getName()); 1087 CmsADEConfigDataInternal config = parseSitemapConfiguration(null, configFile); 1088 configurations.add(config); 1089 } catch (CmsException e) { 1090 // errors while parsing configuration 1091 LOG.error(e.getLocalizedMessage(), e); 1092 } catch (CmsRuntimeException e) { 1093 // may happen during import of org.opencms.ade.configuration module 1094 LOG.warn(e.getLocalizedMessage(), e); 1095 } catch (Throwable e) { 1096 LOG.error(e.getLocalizedMessage(), e); 1097 } 1098 } 1099 } 1100 long endTime = System.currentTimeMillis(); 1101 LOG.debug("readModuleConfiguations took " + (endTime - beginTime) + "ms"); 1102 return configurations; 1103 } 1104 1105 /** 1106 * Helper method to read a boolean value from the XML.<p> 1107 * 1108 * If the element is not found in the XML, false is returned.<p> 1109 * 1110 * @param parent the parent node 1111 * @param name the name of the XML content value 1112 * @return the boolean value 1113 */ 1114 protected boolean getBoolean(I_CmsXmlContentLocation parent, String name) { 1115 1116 I_CmsXmlContentValueLocation location = parent.getSubValue(name); 1117 if (location == null) { 1118 return false; 1119 } 1120 String value = location.getValue().getStringValue(m_cms); 1121 return Boolean.parseBoolean(value); 1122 } 1123 1124 /** 1125 * Gets the string value of an XML content location.<p> 1126 * 1127 * @param location an XML content location 1128 * 1129 * @return the string value of that XML content location 1130 */ 1131 protected String getString(I_CmsXmlContentValueLocation location) { 1132 1133 return getString(m_cms, location); 1134 } 1135 1136 /** 1137 * Parses the detail pages from an XML content node.<p> 1138 * 1139 * @param node the XML content node 1140 */ 1141 protected void parseDetailPage(I_CmsXmlContentLocation node) { 1142 1143 I_CmsXmlContentValueLocation pageLoc = node.getSubValue(N_PAGE); 1144 String typeName = getString(node.getSubValue(N_TYPE)); 1145 int qualifierPos = typeName.indexOf(CmsDetailPageInfo.QUALIFIER_SEPARATOR); 1146 String qualifier = null; 1147 if (qualifierPos != -1) { 1148 qualifier = typeName.substring(qualifierPos + 1); 1149 typeName = typeName.substring(0, qualifierPos); 1150 } 1151 CmsXmlVfsFileValue detailPageValue = (CmsXmlVfsFileValue)pageLoc.getValue(); 1152 CmsLink uncheckedLink = detailPageValue.getUncheckedLink(); 1153 if (uncheckedLink == null) { 1154 LOG.warn( 1155 "Missing detail page link in " + CmsLog.eval(LOG, () -> node.getDocument().getFile().getRootPath())); 1156 return; 1157 } 1158 String page = uncheckedLink.getTarget(); 1159 CmsUUID structureId = uncheckedLink.getStructureId(); 1160 if (structureId == null) { 1161 return; 1162 } 1163 1164 String iconClasses; 1165 if (typeName.startsWith(CmsDetailPageInfo.FUNCTION_PREFIX)) { 1166 iconClasses = CmsIconUtil.getIconClasses(CmsXmlDynamicFunctionHandler.TYPE_FUNCTION, null, false); 1167 } else { 1168 iconClasses = CmsIconUtil.getIconClasses(typeName, null, false); 1169 } 1170 List<CmsUUID> folders = new ArrayList<>(); 1171 for (I_CmsXmlContentValueLocation folderLoc : node.getSubValues(N_FOLDER)) { 1172 CmsXmlVfsFileValue folderValue = (CmsXmlVfsFileValue)folderLoc.getValue(); 1173 CmsLink folderLink = folderValue.getUncheckedLink(); 1174 if ((folderLink != null) && (folderLink.getStructureId() != null)) { 1175 folders.add(folderLink.getStructureId()); 1176 } 1177 } 1178 1179 CmsDetailPageInfo detailPage = new CmsDetailPageInfo( 1180 structureId, 1181 page, 1182 typeName, 1183 qualifier, 1184 folders, 1185 iconClasses); 1186 m_detailPageConfigs.add(detailPage); 1187 1188 } 1189 1190 /** 1191 * Parses the formatter change set.<p> 1192 * 1193 * @param basePath the configuration base path 1194 * @param node the parent node 1195 * @param removeAllFormatters flag, indicating if all formatters that are not explicitly added should be removed 1196 * @param removeFunctions if true, remove functions 1197 * @param functions the functions to add 1198 * @param functionsToRemove the functions to remove 1199 * 1200 * @return the formatter change set 1201 */ 1202 protected CmsFormatterChangeSet parseFormatterChangeSet( 1203 String basePath, 1204 I_CmsXmlContentLocation node, 1205 boolean removeAllFormatters, 1206 boolean removeFunctions, 1207 Set<CmsUUID> functions, 1208 Set<CmsUUID> functionsToRemove) { 1209 1210 Set<String> addFormatters = parseAddFormatters(node); 1211 addFormatters.addAll(readLocalFormatters(node)); 1212 Set<String> removeFormatters = removeAllFormatters ? new HashSet<String>() : parseRemoveFormatters(node); 1213 String siteRoot = null; 1214 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(basePath)) { 1215 siteRoot = OpenCms.getSiteManager().getSiteRoot(basePath); 1216 } 1217 CmsFormatterChangeSet result = new CmsFormatterChangeSet( 1218 removeFormatters, 1219 addFormatters, 1220 siteRoot, 1221 removeAllFormatters, 1222 removeFunctions, 1223 functions, 1224 functionsToRemove); 1225 return result; 1226 } 1227 1228 /** 1229 * Parses a function reference node.<p> 1230 * 1231 * @param node the function reference node 1232 */ 1233 protected void parseFunctionReference(I_CmsXmlContentLocation node) { 1234 1235 String name = node.getSubValue(N_NAME).asString(m_cms); 1236 CmsUUID functionId = node.getSubValue(N_FUNCTION).asId(m_cms); 1237 CmsUUID functionDefaultPageId = null; 1238 I_CmsXmlContentValueLocation defaultPageValue = node.getSubValue(N_FUNCTION_DEFAULT_PAGE); 1239 if (defaultPageValue != null) { 1240 functionDefaultPageId = defaultPageValue.asId(m_cms); 1241 } 1242 I_CmsXmlContentValueLocation orderNode = node.getSubValue(N_ORDER); 1243 int order = I_CmsConfigurationObject.DEFAULT_ORDER; 1244 if (orderNode != null) { 1245 String orderStr = orderNode.asString(m_cms); 1246 try { 1247 order = Integer.parseInt(orderStr); 1248 } catch (NumberFormatException e) { 1249 // noop 1250 } 1251 } 1252 m_functionReferences.add(new CmsFunctionReference(name, functionId, functionDefaultPageId, order)); 1253 } 1254 1255 /** 1256 * Parses a single field definition from a content value.<p> 1257 * 1258 * @param field the content value to parse the field from 1259 * @param mode the property discard mode 1260 */ 1261 private void parseProperty(I_CmsXmlContentLocation field, DiscardPropertiesMode mode) { 1262 1263 CmsPropertyConfig propConfig = parseProperty(m_cms, field); 1264 if (CmsStringUtil.isEmptyOrWhitespaceOnly(propConfig.getName())) { 1265 return; 1266 } 1267 if (mode == DiscardPropertiesMode.top) { 1268 propConfig = propConfig.cloneWithTop(true); 1269 } 1270 m_propertyConfigs.add(propConfig); 1271 } 1272 1273 /** 1274 * Helper method for reading the target ids from a list of internal links two levels nested. 1275 * 1276 * @param root the parent location 1277 * @param childName the node name for the children 1278 * @param grandchildName the node name for the grandchildren 1279 * 1280 * @return the set of target ids collected from the grandchildren 1281 */ 1282 private Set<CmsUUID> readInternalLinkListTargetIds( 1283 I_CmsXmlContentLocation root, 1284 String childName, 1285 String grandchildName) { 1286 1287 Set<CmsUUID> result = new LinkedHashSet<>(); 1288 for (I_CmsXmlContentValueLocation parent : root.getSubValues(childName)) { 1289 for (I_CmsXmlContentValueLocation node : parent.getSubValues(grandchildName)) { 1290 CmsXmlVfsFileValue value = (CmsXmlVfsFileValue)node.getValue(); 1291 CmsLink link = value.getLink(m_cms); 1292 if (link != null) { 1293 CmsUUID structureId = link.getStructureId(); 1294 if (structureId != null) { 1295 result.add(link.getStructureId()); 1296 } 1297 } 1298 } 1299 } 1300 return result; 1301 } 1302 1303 /** 1304 * Reads the local macro or flex formatters from the .formatters folder if present.<p> 1305 * 1306 * @param node the xml content node 1307 * 1308 * @return the local formatters 1309 */ 1310 private Set<String> readLocalFormatters(I_CmsXmlContentLocation node) { 1311 1312 Set<String> addFormatters = new HashSet<String>(); 1313 String path = m_cms.getSitePath(node.getDocument().getFile()); 1314 path = CmsStringUtil.joinPaths(CmsResource.getParentFolder(path), ".formatters"); 1315 try { 1316 if (m_cms.existsResource(path, CmsResourceFilter.IGNORE_EXPIRATION)) { 1317 I_CmsResourceType macroType = OpenCms.getResourceManager().getResourceType( 1318 CmsFormatterConfigurationCache.TYPE_MACRO_FORMATTER); 1319 CmsResourceFilter filter = CmsResourceFilter.IGNORE_EXPIRATION.addRequireType(macroType); 1320 List<CmsResource> macroFormatters = m_cms.readResources(path, filter); 1321 for (CmsResource formatter : macroFormatters) { 1322 addFormatters.add(formatter.getStructureId().toString()); 1323 } 1324 I_CmsResourceType flexType = OpenCms.getResourceManager().getResourceType( 1325 CmsFormatterConfigurationCache.TYPE_FLEX_FORMATTER); 1326 CmsResourceFilter filterFlex = CmsResourceFilter.IGNORE_EXPIRATION.addRequireType(flexType); 1327 List<CmsResource> flexFormatters = m_cms.readResources(path, filterFlex); 1328 for (CmsResource formatter : flexFormatters) { 1329 addFormatters.add(formatter.getStructureId().toString()); 1330 } 1331 } 1332 } catch (CmsException e) { 1333 LOG.warn(e.getMessage(), e); 1334 } 1335 return addFormatters; 1336 } 1337 1338}