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.file.CmsFile; 035import org.opencms.file.CmsObject; 036import org.opencms.file.CmsResource; 037import org.opencms.file.CmsResourceFilter; 038import org.opencms.file.CmsVfsResourceNotFoundException; 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.LinkedHashSet; 067import java.util.List; 068import java.util.Locale; 069import java.util.Set; 070 071import org.apache.commons.logging.Log; 072 073import com.google.common.collect.Lists; 074 075/** 076 * A class to parse ADE sitemap or module configuration files and create configuration objects from them.<p> 077 */ 078public class CmsConfigurationReader { 079 080 /** The default locale for configuration objects. */ 081 public static final Locale DEFAULT_LOCALE = CmsLocaleManager.getLocale("en"); 082 083 /** Node name for added formatters. */ 084 public static final String N_ADD_FORMATTER = "AddFormatter"; 085 086 /** Node name for the nested content with the added formatters. */ 087 public static final String N_ADD_FORMATTERS = "AddFormatters"; 088 089 /** The create content locally node name. */ 090 public static final String N_CREATE_CONTENTS_LOCALLY = "CreateContentsLocally"; 091 092 /** The default node name. */ 093 public static final String N_DEFAULT = "Default"; 094 095 /** The description node name. */ 096 public static final String N_DESCRIPTION = "Description"; 097 098 /** The detail page node name. */ 099 public static final String N_DETAIL_PAGE = "DetailPage"; 100 101 /** The detail pages disabled node name. */ 102 public static final String N_DETAIL_PAGES_DISABLED = "DetailPagesDisabled"; 103 104 /** The disabled node name. */ 105 public static final String N_DISABLED = "Disabled"; 106 107 /** The discard model pages node name. */ 108 public static final String N_DISCARD_MODEL_PAGES = "DiscardModelPages"; 109 110 /** The discard properties node name. */ 111 public static final String N_DISCARD_PROPERTIES = "DiscardProperties"; 112 113 /** The discard types node name. */ 114 public static final String N_DISCARD_TYPES = "DiscardTypes"; 115 116 /** The display name node name. */ 117 public static final String N_DISPLAY_NAME = "DisplayName"; 118 119 /** The element view node name. */ 120 public static final String N_ELEMENT_VIEW = "ElementView"; 121 122 /** The error node name. */ 123 public static final String N_ERROR = "Error"; 124 125 /** The folder node name. */ 126 public static final String N_FOLDER = "Folder"; 127 128 /** The formatter node name. */ 129 public static final String N_FORMATTER = "Formatter"; 130 131 /** The function node name. */ 132 public static final String N_FUNCTION = "Function"; 133 134 /** The function node name. */ 135 public static final String N_FUNCTION_DEFAULT_PAGE = "FunctionDefaultPage"; 136 137 /** The function reference node name. */ 138 public static final String N_FUNCTION_REF = "FunctionRef"; 139 140 /** The is default node name. */ 141 public static final String N_IS_DEFAULT = "IsDefault"; 142 143 /** The is preview node name. */ 144 public static final String N_IS_PREVIEW = "IsPreview"; 145 146 /** The JSP node name. */ 147 public static final String N_JSP = "Jsp"; 148 149 /** The localization node name. */ 150 public static final String N_LOCALIZATION = "Localization"; 151 152 /** The master configuration node name. */ 153 public static final String N_MASTER_CONFIG = "MasterConfig"; 154 155 /** The max width node name. */ 156 public static final String N_MAX_WIDTH = "MaxWidth"; 157 158 /** The min width node name. */ 159 public static final String N_MIN_WIDTH = "MinWidth"; 160 161 /** The model page node name. */ 162 public static final String N_MODEL_PAGE = "ModelPage"; 163 164 /** The folder name node name. */ 165 public static final String N_NAME = "Name"; 166 167 /** The name pattern node name. */ 168 public static final String N_NAME_PATTERN = "NamePattern"; 169 170 /** The order node name. */ 171 public static final String N_ORDER = "Order"; 172 173 /** The page node name. */ 174 public static final String N_PAGE = "Page"; 175 176 /** The folder path node name. */ 177 public static final String N_PATH = "Path"; 178 179 /** The PreferDetailPagesForLocalContents node name. */ 180 public static final String N_PREFER_DETAIL_PAGES_FOR_LOCAL_CONTENTS = "PreferDetailPagesForLocalContents"; 181 182 /** The prefer folder node name. */ 183 public static final String N_PREFER_FOLDER = "PreferFolder"; 184 185 /** The property node name. */ 186 public static final String N_PROPERTY = "Property"; 187 188 /** The property name node name. */ 189 public static final String N_PROPERTY_NAME = "PropertyName"; 190 191 /** Node name for the "Remove all formatters"-option. */ 192 public static final String N_REMOVE_ALL_FORMATTERS = "RemoveAllFormatters"; 193 194 /** Node name for removed formatters. */ 195 public static final String N_REMOVE_FORMATTER = "RemoveFormatter"; 196 197 /** Node name for the nested content with the removed formatters. */ 198 public static final String N_REMOVE_FORMATTERS = "RemoveFormatters"; 199 200 /** The resource type node name. */ 201 public static final String N_RESOURCE_TYPE = "ResourceType"; 202 203 /** The regex rule node name. */ 204 public static final String N_RULE_REGEX = "RuleRegex"; 205 206 /** The rule type node name. */ 207 public static final String N_RULE_TYPE = "RuleType"; 208 209 /** The type node name. */ 210 public static final String N_TYPE = "Type"; 211 212 /** The type name node name. */ 213 public static final String N_TYPE_NAME = "TypeName"; 214 215 /** The widget node name. */ 216 public static final String N_VISIBILITY = "Visibility"; 217 218 /** The widget node name. */ 219 public static final String N_WIDGET = "Widget"; 220 221 /** The widget configuration node name. */ 222 public static final String N_WIDGET_CONFIG = "WidgetConfig"; 223 224 /** Scheme for explorer type view links. */ 225 public static final String VIEW_SCHEME = "view://"; 226 227 /** The log object for this class. */ 228 private static final Log LOG = CmsLog.getLog(CmsConfigurationReader.class); 229 230 /** The CopyInModels node name. */ 231 private static final String N_COPY_IN_MODELS = "CopyInModels"; 232 233 /** The ElementDeleteMode node name. */ 234 private static final String N_ELEMENT_DELETE_MODE = "ElementDeleteMode"; 235 236 /** The IncludeName node name. */ 237 private static final String N_INCLUDE_NAME = "IncludeName"; 238 239 /** The PageRelative node name. */ 240 private static final String N_PAGE_RELATIVE = "PageRelative"; 241 242 /** The ShowInDefaultView node name. */ 243 private static final String N_SHOW_IN_DEFAULT_VIEW = "ShowInDefaultView"; 244 245 /** The CMS context used for reading the configuration data. */ 246 private CmsObject m_cms; 247 248 /** The parsed detail page configuration elements. */ 249 private List<CmsDetailPageInfo> m_detailPageConfigs = new ArrayList<CmsDetailPageInfo>(); 250 251 /** The list of configured function references. */ 252 private List<CmsFunctionReference> m_functionReferences = new ArrayList<CmsFunctionReference>(); 253 254 /** The parsed model page configuration elements. */ 255 private List<CmsModelPageConfig> m_modelPageConfigs = new ArrayList<CmsModelPageConfig>(); 256 257 /** The parsed property configuration elements. */ 258 private List<CmsPropertyConfig> m_propertyConfigs = new ArrayList<CmsPropertyConfig>(); 259 260 /** The resource type configuration objects. */ 261 private List<CmsResourceTypeConfig> m_resourceTypeConfigs = new ArrayList<CmsResourceTypeConfig>(); 262 263 /** 264 * Creates a new configuration reader.<p> 265 * 266 * @param cms the CMS context which should be used to read the configuration data.<p> 267 */ 268 public CmsConfigurationReader(CmsObject cms) { 269 270 m_cms = cms; 271 } 272 273 /** 274 * Gets the string value of an XML content location.<p> 275 * 276 * @param cms the CMS context to use 277 * @param location an XML content location 278 * 279 * @return the string value of that XML content location 280 */ 281 public static String getString(CmsObject cms, I_CmsXmlContentValueLocation location) { 282 283 if (location == null) { 284 return null; 285 } 286 return location.asString(cms); 287 } 288 289 /** 290 * Helper method to parse a property.<p> 291 * 292 * @param cms the CMS context to use 293 * @param field the location of the parent value 294 * 295 * @return the parsed property configuration 296 */ 297 public static CmsPropertyConfig parseProperty(CmsObject cms, I_CmsXmlContentLocation field) { 298 299 String name = getString(cms, field.getSubValue(N_PROPERTY_NAME)); 300 String includeName = getString(cms, field.getSubValue(N_INCLUDE_NAME)); 301 String widget = getString(cms, field.getSubValue(N_WIDGET)); 302 String widgetConfig = getString(cms, field.getSubValue(N_WIDGET_CONFIG)); 303 String ruleRegex = getString(cms, field.getSubValue(N_RULE_REGEX)); 304 String ruleType = getString(cms, field.getSubValue(N_RULE_TYPE)); 305 String default1 = getString(cms, field.getSubValue(N_DEFAULT)); 306 String error = getString(cms, field.getSubValue(N_ERROR)); 307 String niceName = getString(cms, field.getSubValue(N_DISPLAY_NAME)); 308 String description = getString(cms, field.getSubValue(N_DESCRIPTION)); 309 String preferFolder = getString(cms, field.getSubValue(N_PREFER_FOLDER)); 310 311 String disabledStr = getString(cms, field.getSubValue(N_DISABLED)); 312 boolean disabled = ((disabledStr != null) && Boolean.parseBoolean(disabledStr)); 313 314 String orderStr = getString(cms, field.getSubValue(N_ORDER)); 315 int order = I_CmsConfigurationObject.DEFAULT_ORDER; 316 317 try { 318 order = Integer.parseInt(orderStr); 319 } catch (NumberFormatException e) { 320 // noop 321 } 322 323 Visibility visibility; 324 String visibilityStr = getString(cms, field.getSubValue(N_VISIBILITY)); 325 try { 326 // to stay compatible with former visibility option values 327 if ("both".equals(visibilityStr)) { 328 visibilityStr = Visibility.elementAndParentIndividual.name(); 329 } else if ("parent".equals(visibilityStr)) { 330 visibilityStr = Visibility.parentShared.name(); 331 } 332 visibility = Visibility.valueOf(visibilityStr); 333 } catch (Exception e) { 334 visibility = null; 335 } 336 CmsXmlContentProperty prop = new CmsXmlContentProperty( 337 name, 338 "string", 339 visibility, 340 widget, 341 widgetConfig, 342 ruleRegex, 343 ruleType, 344 default1, 345 niceName, 346 description, 347 error, 348 preferFolder).withIncludeName(includeName); 349 // since these are real properties, using type vfslist makes no sense, so we always use the "string" type 350 CmsPropertyConfig propConfig = new CmsPropertyConfig(prop, disabled, order); 351 return propConfig; 352 353 } 354 355 /** 356 * Returns the list of function references.<p> 357 * 358 * @return the list of function references 359 */ 360 public List<CmsFunctionReference> getFunctionReferences() { 361 362 return new ArrayList<CmsFunctionReference>(m_functionReferences); 363 } 364 365 /** 366 * Returns the modelPageConfigs.<p> 367 * 368 * @return the modelPageConfigs 369 */ 370 public List<CmsModelPageConfig> getModelPageConfigs() { 371 372 return m_modelPageConfigs; 373 } 374 375 /** 376 * Parses the formatters to add.<p> 377 * 378 * @param node the parent node 379 * @return the set of keys of the formatters to add 380 */ 381 public Set<String> parseAddFormatters(I_CmsXmlContentLocation node) { 382 383 Set<String> addFormatters = new HashSet<String>(); 384 for (I_CmsXmlContentValueLocation addLoc : node.getSubValues(N_ADD_FORMATTERS + "/" + N_ADD_FORMATTER)) { 385 CmsXmlVfsFileValue value = (CmsXmlVfsFileValue)addLoc.getValue(); 386 CmsLink link = value.getLink(m_cms); 387 if (link != null) { 388 addFormatters.add(link.getStructureId().toString()); 389 } 390 } 391 return addFormatters; 392 } 393 394 /** 395 * Parses a configuration XML content and creates a configuration object from it.<p> 396 * 397 * @param basePath the base path 398 * @param content the XML content 399 * 400 * @return the created configuration object with the data from the XML content 401 * @throws CmsException if something goes wrong 402 */ 403 public CmsADEConfigDataInternal parseConfiguration(String basePath, CmsXmlContent content) throws CmsException { 404 405 m_detailPageConfigs = Lists.newArrayList(); 406 m_functionReferences = Lists.newArrayList(); 407 m_modelPageConfigs = Lists.newArrayList(); 408 m_propertyConfigs = Lists.newArrayList(); 409 m_resourceTypeConfigs = Lists.newArrayList(); 410 411 if (!content.hasLocale(DEFAULT_LOCALE)) { 412 return CmsADEConfigDataInternal.emptyConfiguration(basePath); 413 } 414 CmsXmlContentRootLocation root = new CmsXmlContentRootLocation(content, DEFAULT_LOCALE); 415 for (I_CmsXmlContentValueLocation node : root.getSubValues(N_RESOURCE_TYPE)) { 416 try { 417 parseResourceTypeConfig(basePath, node); 418 } catch (CmsException e) { 419 LOG.warn(e.getLocalizedMessage(), e); 420 } 421 } 422 for (I_CmsXmlContentValueLocation node : root.getSubValues(N_MODEL_PAGE)) { 423 try { 424 parseModelPage(node); 425 } catch (CmsException e) { 426 LOG.warn(e.getLocalizedMessage(), e); 427 } 428 } 429 for (I_CmsXmlContentLocation node : root.getSubValues(N_PROPERTY)) { 430 parseProperty(node); 431 } 432 for (I_CmsXmlContentLocation node : root.getSubValues(N_DETAIL_PAGE)) { 433 try { 434 parseDetailPage(node); 435 } catch (CmsException e) { 436 LOG.warn(e.getLocalizedMessage(), e); 437 } 438 } 439 440 for (I_CmsXmlContentLocation node : root.getSubValues(N_FUNCTION_REF)) { 441 parseFunctionReference(node); 442 } 443 444 boolean removeAllFormatters = getBoolean(root, N_REMOVE_ALL_FORMATTERS); 445 CmsFormatterChangeSet formatterChangeSet = parseFormatterChangeSet(basePath, root, removeAllFormatters); 446 boolean discardInheritedTypes = getBoolean(root, N_DISCARD_TYPES); 447 boolean discardInheritedProperties = getBoolean(root, N_DISCARD_PROPERTIES); 448 boolean discardInheritedModelPages = getBoolean(root, N_DISCARD_MODEL_PAGES); 449 450 boolean createContentsLocally = getBoolean(root, N_CREATE_CONTENTS_LOCALLY); 451 boolean preferDetailPagesForLocalContents = getBoolean(root, N_PREFER_DETAIL_PAGES_FOR_LOCAL_CONTENTS); 452 453 boolean isModuleConfig = OpenCms.getResourceManager().getResourceType( 454 content.getFile().getTypeId()).getTypeName().equals(CmsADEManager.MODULE_CONFIG_TYPE); 455 456 String masterConfig = getString(root.getSubValue(N_MASTER_CONFIG)); 457 CmsResource masterConfigResource = null; 458 if (masterConfig != null) { 459 masterConfigResource = m_cms.readResource(masterConfig, CmsResourceFilter.IGNORE_EXPIRATION); 460 } 461 Set<CmsUUID> functions = new LinkedHashSet<>(); 462 for (I_CmsXmlContentValueLocation node : root.getSubValues(N_FUNCTION)) { 463 CmsXmlVfsFileValue value = (CmsXmlVfsFileValue)node.getValue(); 464 CmsLink link = value.getLink(m_cms); 465 if (link != null) { 466 functions.add(link.getStructureId()); 467 } 468 } 469 if (functions.isEmpty()) { 470 functions = null; 471 } 472 473 CmsADEConfigDataInternal result = new CmsADEConfigDataInternal( 474 content.getFile(), 475 isModuleConfig, 476 basePath, 477 masterConfigResource, 478 m_resourceTypeConfigs, 479 discardInheritedTypes, 480 m_propertyConfigs, 481 discardInheritedProperties, 482 m_detailPageConfigs, 483 m_modelPageConfigs, 484 m_functionReferences, 485 discardInheritedModelPages, 486 createContentsLocally, 487 preferDetailPagesForLocalContents, 488 formatterChangeSet, 489 functions); 490 return result; 491 } 492 493 /** 494 * Parses a folder which may either be given as a path or as a folder name.<p> 495 * 496 * @param basePath the base path for the configuration 497 * @param location the XML content node from which to parse the folder 498 * @return the folder bean 499 * 500 * @throws CmsException if something goes wrong 501 */ 502 public CmsContentFolderDescriptor parseFolderOrName(String basePath, I_CmsXmlContentLocation location) 503 throws CmsException { 504 505 if (location == null) { 506 return null; 507 } 508 I_CmsXmlContentValueLocation nameLoc = location.getSubValue(N_NAME); 509 I_CmsXmlContentValueLocation pathLoc = location.getSubValue(N_PATH); 510 I_CmsXmlContentValueLocation pageRelativeLoc = location.getSubValue(N_PAGE_RELATIVE); 511 if (nameLoc != null) { 512 String name = nameLoc.asString(m_cms); 513 return new CmsContentFolderDescriptor( 514 basePath == null ? null : CmsStringUtil.joinPaths(basePath, CmsADEManager.CONTENT_FOLDER_NAME), 515 name); 516 } else if (pathLoc != null) { 517 String path = pathLoc.asString(m_cms); 518 CmsResource folder = m_cms.readResource(path); 519 return new CmsContentFolderDescriptor(folder); 520 } else if (pageRelativeLoc != null) { 521 return CmsContentFolderDescriptor.createPageRelativeFolderDescriptor(); 522 } else { 523 return null; 524 } 525 } 526 527 /** 528 * Parses a formatter bean.<p> 529 * 530 * @param typeName the type name for which the formatter is being parsed 531 * @param node the node from which to parse the formatter data 532 * 533 * @return the formatter bean from the XML 534 */ 535 public CmsFormatterBean parseFormatter(String typeName, I_CmsXmlContentLocation node) { 536 537 String type = getString(node.getSubValue(N_TYPE)); 538 String minWidth = getString(node.getSubValue(N_MIN_WIDTH)); 539 String maxWidth = getString(node.getSubValue(N_MAX_WIDTH)); 540 boolean preview = false; 541 I_CmsXmlContentValueLocation previewLoc = node.getSubValue(N_IS_PREVIEW); 542 preview = (previewLoc != null) && Boolean.parseBoolean(previewLoc.asString(m_cms)); 543 String jsp = m_cms.getRequestContext().addSiteRoot(getString(node.getSubValue(N_JSP))); 544 boolean searchContent = true; 545 CmsFormatterBean formatterBean = new CmsFormatterBean( 546 type, 547 jsp, 548 minWidth, 549 maxWidth, 550 "" + preview, 551 "" + searchContent, 552 null); 553 return formatterBean; 554 555 } 556 557 /** 558 * Parses model page data from the XML content.<p> 559 * 560 * @param node the XML content node 561 * @throws CmsException if something goes wrong 562 */ 563 public void parseModelPage(I_CmsXmlContentLocation node) throws CmsException { 564 565 String page = getString(node.getSubValue(N_PAGE)); 566 I_CmsXmlContentValueLocation disabledLoc = node.getSubValue(N_DISABLED); 567 boolean disabled = (disabledLoc != null) && Boolean.parseBoolean(disabledLoc.asString(m_cms)); 568 I_CmsXmlContentValueLocation defaultLoc = node.getSubValue(N_IS_DEFAULT); 569 boolean isDefault = (defaultLoc != null) && Boolean.parseBoolean(defaultLoc.asString(m_cms)); 570 CmsModelPageConfig modelPage = new CmsModelPageConfig(m_cms.readResource(page), isDefault, disabled); 571 m_modelPageConfigs.add(modelPage); 572 573 } 574 575 /** 576 * Parses the set of formatters to remove.<p> 577 * 578 * @param node the parent node 579 * @return the set of formatters to remove 580 */ 581 public Set<String> parseRemoveFormatters(I_CmsXmlContentLocation node) { 582 583 Set<String> removeFormatters = new HashSet<String>(); 584 for (I_CmsXmlContentValueLocation removeLoc : node.getSubValues( 585 N_REMOVE_FORMATTERS + "/" + N_REMOVE_FORMATTER)) { 586 CmsXmlVfsFileValue value = (CmsXmlVfsFileValue)removeLoc.getValue(); 587 CmsLink link = value.getLink(m_cms); 588 if (link != null) { 589 removeFormatters.add(link.getStructureId().toString()); 590 } 591 } 592 return removeFormatters; 593 } 594 595 /** 596 * Parses a resource type configuration element from the XML content.<p> 597 * 598 * @param basePath the base path of the configuration 599 * @param node the XML configuration node 600 * @throws CmsException if something goes wrong 601 */ 602 public void parseResourceTypeConfig(String basePath, I_CmsXmlContentLocation node) throws CmsException { 603 604 I_CmsXmlContentValueLocation typeNameLoc = node.getSubValue(N_TYPE_NAME); 605 String typeName = typeNameLoc.asString(m_cms); 606 CmsContentFolderDescriptor folderOrName = parseFolderOrName(basePath, node.getSubValue(N_FOLDER)); 607 I_CmsXmlContentValueLocation disabledLoc = node.getSubValue(N_DISABLED); 608 boolean disabled = false; 609 boolean addDisabled = false; 610 boolean createDisabled = false; 611 String disabledStr = disabledLoc == null ? null : disabledLoc.asString(m_cms); 612 if ((disabledStr != null) && "add".equalsIgnoreCase(disabledStr.trim())) { 613 addDisabled = true; 614 } else if ((disabledStr != null) && "create".equalsIgnoreCase(disabledStr.trim())) { 615 createDisabled = true; 616 } else { 617 disabled = Boolean.parseBoolean(disabledStr); 618 } 619 I_CmsXmlContentValueLocation namePatternLoc = node.getSubValue(N_NAME_PATTERN); 620 String namePattern = null; 621 if (namePatternLoc != null) { 622 namePattern = namePatternLoc.asString(m_cms); 623 } 624 625 boolean detailPagesDisabled = false; 626 I_CmsXmlContentValueLocation detailDisabledLoc = node.getSubValue(N_DETAIL_PAGES_DISABLED); 627 if (detailDisabledLoc != null) { 628 String detailPagesDisabledStr = detailDisabledLoc.asString(m_cms); 629 detailPagesDisabled = Boolean.parseBoolean(detailPagesDisabledStr); 630 } 631 632 int order = I_CmsConfigurationObject.DEFAULT_ORDER; 633 I_CmsXmlContentValueLocation orderLoc = node.getSubValue(N_ORDER); 634 if (orderLoc != null) { 635 try { 636 String orderStr = orderLoc.asString(m_cms); 637 order = Integer.parseInt(orderStr); 638 } catch (NumberFormatException e) { 639 // noop 640 } 641 } 642 643 I_CmsXmlContentValueLocation elementViewLoc = node.getSubValue(N_ELEMENT_VIEW); 644 CmsUUID elementView = null; 645 if (elementViewLoc != null) { 646 try { 647 CmsXmlVarLinkValue elementViewValue = (CmsXmlVarLinkValue)elementViewLoc.getValue(); 648 String stringValue = elementViewValue.getStringValue(m_cms); 649 if ("".equals(stringValue)) { 650 elementView = CmsUUID.getNullUUID(); 651 } else if (stringValue.startsWith(VIEW_SCHEME)) { 652 elementView = new CmsUUID(stringValue.substring(VIEW_SCHEME.length())); 653 } else { 654 elementView = elementViewValue.getLink(m_cms).getStructureId(); 655 } 656 } catch (Exception e) { 657 // in case parsing the link fails, the default element view will be used 658 } 659 } 660 661 I_CmsXmlContentValueLocation locationLoc = node.getSubValue(N_LOCALIZATION); 662 String localization = null; 663 if (locationLoc != null) { 664 CmsXmlVfsFileValue locationValue = (CmsXmlVfsFileValue)locationLoc.getValue(); 665 CmsLink link = locationValue.getLink(m_cms); 666 if (null != link) { 667 String stringValue = link.getSitePath(m_cms); 668 // extract bundle base name from the path to the bundle file 669 int lastSlashIndex = stringValue.lastIndexOf("/"); 670 String fileName = stringValue.substring(lastSlashIndex + 1); 671 if (CmsFileUtil.getExtension(fileName).equals(".properties")) { 672 fileName = fileName.substring(0, fileName.length() - ".properties".length()); 673 } 674 String localeSuffix = CmsStringUtil.getLocaleSuffixForName(fileName); 675 if ((localeSuffix != null) && fileName.endsWith(localeSuffix)) { 676 fileName = fileName.substring(0, fileName.length() - localeSuffix.length() - 1); 677 } 678 localization = fileName; 679 } 680 } 681 682 I_CmsXmlContentValueLocation showDefaultViewLoc = node.getSubValue(N_SHOW_IN_DEFAULT_VIEW); 683 Boolean showInDefaultView = null; 684 if (showDefaultViewLoc != null) { 685 showInDefaultView = Boolean.valueOf( 686 Boolean.parseBoolean(showDefaultViewLoc.getValue().getStringValue(m_cms))); 687 } 688 689 I_CmsXmlContentValueLocation copyInModelsLoc = node.getSubValue(N_COPY_IN_MODELS); 690 Boolean copyInModels = null; 691 if (copyInModelsLoc != null) { 692 copyInModels = Boolean.valueOf(Boolean.parseBoolean(copyInModelsLoc.getValue().getStringValue(m_cms))); 693 } 694 695 I_CmsXmlContentValueLocation elementDeleteModeLoc = node.getSubValue(N_ELEMENT_DELETE_MODE); 696 ElementDeleteMode elementDeleteMode = null; 697 if (elementDeleteModeLoc != null) { 698 try { 699 elementDeleteMode = ElementDeleteMode.valueOf(elementDeleteModeLoc.getValue().getStringValue(m_cms)); 700 } catch (Exception e) { 701 LOG.warn(e.getLocalizedMessage(), e); 702 } 703 } 704 705 List<I_CmsFormatterBean> formatters = new ArrayList<I_CmsFormatterBean>(); 706 for (I_CmsXmlContentValueLocation formatterLoc : node.getSubValues(N_FORMATTER)) { 707 CmsFormatterBean formatter = parseFormatter(typeName, formatterLoc); 708 formatters.add(formatter); 709 } 710 711 CmsResourceTypeConfig typeConfig = new CmsResourceTypeConfig( 712 typeName, 713 disabled, 714 folderOrName, 715 namePattern, 716 detailPagesDisabled, 717 addDisabled, 718 createDisabled, 719 elementView, 720 localization, 721 showInDefaultView, 722 copyInModels, 723 order, 724 elementDeleteMode); 725 m_resourceTypeConfigs.add(typeConfig); 726 } 727 728 /** 729 * Parses the sitemap configuration given the configuration file and base path.<p> 730 * 731 * @param basePath the base path 732 * @param configRes the configuration file resource 733 * @return the parsed configuration data 734 * @throws CmsException if something goes wrong 735 */ 736 public CmsADEConfigDataInternal parseSitemapConfiguration(String basePath, CmsResource configRes) 737 throws CmsException { 738 739 LOG.info("Parsing configuration " + configRes.getRootPath()); 740 CmsFile configFile = m_cms.readFile(configRes); 741 CmsXmlContent content = CmsXmlContentFactory.unmarshal(m_cms, configFile); 742 return parseConfiguration(basePath, content); 743 } 744 745 /** 746 * Reads the configurations of all modules and combines them into a single configuration object.<p> 747 * 748 * @return the combined configuration object 749 */ 750 public List<CmsADEConfigDataInternal> readModuleConfigurations() { 751 752 List<CmsADEConfigDataInternal> configurations = new ArrayList<CmsADEConfigDataInternal>(); 753 List<CmsModule> modules = OpenCms.getModuleManager().getAllInstalledModules(); 754 long beginTime = System.currentTimeMillis(); 755 for (CmsModule module : modules) { 756 String configPath = module.getConfigurationPath(); 757 if (m_cms.existsResource(configPath)) { 758 try { 759 CmsResource configFile = m_cms.readResource(configPath); 760 LOG.info("Found module configuration " + configPath + " for module " + module.getName()); 761 CmsADEConfigDataInternal config = parseSitemapConfiguration(null, configFile); 762 configurations.add(config); 763 } catch (CmsException e) { 764 // errors while parsing configuration 765 LOG.error(e.getLocalizedMessage(), e); 766 } catch (CmsRuntimeException e) { 767 // may happen during import of org.opencms.ade.configuration module 768 LOG.warn(e.getLocalizedMessage(), e); 769 } catch (Throwable e) { 770 LOG.error(e.getLocalizedMessage(), e); 771 } 772 } 773 } 774 long endTime = System.currentTimeMillis(); 775 LOG.debug("readModuleConfiguations took " + (endTime - beginTime) + "ms"); 776 return configurations; 777 } 778 779 /** 780 * Helper method to read a boolean value from the XML.<p> 781 * 782 * If the element is not found in the XML, false is returned.<p> 783 * 784 * @param parent the parent node 785 * @param name the name of the XML content value 786 * @return the boolean value 787 */ 788 protected boolean getBoolean(I_CmsXmlContentLocation parent, String name) { 789 790 I_CmsXmlContentValueLocation location = parent.getSubValue(name); 791 if (location == null) { 792 return false; 793 } 794 String value = location.getValue().getStringValue(m_cms); 795 return Boolean.parseBoolean(value); 796 } 797 798 /** 799 * Gets the string value of an XML content location.<p> 800 * 801 * @param location an XML content location 802 * 803 * @return the string value of that XML content location 804 */ 805 protected String getString(I_CmsXmlContentValueLocation location) { 806 807 return getString(m_cms, location); 808 } 809 810 /** 811 * Parses the detail pages from an XML content node.<p> 812 * 813 * @param node the XML content node 814 * 815 * @throws CmsException if something goes wrong 816 */ 817 protected void parseDetailPage(I_CmsXmlContentLocation node) throws CmsException { 818 819 I_CmsXmlContentValueLocation pageLoc = node.getSubValue(N_PAGE); 820 String typeName = getString(node.getSubValue(N_TYPE)); 821 try { 822 String page = pageLoc.asString(m_cms); 823 CmsResource detailPageRes = m_cms.readResource(page); 824 CmsUUID id = detailPageRes.getStructureId(); 825 String iconClasses; 826 if (typeName.startsWith(CmsDetailPageInfo.FUNCTION_PREFIX)) { 827 iconClasses = CmsIconUtil.getIconClasses(CmsXmlDynamicFunctionHandler.TYPE_FUNCTION, null, false); 828 } else { 829 iconClasses = CmsIconUtil.getIconClasses(typeName, null, false); 830 } 831 832 CmsDetailPageInfo detailPage = new CmsDetailPageInfo(id, page, typeName, iconClasses); 833 m_detailPageConfigs.add(detailPage); 834 } catch (CmsVfsResourceNotFoundException e) { 835 CmsUUID structureId = pageLoc.asId(m_cms); 836 CmsResource detailPageRes = m_cms.readResource(structureId); 837 CmsDetailPageInfo detailPage = new CmsDetailPageInfo( 838 structureId, 839 m_cms.getSitePath(detailPageRes), 840 typeName, 841 CmsIconUtil.getIconClasses(typeName, null, false)); 842 m_detailPageConfigs.add(detailPage); 843 } 844 } 845 846 /** 847 * Parses the formatter change set.<p> 848 * 849 * @param basePath the configuration base path 850 * @param node the parent node 851 * @param removeAllFormatters flag, indicating if all formatters that are not explicitly added should be removed 852 * @return the formatter change set 853 */ 854 protected CmsFormatterChangeSet parseFormatterChangeSet( 855 String basePath, 856 I_CmsXmlContentLocation node, 857 boolean removeAllFormatters) { 858 859 Set<String> addFormatters = parseAddFormatters(node); 860 addFormatters.addAll(readLocalFormatters(node)); 861 Set<String> removeFormatters = removeAllFormatters ? new HashSet<String>() : parseRemoveFormatters(node); 862 String siteRoot = null; 863 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(basePath)) { 864 siteRoot = OpenCms.getSiteManager().getSiteRoot(basePath); 865 } 866 CmsFormatterChangeSet result = new CmsFormatterChangeSet( 867 removeFormatters, 868 addFormatters, 869 siteRoot, 870 removeAllFormatters); 871 return result; 872 } 873 874 /** 875 * Parses a function reference node.<p> 876 * 877 * @param node the function reference node 878 */ 879 protected void parseFunctionReference(I_CmsXmlContentLocation node) { 880 881 String name = node.getSubValue(N_NAME).asString(m_cms); 882 CmsUUID functionId = node.getSubValue(N_FUNCTION).asId(m_cms); 883 CmsUUID functionDefaultPageId = null; 884 I_CmsXmlContentValueLocation defaultPageValue = node.getSubValue(N_FUNCTION_DEFAULT_PAGE); 885 if (defaultPageValue != null) { 886 functionDefaultPageId = defaultPageValue.asId(m_cms); 887 } 888 I_CmsXmlContentValueLocation orderNode = node.getSubValue(N_ORDER); 889 int order = I_CmsConfigurationObject.DEFAULT_ORDER; 890 if (orderNode != null) { 891 String orderStr = orderNode.asString(m_cms); 892 try { 893 order = Integer.parseInt(orderStr); 894 } catch (NumberFormatException e) { 895 // noop 896 } 897 } 898 m_functionReferences.add(new CmsFunctionReference(name, functionId, functionDefaultPageId, order)); 899 } 900 901 /** 902 * Parses a single field definition from a content value.<p> 903 * 904 * @param field the content value to parse the field from 905 */ 906 private void parseProperty(I_CmsXmlContentLocation field) { 907 908 CmsPropertyConfig propConfig = parseProperty(m_cms, field); 909 m_propertyConfigs.add(propConfig); 910 } 911 912 /** 913 * Reads the local macro or flex formatters from the .formatters folder if present.<p> 914 * 915 * @param node the xml content node 916 * 917 * @return the local formatters 918 */ 919 private Set<String> readLocalFormatters(I_CmsXmlContentLocation node) { 920 921 Set<String> addFormatters = new HashSet<String>(); 922 String path = m_cms.getSitePath(node.getDocument().getFile()); 923 path = CmsStringUtil.joinPaths(CmsResource.getParentFolder(path), ".formatters"); 924 try { 925 if (m_cms.existsResource(path, CmsResourceFilter.IGNORE_EXPIRATION)) { 926 I_CmsResourceType macroType = OpenCms.getResourceManager().getResourceType( 927 CmsFormatterConfigurationCache.TYPE_MACRO_FORMATTER); 928 CmsResourceFilter filter = CmsResourceFilter.IGNORE_EXPIRATION.addRequireType(macroType); 929 List<CmsResource> macroFormatters = m_cms.readResources(path, filter); 930 for (CmsResource formatter : macroFormatters) { 931 addFormatters.add(formatter.getStructureId().toString()); 932 } 933 I_CmsResourceType flexType = OpenCms.getResourceManager().getResourceType( 934 CmsFormatterConfigurationCache.TYPE_FLEX_FORMATTER); 935 CmsResourceFilter filterFlex = CmsResourceFilter.IGNORE_EXPIRATION.addRequireType(flexType); 936 List<CmsResource> flexFormatters = m_cms.readResources(path, filterFlex); 937 for (CmsResource formatter : flexFormatters) { 938 addFormatters.add(formatter.getStructureId().toString()); 939 } 940 } 941 } catch (CmsException e) { 942 LOG.warn(e.getMessage(), e); 943 } 944 return addFormatters; 945 } 946 947}