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 /** The Plugin node name. */ 267 public static final String N_PLUGIN = "Plugin"; 268 269 /** The PreferDetailPagesForLocalContents node name. */ 270 public static final String N_PREFER_DETAIL_PAGES_FOR_LOCAL_CONTENTS = "PreferDetailPagesForLocalContents"; 271 272 /** The prefer folder node name. */ 273 public static final String N_PREFER_FOLDER = "PreferFolder"; 274 275 /** The property node name. */ 276 public static final String N_PROPERTY = "Property"; 277 278 /** The property name node name. */ 279 public static final String N_PROPERTY_NAME = "PropertyName"; 280 281 /** XML node name. */ 282 public static final String N_PROPERTY_NAME_ALIAS = "PropertyNameAlias"; 283 284 /** Node name for the "Remove all formatters"-option. */ 285 public static final String N_REMOVE_ALL_FORMATTERS = "RemoveAllFormatters"; 286 287 /** Field name for the 'Remove all functions' setting. */ 288 public static final String N_REMOVE_ALL_FUNCTIONS = "RemoveAllFunctions"; 289 290 /** The RemoveAllPlugins node name. */ 291 public static final String N_REMOVE_ALL_PLUGINS = "RemoveAllPlugins"; 292 293 /** The RemoveAllSharedSettingOverrides node name. */ 294 public static final String N_REMOVE_ALL_SHARED_SETTING_OVERRIDES = "RemoveAllSharedSettingOverrides"; 295 296 /** Node name for removed formatters. */ 297 public static final String N_REMOVE_FORMATTER = "RemoveFormatter"; 298 299 /** Node name for the nested content with the removed formatters. */ 300 public static final String N_REMOVE_FORMATTERS = "RemoveFormatters"; 301 302 /** The remove function node name. */ 303 public static final String N_REMOVE_FUNCTIONS = "RemoveFunctions"; 304 305 /** The RemovePlugin node name. */ 306 public static final String N_REMOVE_PLUGIN = "RemovePlugin"; 307 308 /** The RemovePlugins node name. */ 309 public static final String N_REMOVE_PLUGINS = "RemovePlugins"; 310 311 /** The resource type node name. */ 312 public static final String N_RESOURCE_TYPE = "ResourceType"; 313 314 /** The regex rule node name. */ 315 public static final String N_RULE_REGEX = "RuleRegex"; 316 317 /** The rule type node name. */ 318 public static final String N_RULE_TYPE = "RuleType"; 319 320 /** The SharedSettingOverride node name. */ 321 public static final String N_SHARED_SETTING_OVERRIDE = "SharedSettingOverride"; 322 323 /** The ShowInDefaultView node name. */ 324 public static final String N_SHOW_IN_DEFAULT_VIEW = "ShowInDefaultView"; 325 326 /** The type node name. */ 327 public static final String N_TYPE = "Type"; 328 329 /** The type name node name. */ 330 public static final String N_TYPE_NAME = "TypeName"; 331 332 /** The node name for the type ordering mode. */ 333 public static final String N_TYPE_ORDERING_MODE = "TypeOrderingMode"; 334 335 /** Node name. */ 336 public static final String N_USE_FORMATTER_KEYS = "UseFormatterKeys"; 337 338 /** The Value node name. */ 339 public static final String N_VALUE = "Value"; 340 341 /** XML node name. */ 342 public static final String N_VALUE_TRANSLATION = "ValueTranslation"; 343 344 /** The widget node name. */ 345 public static final String N_VISIBILITY = "Visibility"; 346 347 /** The widget node name. */ 348 public static final String N_WIDGET = "Widget"; 349 350 /** The widget configuration node name. */ 351 public static final String N_WIDGET_CONFIG = "WidgetConfig"; 352 353 /** Scheme for explorer type view links. */ 354 public static final String VIEW_SCHEME = "view://"; 355 356 /** The log object for this class. */ 357 private static final Log LOG = CmsLog.getLog(CmsConfigurationReader.class); 358 359 /** The ElementDeleteMode node name. */ 360 private static final String N_ELEMENT_DELETE_MODE = "ElementDeleteMode"; 361 362 /** The CMS context used for reading the configuration data. */ 363 private CmsObject m_cms; 364 365 /** The parsed detail page configuration elements. */ 366 private List<CmsDetailPageInfo> m_detailPageConfigs = new ArrayList<CmsDetailPageInfo>(); 367 368 /** The list of configured function references. */ 369 private List<CmsFunctionReference> m_functionReferences = new ArrayList<CmsFunctionReference>(); 370 371 /** The parsed model page configuration elements. */ 372 private List<CmsModelPageConfigWithoutResource> m_modelPageConfigs = new ArrayList<CmsModelPageConfigWithoutResource>(); 373 374 /** The parsed property configuration elements. */ 375 private List<CmsPropertyConfig> m_propertyConfigs = new ArrayList<CmsPropertyConfig>(); 376 377 /** The resource type configuration objects. */ 378 private List<CmsResourceTypeConfig> m_resourceTypeConfigs = new ArrayList<CmsResourceTypeConfig>(); 379 380 /** 381 * Creates a new configuration reader.<p> 382 * 383 * @param cms the CMS context which should be used to read the configuration data.<p> 384 */ 385 public CmsConfigurationReader(CmsObject cms) { 386 387 m_cms = cms; 388 } 389 390 /** 391 * Gets the string value of an XML content location.<p> 392 * 393 * @param cms the CMS context to use 394 * @param location an XML content location 395 * 396 * @return the string value of that XML content location 397 */ 398 public static String getString(CmsObject cms, I_CmsXmlContentValueLocation location) { 399 400 if (location == null) { 401 return null; 402 } 403 return location.asString(cms); 404 } 405 406 /** 407 * Helper method to parse a property.<p> 408 * 409 * @param cms the CMS context to use 410 * @param field the location of the parent value 411 * 412 * @return the parsed property configuration 413 */ 414 public static CmsPropertyConfig parseProperty(CmsObject cms, I_CmsXmlContentLocation field) { 415 416 String name = getString(cms, field.getSubValue(N_PROPERTY_NAME)); 417 String includeName = getString(cms, field.getSubValue(N_INCLUDE_NAME)); 418 String widget = getString(cms, field.getSubValue(N_WIDGET)); 419 String widgetConfig = getString(cms, field.getSubValue(N_WIDGET_CONFIG)); 420 String ruleRegex = getString(cms, field.getSubValue(N_RULE_REGEX)); 421 String ruleType = getString(cms, field.getSubValue(N_RULE_TYPE)); 422 String default1 = getString(cms, field.getSubValue(N_DEFAULT)); 423 String error = getString(cms, field.getSubValue(N_ERROR)); 424 String niceName = getString(cms, field.getSubValue(N_DISPLAY_NAME)); 425 String description = getString(cms, field.getSubValue(N_DESCRIPTION)); 426 String preferFolder = getString(cms, field.getSubValue(N_PREFER_FOLDER)); 427 String aliasName = getString(cms, field.getSubValue(N_PROPERTY_NAME_ALIAS)); 428 String valueTranslations = getString(cms, field.getSubValue(N_VALUE_TRANSLATION)); 429 430 String disabledStr = getString(cms, field.getSubValue(N_DISABLED)); 431 boolean disabled = ((disabledStr != null) && Boolean.parseBoolean(disabledStr)); 432 433 String orderStr = getString(cms, field.getSubValue(N_ORDER)); 434 int order = I_CmsConfigurationObject.DEFAULT_ORDER; 435 436 try { 437 order = Integer.parseInt(orderStr); 438 } catch (NumberFormatException e) { 439 // noop 440 } 441 442 Visibility visibility; 443 String visibilityStr = getString(cms, field.getSubValue(N_VISIBILITY)); 444 try { 445 // to stay compatible with former visibility option values 446 if ("both".equals(visibilityStr)) { 447 visibilityStr = Visibility.elementAndParentIndividual.name(); 448 } else if ("parent".equals(visibilityStr)) { 449 visibilityStr = Visibility.parentShared.name(); 450 } 451 visibility = Visibility.valueOf(visibilityStr); 452 } catch (Exception e) { 453 visibility = null; 454 } 455 CmsXmlContentProperty prop = new CmsXmlContentProperty( 456 name, 457 aliasName, 458 "string", 459 visibility, 460 widget, 461 widgetConfig, 462 ruleRegex, 463 ruleType, 464 default1, 465 niceName, 466 description, 467 error, 468 preferFolder, 469 valueTranslations).withIncludeName(includeName); 470 // since these are real properties, using type vfslist makes no sense, so we always use the "string" type 471 CmsPropertyConfig propConfig = new CmsPropertyConfig(prop, disabled, order); 472 return propConfig; 473 474 } 475 476 /** 477 * Returns the list of function references.<p> 478 * 479 * @return the list of function references 480 */ 481 public List<CmsFunctionReference> getFunctionReferences() { 482 483 return new ArrayList<CmsFunctionReference>(m_functionReferences); 484 } 485 486 /** 487 * Returns the modelPageConfigs.<p> 488 * 489 * @return the modelPageConfigs 490 */ 491 public List<CmsModelPageConfigWithoutResource> getModelPageConfigs() { 492 493 return m_modelPageConfigs; 494 } 495 496 /** 497 * Parses the formatters to add.<p> 498 * 499 * @param node the parent node 500 * @return the set of keys of the formatters to add 501 */ 502 public Set<String> parseAddFormatters(I_CmsXmlContentLocation node) { 503 504 Set<String> addFormatters = new HashSet<String>(); 505 for (I_CmsXmlContentValueLocation addLoc : node.getSubValues(N_ADD_FORMATTERS + "/" + N_ADD_FORMATTER)) { 506 CmsXmlVfsFileValue value = (CmsXmlVfsFileValue)addLoc.getValue(); 507 CmsLink link = value.getLink(m_cms); 508 if (link != null) { 509 CmsUUID structureId = link.getStructureId(); 510 if (structureId != null) { 511 addFormatters.add(structureId.toString()); 512 } 513 } 514 } 515 return addFormatters; 516 } 517 518 /** 519 * Parses a configuration XML content and creates a configuration object from it.<p> 520 * 521 * @param basePath the base path 522 * @param content the XML content 523 * 524 * @return the created configuration object with the data from the XML content 525 * @throws CmsException if something goes wrong 526 */ 527 public CmsADEConfigDataInternal parseConfiguration(String basePath, CmsXmlContent content) throws CmsException { 528 529 m_detailPageConfigs = Lists.newArrayList(); 530 m_functionReferences = Lists.newArrayList(); 531 m_modelPageConfigs = Lists.newArrayList(); 532 m_propertyConfigs = Lists.newArrayList(); 533 m_resourceTypeConfigs = Lists.newArrayList(); 534 CmsUUID baseId = null; 535 if (basePath != null) { 536 try { 537 CmsResource folderRes = m_cms.readResource(basePath, CmsResourceFilter.IGNORE_EXPIRATION); 538 baseId = folderRes.getStructureId(); 539 } catch (Exception e) { 540 LOG.error(e.getLocalizedMessage(), e); 541 } 542 } 543 if (!content.hasLocale(DEFAULT_LOCALE)) { 544 return CmsADEConfigDataInternal.emptyConfiguration(basePath); 545 } 546 CmsXmlContentRootLocation root = new CmsXmlContentRootLocation(content, DEFAULT_LOCALE); 547 for (I_CmsXmlContentValueLocation node : root.getSubValues(N_RESOURCE_TYPE)) { 548 try { 549 parseResourceTypeConfig(basePath, node); 550 } catch (CmsException e) { 551 LOG.warn(e.getLocalizedMessage(), e); 552 } 553 } 554 for (I_CmsXmlContentValueLocation node : root.getSubValues(N_MODEL_PAGE)) { 555 try { 556 parseModelPage(node); 557 } catch (Exception e) { 558 LOG.warn(e.getLocalizedMessage(), e); 559 } 560 } 561 for (I_CmsXmlContentLocation node : root.getSubValues(N_DETAIL_PAGE)) { 562 try { 563 parseDetailPage(node); 564 } catch (Exception e) { 565 LOG.warn(e.getLocalizedMessage(), e); 566 } 567 } 568 569 for (I_CmsXmlContentLocation node : root.getSubValues(N_FUNCTION_REF)) { 570 parseFunctionReference(node); 571 } 572 573 CmsUUID sharedSettingOverride = null; 574 for (I_CmsXmlContentValueLocation node : root.getSubValues(N_SHARED_SETTING_OVERRIDE)) { 575 sharedSettingOverride = ((CmsXmlVfsFileValue)node.getValue()).getLink(m_cms).getStructureId(); 576 } 577 578 boolean removeSharedSettingOverrides = getBoolean(root, N_REMOVE_ALL_SHARED_SETTING_OVERRIDES); 579 580 boolean removeFunctions = false; 581 removeFunctions = getBoolean(root, N_REMOVE_ALL_FUNCTIONS); 582 583 Set<CmsUUID> functions = new LinkedHashSet<>(); 584 for (I_CmsXmlContentValueLocation node : root.getSubValues(N_FUNCTION)) { 585 CmsXmlVfsFileValue value = (CmsXmlVfsFileValue)node.getValue(); 586 CmsLink link = value.getLink(m_cms); 587 if (link != null) { 588 CmsUUID structureId = link.getStructureId(); 589 if (structureId != null) { 590 functions.add(link.getStructureId()); 591 } 592 } 593 } 594 595 Set<CmsUUID> functionsToRemove = new LinkedHashSet<>(); 596 for (I_CmsXmlContentValueLocation parent : root.getSubValues(N_REMOVE_FUNCTIONS)) { 597 for (I_CmsXmlContentValueLocation node : parent.getSubValues(N_FUNCTION)) { 598 CmsXmlVfsFileValue value = (CmsXmlVfsFileValue)node.getValue(); 599 CmsLink link = value.getLink(m_cms); 600 if (link != null) { 601 CmsUUID structureId = link.getStructureId(); 602 if (structureId != null) { 603 functionsToRemove.add(link.getStructureId()); 604 } 605 } 606 } 607 } 608 609 boolean removeAllPlugins = getBoolean(root, N_REMOVE_ALL_PLUGINS); 610 Set<CmsUUID> pluginsToRemove = readInternalLinkListTargetIds(root, N_REMOVE_PLUGINS, N_PLUGIN); 611 Set<CmsUUID> pluginsToAdd = readInternalLinkListTargetIds(root, N_ADD_PLUGINS, N_PLUGIN); 612 613 boolean removeAllFormatters = getBoolean(root, N_REMOVE_ALL_FORMATTERS); 614 CmsFormatterChangeSet formatterChangeSet = parseFormatterChangeSet( 615 basePath, 616 root, 617 removeAllFormatters, 618 removeFunctions, 619 functions, 620 functionsToRemove); 621 boolean discardInheritedTypes = getBoolean(root, N_DISCARD_TYPES); 622 // boolean discardInheritedProperties = getBoolean(root, N_DISCARD_PROPERTIES); 623 I_CmsXmlContentValueLocation discardPropertiesLoc = root.getSubValue(N_DISCARD_PROPERTIES); 624 DiscardPropertiesMode discardPropertiesMode = DiscardPropertiesMode.keep; 625 if (discardPropertiesLoc != null) { 626 String discardPropertiesStr = discardPropertiesLoc.getValue().getStringValue(m_cms); 627 for (DiscardPropertiesMode discardMode : DiscardPropertiesMode.values()) { 628 if (discardMode.getStringValue().contentEquals(discardPropertiesStr)) { 629 discardPropertiesMode = discardMode; 630 } 631 } 632 } 633 for (I_CmsXmlContentLocation node : root.getSubValues(N_PROPERTY)) { 634 parseProperty(node, discardPropertiesMode); 635 } 636 637 boolean discardInheritedModelPages = getBoolean(root, N_DISCARD_MODEL_PAGES); 638 639 boolean createContentsLocally = getBoolean(root, N_CREATE_CONTENTS_LOCALLY); 640 CmsContentFolderOption contentFolderOption = null; 641 for (I_CmsXmlContentValueLocation contentFolderLoc : root.getSubValues(N_CONTENT_FOLDER)) { 642 contentFolderOption = parseContentFolderOption(contentFolderLoc); 643 } 644 boolean preferDetailPagesForLocalContents = getBoolean(root, N_PREFER_DETAIL_PAGES_FOR_LOCAL_CONTENTS); 645 boolean exludeExternalDetailContents = getBoolean(root, N_EXCLUDE_EXTERNAL_DETAIL_CONTENTS); 646 boolean includeInSiteSelector = getBoolean(root, N_INCLUDE_IN_SITE_SELECTOR); 647 648 String galleryDisabledTypesStr = getString(root.getSubValue(N_DISABLED_TYPES_MODE)); 649 CmsGalleryDisabledTypesMode galleryDisabledTypesMode = null; 650 if (galleryDisabledTypesStr != null) { 651 galleryDisabledTypesMode = CmsGalleryDisabledTypesMode.valueOf(galleryDisabledTypesStr); 652 } 653 654 String galleryDisabledFunctionsStr = getString(root.getSubValue(N_DISABLED_FUNCTIONS_MODE)); 655 CmsGalleryDisabledTypesMode galleryDisabledFunctionsMode = null; 656 if (galleryDisabledFunctionsStr != null) { 657 galleryDisabledFunctionsMode = CmsGalleryDisabledTypesMode.valueOf(galleryDisabledFunctionsStr); 658 } 659 660 I_CmsXmlContentValueLocation typeOrderingLoc = root.getSubValue(N_TYPE_ORDERING_MODE); 661 CmsTypeOrderingMode typeOrderingMode = null; 662 if (typeOrderingLoc != null) { 663 boolean byDisplayOrder = Boolean.parseBoolean(typeOrderingLoc.getValue().getStringValue(m_cms)); 664 typeOrderingMode = byDisplayOrder ? CmsTypeOrderingMode.byDisplayOrder : CmsTypeOrderingMode.latestOnTop; 665 } 666 667 I_CmsXmlContentValueLocation useFormatterKeysLoc = root.getSubValue(N_USE_FORMATTER_KEYS); 668 Boolean useFormatterKeys = null; 669 if (useFormatterKeysLoc != null) { 670 useFormatterKeys = Boolean.valueOf(useFormatterKeysLoc.getValue().getStringValue(m_cms)); 671 } 672 673 boolean isModuleConfig = OpenCms.getResourceManager().getResourceType( 674 content.getFile().getTypeId()).getTypeName().equals(CmsADEManager.MODULE_CONFIG_TYPE); 675 676 List<ConfigReference> masterConfigIds = new ArrayList<>(); 677 for (I_CmsXmlContentValueLocation masterConfigLoc : root.getSubValues(N_MASTER_CONFIG)) { 678 CmsXmlVfsFileValue value = (CmsXmlVfsFileValue)masterConfigLoc.getValue(); 679 CmsLink link = value.getUncheckedLink(); 680 ConfigReferenceMeta meta = null; 681 if (link != null) { 682 meta = new ConfigReferenceMeta(link.getParameterMap()); 683 } 684 CmsUUID id = masterConfigLoc.asId(m_cms); 685 if (id != null) { 686 masterConfigIds.add(new ConfigReference(id, meta)); 687 } 688 } 689 690 Map<String, String> attributes = new LinkedHashMap<>(); 691 for (I_CmsXmlContentValueLocation mappingLoc : root.getSubValues(N_ATTRIBUTE)) { 692 String key = getString(mappingLoc.getSubValue(N_KEY)).trim(); 693 String value = getString(mappingLoc.getSubValue(N_VALUE)).trim(); 694 attributes.put(key, value); 695 } 696 697 I_CmsXmlContentValueLocation attributeEditorConfigLoc = root.getSubValue(N_ATTRIBUTE_EDITOR_CONFIG); 698 CmsUUID attributeEditorConfigId = null; 699 if (attributeEditorConfigLoc != null) { 700 attributeEditorConfigId = attributeEditorConfigLoc.asId(m_cms); 701 } 702 703 CmsAddContentRestriction addContentRestriction = CmsAddContentRestriction.read( 704 m_cms, 705 root, 706 N_ADD_CONTENT_RESTRICTION); 707 708 CmsADEConfigDataInternal result = new CmsADEConfigDataInternal( 709 m_cms, 710 content.getFile(), 711 isModuleConfig, 712 basePath, 713 baseId, 714 masterConfigIds, 715 m_resourceTypeConfigs, 716 galleryDisabledTypesMode, 717 galleryDisabledFunctionsMode, 718 discardInheritedTypes, 719 m_propertyConfigs, 720 discardPropertiesMode, 721 m_detailPageConfigs, 722 m_modelPageConfigs, 723 m_functionReferences, 724 discardInheritedModelPages, 725 createContentsLocally, 726 contentFolderOption, 727 preferDetailPagesForLocalContents, 728 exludeExternalDetailContents, 729 includeInSiteSelector, 730 formatterChangeSet, 731 removeFunctions, 732 functions, 733 functionsToRemove, 734 removeAllPlugins, 735 pluginsToAdd, 736 pluginsToRemove, 737 useFormatterKeys, 738 typeOrderingMode, 739 addContentRestriction, 740 sharedSettingOverride, 741 removeSharedSettingOverrides, 742 attributeEditorConfigId, 743 attributes); 744 return result; 745 } 746 747 /** 748 * Parses the content folder configuration. 749 * 750 * @param location the XML content location from which to read the data. 751 * 752 * @return the content folder configuration 753 */ 754 public CmsContentFolderOption parseContentFolderOption(I_CmsXmlContentLocation location) { 755 756 if (location == null) { 757 return null; 758 } 759 I_CmsXmlContentValueLocation defaultLoc = location.getSubValue(N_DEFAULT); 760 I_CmsXmlContentValueLocation pathLoc = location.getSubValue(N_PATH); 761 if (defaultLoc != null) { 762 return new CmsContentFolderOption(null); 763 } 764 if (pathLoc != null) { 765 CmsXmlVfsFileValue value = (CmsXmlVfsFileValue)pathLoc.getValue(); 766 if ((value.getUncheckedLink() != null) && (value.getUncheckedLink().getStructureId() != null)) { 767 768 return new CmsContentFolderOption(value.getUncheckedLink().getStructureId()); 769 } 770 } 771 if (LOG.isWarnEnabled()) { 772 LOG.warn(location.getDocument().getFile().getRootPath() + ": invalid content folder"); 773 } 774 return null; 775 } 776 777 /** 778 * Parses a folder which may either be given as a path or as a folder name.<p> 779 * 780 * @param basePath the base path for the configuration 781 * @param location the XML content node from which to parse the folder 782 * @return the folder bean 783 * 784 * @throws CmsException if something goes wrong 785 */ 786 public CmsContentFolderDescriptor parseFolderOrName(String basePath, I_CmsXmlContentLocation location) 787 throws CmsException { 788 789 if (location == null) { 790 return null; 791 } 792 I_CmsXmlContentValueLocation nameLoc = location.getSubValue(N_NAME); 793 I_CmsXmlContentValueLocation pathLoc = location.getSubValue(N_PATH); 794 I_CmsXmlContentValueLocation pageRelativeLoc = location.getSubValue(N_PAGE_RELATIVE); 795 if (nameLoc != null) { 796 String name = nameLoc.asString(m_cms); 797 return new CmsContentFolderDescriptor( 798 basePath == null ? null : CmsStringUtil.joinPaths(basePath, CmsADEManager.CONTENT_FOLDER_NAME), 799 name); 800 } else if (pathLoc != null) { 801 String path = pathLoc.asString(m_cms); 802 CmsResource folder = m_cms.readResource(path); 803 return new CmsContentFolderDescriptor(folder); 804 } else if (pageRelativeLoc != null) { 805 return CmsContentFolderDescriptor.createPageRelativeFolderDescriptor(); 806 } else { 807 return null; 808 } 809 } 810 811 /** 812 * Parses a formatter bean.<p> 813 * 814 * @param typeName the type name for which the formatter is being parsed 815 * @param node the node from which to parse the formatter data 816 * 817 * @return the formatter bean from the XML 818 */ 819 public CmsFormatterBean parseFormatter(String typeName, I_CmsXmlContentLocation node) { 820 821 String type = getString(node.getSubValue(N_TYPE)); 822 String minWidth = getString(node.getSubValue(N_MIN_WIDTH)); 823 String maxWidth = getString(node.getSubValue(N_MAX_WIDTH)); 824 boolean preview = false; 825 I_CmsXmlContentValueLocation previewLoc = node.getSubValue(N_IS_PREVIEW); 826 preview = (previewLoc != null) && Boolean.parseBoolean(previewLoc.asString(m_cms)); 827 String jsp = m_cms.getRequestContext().addSiteRoot(getString(node.getSubValue(N_JSP))); 828 boolean searchContent = true; 829 CmsFormatterBean formatterBean = new CmsFormatterBean( 830 type, 831 jsp, 832 minWidth, 833 maxWidth, 834 "" + preview, 835 "" + searchContent, 836 null); 837 return formatterBean; 838 839 } 840 841 /** 842 * Parses model page data from the XML content.<p> 843 * 844 * @param node the XML content node 845 */ 846 public void parseModelPage(I_CmsXmlContentLocation node) { 847 848 CmsXmlVfsFileValue pageValue = (CmsXmlVfsFileValue)node.getSubValue(N_PAGE).getValue(); 849 CmsLink link = pageValue.getUncheckedLink(); 850 if ((link == null) || (link.getStructureId() == null)) { 851 return; 852 } 853 I_CmsXmlContentValueLocation disabledLoc = node.getSubValue(N_DISABLED); 854 boolean disabled = (disabledLoc != null) && Boolean.parseBoolean(disabledLoc.asString(m_cms)); 855 I_CmsXmlContentValueLocation defaultLoc = node.getSubValue(N_IS_DEFAULT); 856 boolean isDefault = (defaultLoc != null) && Boolean.parseBoolean(defaultLoc.asString(m_cms)); 857 CmsModelPageConfigWithoutResource modelPage = new CmsModelPageConfigWithoutResource( 858 link.getStructureId(), 859 isDefault, 860 disabled); 861 m_modelPageConfigs.add(modelPage); 862 863 } 864 865 /** 866 * Parses the set of formatters to remove.<p> 867 * 868 * @param node the parent node 869 * @return the set of formatters to remove 870 */ 871 public Set<String> parseRemoveFormatters(I_CmsXmlContentLocation node) { 872 873 Set<String> removeFormatters = new HashSet<String>(); 874 for (I_CmsXmlContentValueLocation removeLoc : node.getSubValues( 875 N_REMOVE_FORMATTERS + "/" + N_REMOVE_FORMATTER)) { 876 CmsXmlVfsFileValue value = (CmsXmlVfsFileValue)removeLoc.getValue(); 877 CmsLink link = value.getLink(m_cms); 878 if (link != null) { 879 CmsUUID structureId = link.getStructureId(); 880 if (structureId != null) { 881 removeFormatters.add(structureId.toString()); 882 } 883 } 884 } 885 return removeFormatters; 886 } 887 888 /** 889 * Parses a resource type configuration element from the XML content.<p> 890 * 891 * @param basePath the base path of the configuration 892 * @param node the XML configuration node 893 * @throws CmsException if something goes wrong 894 */ 895 public void parseResourceTypeConfig(String basePath, I_CmsXmlContentLocation node) throws CmsException { 896 897 I_CmsXmlContentValueLocation typeNameLoc = node.getSubValue(N_TYPE_NAME); 898 String typeName = typeNameLoc.asString(m_cms); 899 CmsContentFolderDescriptor folderOrName = parseFolderOrName(basePath, node.getSubValue(N_FOLDER)); 900 I_CmsXmlContentValueLocation disabledLoc = node.getSubValue(N_DISABLED); 901 boolean disabled = false; 902 boolean addDisabled = false; 903 boolean createDisabled = false; 904 boolean editDisabled = false; 905 boolean listsOnly = false; 906 String disabledStr = disabledLoc == null ? null : disabledLoc.asString(m_cms); 907 boolean availabilityNotSet = false; 908 if (disabledStr != null) { 909 if ("add".equalsIgnoreCase(disabledStr.trim())) { 910 addDisabled = true; 911 } else if ("create".equalsIgnoreCase(disabledStr.trim())) { 912 createDisabled = true; 913 } else if ("createOrEdit".equalsIgnoreCase(disabledStr.trim())) { 914 createDisabled = true; 915 editDisabled = true; 916 } else if ("listsOnly".equalsIgnoreCase(disabledStr.trim())) { 917 listsOnly = true; 918 addDisabled = true; 919 } else { 920 disabled = Boolean.parseBoolean(disabledStr); 921 } 922 } else { 923 availabilityNotSet = true; 924 } 925 926 I_CmsXmlContentValueLocation namePatternLoc = node.getSubValue(N_NAME_PATTERN); 927 String namePattern = null; 928 if (namePatternLoc != null) { 929 namePattern = namePatternLoc.asString(m_cms); 930 } 931 932 boolean detailPagesDisabled = false; 933 I_CmsXmlContentValueLocation detailDisabledLoc = node.getSubValue(N_DETAIL_PAGES_DISABLED); 934 if (detailDisabledLoc != null) { 935 String detailPagesDisabledStr = detailDisabledLoc.asString(m_cms); 936 detailPagesDisabled = Boolean.parseBoolean(detailPagesDisabledStr); 937 } 938 939 Integer order = null; 940 I_CmsXmlContentValueLocation orderLoc = node.getSubValue(N_ORDER); 941 if (orderLoc != null) { 942 try { 943 String orderStr = orderLoc.asString(m_cms); 944 order = Integer.valueOf(orderStr); 945 } catch (NumberFormatException e) { 946 // noop 947 } 948 } 949 950 I_CmsXmlContentValueLocation elementViewLoc = node.getSubValue(N_ELEMENT_VIEW); 951 CmsUUID elementView = null; 952 if (elementViewLoc != null) { 953 try { 954 CmsXmlVarLinkValue elementViewValue = (CmsXmlVarLinkValue)elementViewLoc.getValue(); 955 String stringValue = elementViewValue.getStringValue(m_cms); 956 if ("".equals(stringValue)) { 957 elementView = CmsUUID.getNullUUID(); 958 } else if (stringValue.startsWith(VIEW_SCHEME)) { 959 elementView = new CmsUUID(stringValue.substring(VIEW_SCHEME.length())); 960 } else { 961 elementView = elementViewValue.getLink(m_cms).getStructureId(); 962 } 963 } catch (Exception e) { 964 // in case parsing the link fails, the default element view will be used 965 } 966 } 967 968 I_CmsXmlContentValueLocation locationLoc = node.getSubValue(N_LOCALIZATION); 969 String localization = null; 970 if (locationLoc != null) { 971 CmsXmlVfsFileValue locationValue = (CmsXmlVfsFileValue)locationLoc.getValue(); 972 CmsLink link = locationValue.getLink(m_cms); 973 if (null != link) { 974 String stringValue = link.getSitePath(m_cms); 975 // extract bundle base name from the path to the bundle file 976 int lastSlashIndex = stringValue.lastIndexOf("/"); 977 String fileName = stringValue.substring(lastSlashIndex + 1); 978 if (CmsFileUtil.getExtension(fileName).equals(".properties")) { 979 fileName = fileName.substring(0, fileName.length() - ".properties".length()); 980 } 981 String localeSuffix = CmsStringUtil.getLocaleSuffixForName(fileName); 982 if ((localeSuffix != null) && fileName.endsWith(localeSuffix)) { 983 fileName = fileName.substring(0, fileName.length() - localeSuffix.length() - 1); 984 } 985 localization = fileName; 986 } 987 } 988 989 I_CmsXmlContentValueLocation showDefaultViewLoc = node.getSubValue(N_SHOW_IN_DEFAULT_VIEW); 990 Boolean showInDefaultView = null; 991 if (showDefaultViewLoc != null) { 992 showInDefaultView = Boolean.valueOf( 993 Boolean.parseBoolean(showDefaultViewLoc.getValue().getStringValue(m_cms))); 994 } 995 996 I_CmsXmlContentValueLocation copyInModelsLoc = node.getSubValue(N_COPY_IN_MODELS); 997 Boolean copyInModels = null; 998 if (copyInModelsLoc != null) { 999 copyInModels = Boolean.valueOf(Boolean.parseBoolean(copyInModelsLoc.getValue().getStringValue(m_cms))); 1000 } 1001 1002 I_CmsXmlContentValueLocation elementDeleteModeLoc = node.getSubValue(N_ELEMENT_DELETE_MODE); 1003 ElementDeleteMode elementDeleteMode = null; 1004 if (elementDeleteModeLoc != null) { 1005 try { 1006 elementDeleteMode = ElementDeleteMode.valueOf(elementDeleteModeLoc.getValue().getStringValue(m_cms)); 1007 } catch (Exception e) { 1008 LOG.warn(e.getLocalizedMessage(), e); 1009 } 1010 } 1011 1012 I_CmsXmlContentValueLocation checkReuseLoc = node.getSubValue(N_CHECK_REUSE); 1013 Boolean checkReuse = null; 1014 if (checkReuseLoc != null) { 1015 try { 1016 checkReuse = Boolean.valueOf(checkReuseLoc.getValue().getStringValue(m_cms)); 1017 } catch (Exception e) { 1018 LOG.warn(e.getLocalizedMessage(), e); 1019 } 1020 } 1021 1022 List<I_CmsFormatterBean> formatters = new ArrayList<I_CmsFormatterBean>(); 1023 for (I_CmsXmlContentValueLocation formatterLoc : node.getSubValues(N_FORMATTER)) { 1024 CmsFormatterBean formatter = parseFormatter(typeName, formatterLoc); 1025 formatters.add(formatter); 1026 } 1027 1028 CmsResourceTypeConfig typeConfig = new CmsResourceTypeConfig( 1029 typeName, 1030 disabled, 1031 folderOrName, 1032 namePattern, 1033 detailPagesDisabled, 1034 addDisabled, 1035 createDisabled, 1036 editDisabled, 1037 listsOnly, 1038 availabilityNotSet, 1039 elementView, 1040 localization, 1041 showInDefaultView, 1042 copyInModels, 1043 order, 1044 elementDeleteMode, 1045 checkReuse); 1046 m_resourceTypeConfigs.add(typeConfig); 1047 } 1048 1049 /** 1050 * Parses the sitemap configuration given the configuration file and base path.<p> 1051 * 1052 * @param basePath the base path 1053 * @param configRes the configuration file resource 1054 * @return the parsed configuration data 1055 * @throws CmsException if something goes wrong 1056 */ 1057 public CmsADEConfigDataInternal parseSitemapConfiguration(String basePath, CmsResource configRes) 1058 throws CmsException { 1059 1060 LOG.info("Parsing configuration " + configRes.getRootPath()); 1061 CmsFile configFile = m_cms.readFile(configRes); 1062 CmsXmlContent content = CmsXmlContentFactory.unmarshal(m_cms, configFile); 1063 return parseConfiguration(basePath, content); 1064 } 1065 1066 /** 1067 * Reads the configurations of all modules and combines them into a single configuration object.<p> 1068 * 1069 * @return the combined configuration object 1070 */ 1071 public List<CmsADEConfigDataInternal> readModuleConfigurations() { 1072 1073 List<CmsADEConfigDataInternal> configurations = new ArrayList<CmsADEConfigDataInternal>(); 1074 List<CmsModule> modules = OpenCms.getModuleManager().getAllInstalledModules(); 1075 long beginTime = System.currentTimeMillis(); 1076 for (CmsModule module : modules) { 1077 String configPath = module.getConfigurationPath(); 1078 if (m_cms.existsResource(configPath)) { 1079 try { 1080 CmsResource configFile = m_cms.readResource(configPath); 1081 LOG.info("Found module configuration " + configPath + " for module " + module.getName()); 1082 CmsADEConfigDataInternal config = parseSitemapConfiguration(null, configFile); 1083 configurations.add(config); 1084 } catch (CmsException e) { 1085 // errors while parsing configuration 1086 LOG.error(e.getLocalizedMessage(), e); 1087 } catch (CmsRuntimeException e) { 1088 // may happen during import of org.opencms.ade.configuration module 1089 LOG.warn(e.getLocalizedMessage(), e); 1090 } catch (Throwable e) { 1091 LOG.error(e.getLocalizedMessage(), e); 1092 } 1093 } 1094 } 1095 long endTime = System.currentTimeMillis(); 1096 LOG.debug("readModuleConfiguations took " + (endTime - beginTime) + "ms"); 1097 return configurations; 1098 } 1099 1100 /** 1101 * Helper method to read a boolean value from the XML.<p> 1102 * 1103 * If the element is not found in the XML, false is returned.<p> 1104 * 1105 * @param parent the parent node 1106 * @param name the name of the XML content value 1107 * @return the boolean value 1108 */ 1109 protected boolean getBoolean(I_CmsXmlContentLocation parent, String name) { 1110 1111 I_CmsXmlContentValueLocation location = parent.getSubValue(name); 1112 if (location == null) { 1113 return false; 1114 } 1115 String value = location.getValue().getStringValue(m_cms); 1116 return Boolean.parseBoolean(value); 1117 } 1118 1119 /** 1120 * Gets the string value of an XML content location.<p> 1121 * 1122 * @param location an XML content location 1123 * 1124 * @return the string value of that XML content location 1125 */ 1126 protected String getString(I_CmsXmlContentValueLocation location) { 1127 1128 return getString(m_cms, location); 1129 } 1130 1131 /** 1132 * Parses the detail pages from an XML content node.<p> 1133 * 1134 * @param node the XML content node 1135 */ 1136 protected void parseDetailPage(I_CmsXmlContentLocation node) { 1137 1138 I_CmsXmlContentValueLocation pageLoc = node.getSubValue(N_PAGE); 1139 String typeName = getString(node.getSubValue(N_TYPE)); 1140 int qualifierPos = typeName.indexOf(CmsDetailPageInfo.QUALIFIER_SEPARATOR); 1141 String qualifier = null; 1142 if (qualifierPos != -1) { 1143 qualifier = typeName.substring(qualifierPos + 1); 1144 typeName = typeName.substring(0, qualifierPos); 1145 } 1146 CmsXmlVfsFileValue detailPageValue = (CmsXmlVfsFileValue)pageLoc.getValue(); 1147 CmsLink uncheckedLink = detailPageValue.getUncheckedLink(); 1148 if (uncheckedLink == null) { 1149 LOG.warn( 1150 "Missing detail page link in " + CmsLog.eval(LOG, () -> node.getDocument().getFile().getRootPath())); 1151 return; 1152 } 1153 String page = uncheckedLink.getTarget(); 1154 CmsUUID structureId = uncheckedLink.getStructureId(); 1155 if (structureId == null) { 1156 return; 1157 } 1158 1159 String iconClasses; 1160 if (typeName.startsWith(CmsDetailPageInfo.FUNCTION_PREFIX)) { 1161 iconClasses = CmsIconUtil.getIconClasses(CmsXmlDynamicFunctionHandler.TYPE_FUNCTION, null, false); 1162 } else { 1163 iconClasses = CmsIconUtil.getIconClasses(typeName, null, false); 1164 } 1165 List<CmsUUID> folders = new ArrayList<>(); 1166 for (I_CmsXmlContentValueLocation folderLoc : node.getSubValues(N_FOLDER)) { 1167 CmsXmlVfsFileValue folderValue = (CmsXmlVfsFileValue)folderLoc.getValue(); 1168 CmsLink folderLink = folderValue.getUncheckedLink(); 1169 if ((folderLink != null) && (folderLink.getStructureId() != null)) { 1170 folders.add(folderLink.getStructureId()); 1171 } 1172 } 1173 1174 CmsDetailPageInfo detailPage = new CmsDetailPageInfo( 1175 structureId, 1176 page, 1177 typeName, 1178 qualifier, 1179 folders, 1180 iconClasses); 1181 m_detailPageConfigs.add(detailPage); 1182 1183 } 1184 1185 /** 1186 * Parses the formatter change set.<p> 1187 * 1188 * @param basePath the configuration base path 1189 * @param node the parent node 1190 * @param removeAllFormatters flag, indicating if all formatters that are not explicitly added should be removed 1191 * @param removeFunctions if true, remove functions 1192 * @param functions the functions to add 1193 * @param functionsToRemove the functions to remove 1194 * 1195 * @return the formatter change set 1196 */ 1197 protected CmsFormatterChangeSet parseFormatterChangeSet( 1198 String basePath, 1199 I_CmsXmlContentLocation node, 1200 boolean removeAllFormatters, 1201 boolean removeFunctions, 1202 Set<CmsUUID> functions, 1203 Set<CmsUUID> functionsToRemove) { 1204 1205 Set<String> addFormatters = parseAddFormatters(node); 1206 addFormatters.addAll(readLocalFormatters(node)); 1207 Set<String> removeFormatters = removeAllFormatters ? new HashSet<String>() : parseRemoveFormatters(node); 1208 String siteRoot = null; 1209 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(basePath)) { 1210 siteRoot = OpenCms.getSiteManager().getSiteRoot(basePath); 1211 } 1212 CmsFormatterChangeSet result = new CmsFormatterChangeSet( 1213 removeFormatters, 1214 addFormatters, 1215 siteRoot, 1216 removeAllFormatters, 1217 removeFunctions, 1218 functions, 1219 functionsToRemove); 1220 return result; 1221 } 1222 1223 /** 1224 * Parses a function reference node.<p> 1225 * 1226 * @param node the function reference node 1227 */ 1228 protected void parseFunctionReference(I_CmsXmlContentLocation node) { 1229 1230 String name = node.getSubValue(N_NAME).asString(m_cms); 1231 CmsUUID functionId = node.getSubValue(N_FUNCTION).asId(m_cms); 1232 CmsUUID functionDefaultPageId = null; 1233 I_CmsXmlContentValueLocation defaultPageValue = node.getSubValue(N_FUNCTION_DEFAULT_PAGE); 1234 if (defaultPageValue != null) { 1235 functionDefaultPageId = defaultPageValue.asId(m_cms); 1236 } 1237 I_CmsXmlContentValueLocation orderNode = node.getSubValue(N_ORDER); 1238 int order = I_CmsConfigurationObject.DEFAULT_ORDER; 1239 if (orderNode != null) { 1240 String orderStr = orderNode.asString(m_cms); 1241 try { 1242 order = Integer.parseInt(orderStr); 1243 } catch (NumberFormatException e) { 1244 // noop 1245 } 1246 } 1247 m_functionReferences.add(new CmsFunctionReference(name, functionId, functionDefaultPageId, order)); 1248 } 1249 1250 /** 1251 * Parses a single field definition from a content value.<p> 1252 * 1253 * @param field the content value to parse the field from 1254 * @param mode the property discard mode 1255 */ 1256 private void parseProperty(I_CmsXmlContentLocation field, DiscardPropertiesMode mode) { 1257 1258 CmsPropertyConfig propConfig = parseProperty(m_cms, field); 1259 if (CmsStringUtil.isEmptyOrWhitespaceOnly(propConfig.getName())) { 1260 return; 1261 } 1262 if (mode == DiscardPropertiesMode.top) { 1263 propConfig = propConfig.cloneWithTop(true); 1264 } 1265 m_propertyConfigs.add(propConfig); 1266 } 1267 1268 /** 1269 * Helper method for reading the target ids from a list of internal links two levels nested. 1270 * 1271 * @param root the parent location 1272 * @param childName the node name for the children 1273 * @param grandchildName the node name for the grandchildren 1274 * 1275 * @return the set of target ids collected from the grandchildren 1276 */ 1277 private Set<CmsUUID> readInternalLinkListTargetIds( 1278 I_CmsXmlContentLocation root, 1279 String childName, 1280 String grandchildName) { 1281 1282 Set<CmsUUID> result = new LinkedHashSet<>(); 1283 for (I_CmsXmlContentValueLocation parent : root.getSubValues(childName)) { 1284 for (I_CmsXmlContentValueLocation node : parent.getSubValues(grandchildName)) { 1285 CmsXmlVfsFileValue value = (CmsXmlVfsFileValue)node.getValue(); 1286 CmsLink link = value.getLink(m_cms); 1287 if (link != null) { 1288 CmsUUID structureId = link.getStructureId(); 1289 if (structureId != null) { 1290 result.add(link.getStructureId()); 1291 } 1292 } 1293 } 1294 } 1295 return result; 1296 } 1297 1298 /** 1299 * Reads the local macro or flex formatters from the .formatters folder if present.<p> 1300 * 1301 * @param node the xml content node 1302 * 1303 * @return the local formatters 1304 */ 1305 private Set<String> readLocalFormatters(I_CmsXmlContentLocation node) { 1306 1307 Set<String> addFormatters = new HashSet<String>(); 1308 String path = m_cms.getSitePath(node.getDocument().getFile()); 1309 path = CmsStringUtil.joinPaths(CmsResource.getParentFolder(path), ".formatters"); 1310 try { 1311 if (m_cms.existsResource(path, CmsResourceFilter.IGNORE_EXPIRATION)) { 1312 I_CmsResourceType macroType = OpenCms.getResourceManager().getResourceType( 1313 CmsFormatterConfigurationCache.TYPE_MACRO_FORMATTER); 1314 CmsResourceFilter filter = CmsResourceFilter.IGNORE_EXPIRATION.addRequireType(macroType); 1315 List<CmsResource> macroFormatters = m_cms.readResources(path, filter); 1316 for (CmsResource formatter : macroFormatters) { 1317 addFormatters.add(formatter.getStructureId().toString()); 1318 } 1319 I_CmsResourceType flexType = OpenCms.getResourceManager().getResourceType( 1320 CmsFormatterConfigurationCache.TYPE_FLEX_FORMATTER); 1321 CmsResourceFilter filterFlex = CmsResourceFilter.IGNORE_EXPIRATION.addRequireType(flexType); 1322 List<CmsResource> flexFormatters = m_cms.readResources(path, filterFlex); 1323 for (CmsResource formatter : flexFormatters) { 1324 addFormatters.add(formatter.getStructureId().toString()); 1325 } 1326 } 1327 } catch (CmsException e) { 1328 LOG.warn(e.getMessage(), e); 1329 } 1330 return addFormatters; 1331 } 1332 1333}