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