/* * This library is part of OpenCms - * the Open Source Content Management System * * Copyright (C) Alkacon Software (http://www.alkacon.com) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * For further information about Alkacon Software, please see the * company website: http://www.alkacon.com * * For further information about OpenCms, please see the * project website: http://www.opencms.org * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.opencms.ade.configuration; import org.opencms.ade.detailpage.CmsDetailPageInfo; import org.opencms.file.CmsObject; import org.opencms.file.CmsResource; import org.opencms.file.types.CmsResourceTypeFolder; import org.opencms.file.types.I_CmsResourceType; import org.opencms.loader.CmsLoaderException; import org.opencms.main.CmsException; import org.opencms.main.CmsLog; import org.opencms.main.OpenCms; import org.opencms.util.CmsStringUtil; import org.opencms.util.CmsUUID; import org.opencms.xml.CmsXmlContentDefinition; import org.opencms.xml.containerpage.CmsFormatterConfiguration; import org.opencms.xml.content.CmsXmlContentProperty; import org.opencms.xml.content.I_CmsXmlContentHandler; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.commons.logging.Log; import com.google.common.collect.ComparisonChain; import com.google.common.collect.Lists; import com.google.common.collect.Maps; /** * A class which represents the accessible configuration data at a given point in a sitemap.<p> */ public class CmsADEConfigData { /** The content folder name. */ public static final String CONTENT_FOLDER_NAME = ".content"; /** The log instance for this class. */ private static final Log LOG = CmsLog.getLog(CmsADEConfigData.class); /** The "create contents locally" flag. */ protected boolean m_createContentsLocally; /** Should inherited model pages be discarded? */ protected boolean m_discardInheritedModelPages; /** Should inherited properties be discard? */ protected boolean m_discardInheritedProperties; /** Should inherited types be discarded? */ protected boolean m_discardInheritedTypes; /** The base path of this configuration. */ private String m_basePath; /** The cms context used for reading the configuration data. */ private CmsObject m_cms; /** The list of configured function references. */ private List<CmsFunctionReference> m_functionReferences = new ArrayList<CmsFunctionReference>(); /** A flag which keeps track of whether this instance has already been initialized. */ private boolean m_initialized; /** True if this is a module configuration, not a normal sitemap configuration. */ private boolean m_isModuleConfig; /** The internal detail page configuration. */ private List<CmsDetailPageInfo> m_ownDetailPages = new ArrayList<CmsDetailPageInfo>(); /** The internal model page entries. */ private List<CmsModelPageConfig> m_ownModelPageConfig = new ArrayList<CmsModelPageConfig>(); /** The internal property configuration. */ private List<CmsPropertyConfig> m_ownPropertyConfigurations = new ArrayList<CmsPropertyConfig>(); /** The internal resource type entries. */ private List<CmsResourceTypeConfig> m_ownResourceTypes = new ArrayList<CmsResourceTypeConfig>(); /** The resource from which the configuration data was read. */ private CmsResource m_resource; /** * Default constructor to create an empty configuration.<p> */ public CmsADEConfigData() { // do nothing } /** * Creates an empty configuration data object with a given base path.<p> * * @param basePath the base path */ public CmsADEConfigData(String basePath) { m_basePath = basePath; } /** * Creates a new configuration data instance.<p> * * @param basePath the base path * @param resourceTypeConfig the resource type configuration * @param discardInheritedTypes the "discard inherited types" flag * @param propertyConfig the property configuration * @param discardInheritedProperties the "discard inherited properties" flag * @param detailPageInfos the detail page configuration * @param modelPages the model page configuration * @param functionReferences the function reference configuration * @param discardInheritedModelPages the "discard inherited model pages" flag * @param createContentsLocally the "create contents locally" flag */ public CmsADEConfigData( String basePath, List<CmsResourceTypeConfig> resourceTypeConfig, boolean discardInheritedTypes, List<CmsPropertyConfig> propertyConfig, boolean discardInheritedProperties, List<CmsDetailPageInfo> detailPageInfos, List<CmsModelPageConfig> modelPages, List<CmsFunctionReference> functionReferences, boolean discardInheritedModelPages, boolean createContentsLocally) { m_basePath = basePath; m_ownResourceTypes = resourceTypeConfig; m_ownPropertyConfigurations = propertyConfig; m_ownModelPageConfig = modelPages; m_ownDetailPages = detailPageInfos; m_functionReferences = functionReferences; m_discardInheritedTypes = discardInheritedTypes; m_discardInheritedProperties = discardInheritedProperties; m_discardInheritedModelPages = discardInheritedModelPages; m_createContentsLocally = createContentsLocally; } /** * Creates an empty configuration for a given base path.<p> * * @param basePath the base path * * @return the empty configuration object */ public static CmsADEConfigData emptyConfiguration(String basePath) { return new CmsADEConfigData(basePath); } /** * Generic method to merge lists of named configuration objects.<p> * * The lists are merged such that the configuration objects from the child list rise to the front of the result list, * and two configuration objects will be merged themselves if they share the same name.<p> * * For example, if we have two lists of configuration objects:<p> * * parent: A1, B1, C1<p> * child: D2, B2<p> * * then the resulting list will look like:<p> * * D2, B3, A1, C1<p> * * where B3 is the result of merging B1 and B2.<p> * * @param <C> the type of configuration object * @param parentConfigs the parent configurations * @param childConfigs the child configurations * @return the merged configuration object list */ protected static <C extends I_CmsConfigurationObject<C>> List<C> combineConfigurationElements( List<C> parentConfigs, List<C> childConfigs) { List<C> result = new ArrayList<C>(); Map<String, C> map = new LinkedHashMap<String, C>(); if (parentConfigs != null) { for (C parent : Lists.reverse(parentConfigs)) { map.put(parent.getKey(), parent); } } if (childConfigs == null) { childConfigs = Collections.emptyList(); } for (C child : Lists.reverse(childConfigs)) { String childKey = child.getKey(); if (child.isDisabled()) { map.remove(childKey); } else { C parent = map.get(childKey); map.remove(childKey); C newValue; if (parent != null) { newValue = parent.merge(child); } else { newValue = child; } map.put(childKey, newValue); } } result = new ArrayList<C>(map.values()); Collections.reverse(result); // those multiple "reverse" calls may a bit confusing. They are there because on the one hand we want to keep the // configuration items from one configuration in the same order as they are defined, on the other hand we want // configuration items from a child configuration to rise to the top of the configuration items. // so for example, if the parent configuration has items with the keys A,B,C,E // and the child configuration has items with the keys C,B,D // we want the items of the combined configuration in the order C,B,D,A,E return result; } /** * Gets the list of all detail pages.<p> * * @return the list of all detail pages */ public List<CmsDetailPageInfo> getAllDetailPages() { return getAllDetailPages(true); } /** * Gets a list of all detail pages.<p> * * @param update if true, this method will try to correct the root paths in the returned objects if the corresponding resources have been moved * * @return the list of all detail pages */ public List<CmsDetailPageInfo> getAllDetailPages(boolean update) { checkInitialized(); CmsADEConfigData parentData = parent(); List<CmsDetailPageInfo> parentDetailPages; if (parentData != null) { parentDetailPages = parentData.getAllDetailPages(false); } else { parentDetailPages = Collections.emptyList(); } List<CmsDetailPageInfo> result = mergeDetailPages(parentDetailPages, m_ownDetailPages); if (update) { result = updateUris(result); } return result; } /** * Gets the configuration base path.<p> * * For example, if the configuration file is located at /sites/default/.content/.config, the base path is /sites/default.<p> * * @return the base path of the configuration */ public String getBasePath() { checkInitialized(); return m_basePath; } /** * Gets the content folder path.<p> * * For example, if the configuration file is located at /sites/default/.content/.config, the content folder path is /sites/default/.content * * @return the content folder path */ public String getContentFolderPath() { return CmsStringUtil.joinPaths(m_basePath, CONTENT_FOLDER_NAME); } /** * Returns a list of the creatable resource types.<p> * * @param cms the CMS context used to check whether the resource types are creatable * @return the list of creatable resource type * * @throws CmsException if something goes wrong */ public List<CmsResourceTypeConfig> getCreatableTypes(CmsObject cms) throws CmsException { checkInitialized(); List<CmsResourceTypeConfig> result = new ArrayList<CmsResourceTypeConfig>(); for (CmsResourceTypeConfig typeConfig : getResourceTypes()) { if (typeConfig.checkCreatable(cms)) { result.add(typeConfig); } } return result; } /** * Returns the default model page.<p> * * @return the default model page */ public CmsModelPageConfig getDefaultModelPage() { checkInitialized(); List<CmsModelPageConfig> modelPages = getModelPages(); for (CmsModelPageConfig modelPageConfig : getModelPages()) { if (modelPageConfig.isDefault()) { return modelPageConfig; } } if (modelPages.isEmpty()) { return null; } return modelPages.get(0); } /** * Gets the detail pages for a specific type.<p> * * @param type the type name * * @return the list of detail pages for that type */ public List<CmsDetailPageInfo> getDetailPagesForType(String type) { List<CmsDetailPageInfo> result = new ArrayList<CmsDetailPageInfo>(); for (CmsDetailPageInfo detailpage : getAllDetailPages(true)) { if (detailpage.getType().equals(type)) { result.add(detailpage); } } return result; } /** * Gets the formatter configuration for a resource.<p> * * @param cms the current CMS context * @param res the resource for which the formatter configuration should be retrieved * * @return the configuration of formatters for the resource */ public CmsFormatterConfiguration getFormatters(CmsObject cms, CmsResource res) { int resTypeId = res.getTypeId(); try { I_CmsResourceType resType = OpenCms.getResourceManager().getResourceType(resTypeId); String typeName = resType.getTypeName(); CmsResourceTypeConfig typeConfig = getResourceType(typeName); if ((typeConfig != null) && (typeConfig.getFormatterConfiguration() != null) && !typeConfig.getFormatterConfiguration().getAllFormatters().isEmpty()) { return typeConfig.getFormatterConfiguration(); } return getFormattersFromSchema(cms, res); } catch (CmsLoaderException e) { LOG.warn(e.getLocalizedMessage(), e); return null; } } /** * Gets a named function reference.<p> * * @param name the name of the function reference * * @return the function reference for the given name */ public CmsFunctionReference getFunctionReference(String name) { List<CmsFunctionReference> functionReferences = getFunctionReferences(); for (CmsFunctionReference functionRef : functionReferences) { if (functionRef.getName().equals(name)) { return functionRef; } } return null; } /** * Gets the list of configured function references.<p> * * @return the list of configured function references */ public List<CmsFunctionReference> getFunctionReferences() { return internalGetFunctionReferences(); } /** * Gets the main detail page for a specific type.<p> * * @param type the type name * * @return the main detail page for that type */ public CmsDetailPageInfo getMainDetailPage(String type) { List<CmsDetailPageInfo> detailPages = getDetailPagesForType(type); if ((detailPages == null) || detailPages.isEmpty()) { return null; } return detailPages.get(0); } /** * Gets the list of available model pages.<p> * * @return the list of available model pages */ public List<CmsModelPageConfig> getModelPages() { CmsADEConfigData parentData = parent(); List<CmsModelPageConfig> parentModelPages; if ((parentData != null) && !m_discardInheritedModelPages) { parentModelPages = parentData.getModelPages(); } else { parentModelPages = Collections.emptyList(); } List<CmsModelPageConfig> result = combineConfigurationElements(parentModelPages, m_ownModelPageConfig); return result; } /** * Gets the configuration for the available properties.<p> * * @return the configuration for the available properties */ public List<CmsPropertyConfig> getPropertyConfiguration() { CmsADEConfigData parentData = parent(); List<CmsPropertyConfig> parentProperties; if ((parentData != null) && !m_discardInheritedProperties) { parentProperties = parentData.getPropertyConfiguration(); } else { parentProperties = Collections.emptyList(); } List<CmsPropertyConfig> result = combineConfigurationElements(parentProperties, m_ownPropertyConfigurations); return result; } /** * Gets the property configuration as a map of CmsXmlContentProperty instances.<p> * * @return the map of property configurations */ public Map<String, CmsXmlContentProperty> getPropertyConfigurationAsMap() { Map<String, CmsXmlContentProperty> result = new LinkedHashMap<String, CmsXmlContentProperty>(); for (CmsPropertyConfig propConf : getPropertyConfiguration()) { result.put(propConf.getName(), propConf.getPropertyData()); } return result; } /** * Returns the resource from which this configuration was read.<p> * * @return the resource from which this configuration was read */ public CmsResource getResource() { return m_resource; } /** * Returns the configuration for a specific resource type.<p> * * @param typeName the name of the type * * @return the resource type configuration for that type */ public CmsResourceTypeConfig getResourceType(String typeName) { checkInitialized(); for (CmsResourceTypeConfig type : getResourceTypes()) { if (typeName.equals(type.getTypeName())) { return type; } } return null; } /** * Gets a list of all available resource type configurations.<p> * * @return the available resource type configurations */ public List<CmsResourceTypeConfig> getResourceTypes() { List<CmsResourceTypeConfig> result = internalGetResourceTypes(); for (CmsResourceTypeConfig config : result) { config.initialize(m_cms); } return result; } /** * Gets the searchable resource type configurations.<p> * * @param cms the current CMS context * @return the searchable resource type configurations */ public Collection<CmsResourceTypeConfig> getSearchableTypes(CmsObject cms) { return getResourceTypes(); } /** * Initializes the configuration object.<p> * * @param cms the CMS context to be used for VFS operations */ public void initialize(CmsObject cms) { m_cms = cms; m_initialized = true; } /** * Returns the value of the "create contents locally" flag.<p> * * If this flag is set, contents of types configured in a super-sitemap will be created in the sub-sitemap (if the user * creates them from the sub-sitemap). * * @return the "create contents locally" flag */ public boolean isCreateContentsLocally() { return m_createContentsLocally; } /** * Returns the value of the "discard inherited model pages" flag.<p> * * If this flag is set, inherited model pages will be discarded for this sitemap.<p> * * @return the "discard inherited model pages" flag */ public boolean isDiscardInheritedModelPages() { return m_discardInheritedModelPages; } /** * Returns the value of the "discard inherited properties" flag.<p> * * If this is flag is set, inherited property definitions will be discarded for this sitemap.<p> * * @return the "discard inherited properties" flag.<p> */ public boolean isDiscardInheritedProperties() { return m_discardInheritedProperties; } /** * Returns the value of the "discard inherited types" flag.<p> * * If this flag is set, inherited resource types from a super-sitemap will be discarded for this sitemap.<p> * * @return the "discard inherited types" flag */ public boolean isDiscardInheritedTypes() { return m_discardInheritedTypes; } /** * Returns true if this is a module configuration instead of a normal sitemap configuration.<p> * * @return true if this is a module configuration */ public boolean isModuleConfiguration() { return m_isModuleConfig; } /** * Fetches the parent configuration of this configuration.<p> * * If this configuration is a sitemap configuration with no direct parent configuration, * the module configuration will be returned. If this configuration already is a module configuration, * null will be returned.<p> * * @return the parent configuration */ public CmsADEConfigData parent() { if (m_basePath == null) { return null; } String parentPath = CmsResource.getParentFolder(m_basePath); if (OpenCms.getADEManager() == null) { return null; } CmsADEConfigData result = OpenCms.getADEManager().internalLookupConfiguration(m_cms, parentPath); return result; } /** * Sets the "module configuration" flag.<p> * * @param isModuleConfig true if this configuration should be marked as a module configuration */ public void setIsModuleConfig(boolean isModuleConfig) { checkNotInitialized(); m_isModuleConfig = isModuleConfig; } /** * Sets the configuration file resource.<p> * * @param resource the configuration file resource */ public void setResource(CmsResource resource) { checkNotInitialized(); m_resource = resource; } /** * Checks whether the configuration is initialized and throws an error otherwise.<p> */ protected void checkInitialized() { if (!m_initialized) { throw new IllegalStateException(); } } /** * Checks whether the configuration is *NOT* initialized and throws an error otherwise.<p> */ protected void checkNotInitialized() { if (m_initialized) { throw new IllegalStateException(); } } /** * Creates the content directory for this configuration node if possible.<p> * * @throws CmsException if something goes wrong */ protected void createContentDirectory() throws CmsException { if (!isModuleConfiguration()) { String contentFolder = getContentFolderPath(); if (!m_cms.existsResource(contentFolder)) { m_cms.createResource( contentFolder, OpenCms.getResourceManager().getResourceType(CmsResourceTypeFolder.getStaticTypeName()).getTypeId()); } } } /** * Gets the CMS object used for VFS operations.<p> * * @return the CMS object */ protected CmsObject getCmsObject() { return m_cms; } /** * Helper method to converts a list of detail pages to a map from type names to lists of detail pages for each type.<p> * * @param detailPages the list of detail pages * * @return the map of detail pages */ protected Map<String, List<CmsDetailPageInfo>> getDetailPagesMap(List<CmsDetailPageInfo> detailPages) { Map<String, List<CmsDetailPageInfo>> result = Maps.newHashMap(); for (CmsDetailPageInfo detailpage : detailPages) { String type = detailpage.getType(); if (!result.containsKey(type)) { result.put(type, new ArrayList<CmsDetailPageInfo>()); } result.get(type).add(detailpage); } return result; } /** * Collects the folder types in a map.<p> * * @return the map of folder types * * @throws CmsException if something goes wrong */ protected Map<String, String> getFolderTypes() throws CmsException { Map<String, String> result = new HashMap<String, String>(); CmsObject cms = OpenCms.initCmsObject(m_cms); if (m_isModuleConfig) { Set<String> siteRoots = OpenCms.getSiteManager().getSiteRoots(); for (String siteRoot : siteRoots) { cms.getRequestContext().setSiteRoot(siteRoot); for (CmsResourceTypeConfig config : getResourceTypes()) { String typeName = config.getTypeName(); String folderPath = config.getFolderPath(cms); result.put(CmsStringUtil.joinPaths(folderPath, "/"), typeName); } } } else { for (CmsResourceTypeConfig config : getResourceTypes()) { String typeName = config.getTypeName(); String folderPath = config.getFolderPath(m_cms); result.put(CmsStringUtil.joinPaths(folderPath, "/"), typeName); } } return result; } /** * Gets the formatter configuration for a given type.<p> * * @param type the type for which to get the formatters * * @return the formatter configuration for that type */ protected CmsFormatterConfiguration getFormatters(String type) { CmsResourceTypeConfig typeConfig = getResourceType(type); if ((typeConfig == null) || (typeConfig.getFormatterConfiguration() == null) || (typeConfig.getFormatterConfiguration().getAllFormatters().isEmpty())) { try { CmsXmlContentDefinition contentDefinition = CmsXmlContentDefinition.getContentDefinitionForType( m_cms, type); if (contentDefinition == null) { return null; } return contentDefinition.getContentHandler().getFormatterConfiguration(m_cms, null); } catch (CmsException e) { LOG.error(e.getLocalizedMessage(), e); return null; } } return typeConfig.getFormatterConfiguration(); } /** * Gets the formatters from the schema.<p> * * @param cms the current CMS context * @param res the resource for which the formatters should be retrieved * * @return the formatters from the schema */ protected CmsFormatterConfiguration getFormattersFromSchema(CmsObject cms, CmsResource res) { try { I_CmsXmlContentHandler contentHandler = CmsXmlContentDefinition.getContentHandlerForResource(m_cms, res); return contentHandler.getFormatterConfiguration(cms, res); } catch (CmsException e) { LOG.warn(e.getLocalizedMessage(), e); return CmsFormatterConfiguration.EMPTY_CONFIGURATION; } } /** * Internal method for getting the function references.<p> * * @return the function references */ protected List<CmsFunctionReference> internalGetFunctionReferences() { checkInitialized(); CmsADEConfigData parentData = parent(); if ((parentData == null)) { if (m_isModuleConfig) { return Collections.unmodifiableList(m_functionReferences); } else { return Lists.newArrayList(); } } else { return parentData.internalGetFunctionReferences(); } } /** * Helper method for getting the list of resource types.<p> * * @return the list of resource types */ protected List<CmsResourceTypeConfig> internalGetResourceTypes() { checkInitialized(); CmsADEConfigData parentData = parent(); List<CmsResourceTypeConfig> parentResourceTypes = null; if ((parentData == null) || m_discardInheritedTypes) { parentResourceTypes = Lists.newArrayList(); } else { parentResourceTypes = Lists.newArrayList(); for (CmsResourceTypeConfig typeConfig : parentData.internalGetResourceTypes()) { parentResourceTypes.add(typeConfig.copy()); } } List<CmsResourceTypeConfig> result = combineConfigurationElements(parentResourceTypes, m_ownResourceTypes); if (m_createContentsLocally) { for (CmsResourceTypeConfig typeConfig : result) { typeConfig.updateBasePath(CmsStringUtil.joinPaths(m_basePath, ".content")); } } return result; } /** * Merges two lists of detail pages, one from a parent configuration and one from a child configuration.<p> * * @param parentDetailPages the parent's detail pages * @param ownDetailPages the child's detail pages * * @return the merged detail pages */ protected List<CmsDetailPageInfo> mergeDetailPages( List<CmsDetailPageInfo> parentDetailPages, List<CmsDetailPageInfo> ownDetailPages) { List<CmsDetailPageInfo> result = new ArrayList<CmsDetailPageInfo>(); Map<String, List<CmsDetailPageInfo>> resultDetailPageMap = Maps.newHashMap(); resultDetailPageMap.putAll(getDetailPagesMap(parentDetailPages)); resultDetailPageMap.putAll(getDetailPagesMap(ownDetailPages)); result = new ArrayList<CmsDetailPageInfo>(); for (List<CmsDetailPageInfo> pages : resultDetailPageMap.values()) { result.addAll(pages); } return result; } /** * Merges the parent's data into this object.<p> * * @param parent the parent configuration data */ protected void mergeParent(CmsADEConfigData parent) { List<CmsResourceTypeConfig> parentTypes = null; if (parent != null) { parentTypes = parent.m_ownResourceTypes; } else { parentTypes = Collections.emptyList(); } List<CmsPropertyConfig> parentProperties = null; if (parent != null) { parentProperties = parent.m_ownPropertyConfigurations; } else { parentProperties = Collections.emptyList(); } List<CmsModelPageConfig> parentModelPages = null; if (parent != null) { parentModelPages = parent.m_ownModelPageConfig; } else { parentModelPages = Collections.emptyList(); } List<CmsFunctionReference> parentFunctionRefs = null; if (parent != null) { parentFunctionRefs = parent.m_functionReferences; } else { parentFunctionRefs = Collections.emptyList(); } m_ownResourceTypes = combineConfigurationElements(parentTypes, m_ownResourceTypes); m_ownPropertyConfigurations = combineConfigurationElements(parentProperties, m_ownPropertyConfigurations); m_ownModelPageConfig = combineConfigurationElements(parentModelPages, m_ownModelPageConfig); m_functionReferences = combineConfigurationElements(parentFunctionRefs, m_functionReferences); } /** * Handle the ordering from the module configurations.<p> */ protected void processModuleOrdering() { Collections.sort(m_ownResourceTypes, new Comparator<CmsResourceTypeConfig>() { public int compare(CmsResourceTypeConfig a, CmsResourceTypeConfig b) { return ComparisonChain.start().compare(a.getOrder(), b.getOrder()).compare( a.getTypeName(), b.getTypeName()).result(); } }); Collections.sort(m_ownPropertyConfigurations, new Comparator<CmsPropertyConfig>() { public int compare(CmsPropertyConfig a, CmsPropertyConfig b) { return ComparisonChain.start().compare(a.getOrder(), b.getOrder()).compare(a.getName(), b.getName()).result(); } }); Collections.sort(m_functionReferences, new Comparator<CmsFunctionReference>() { public int compare(CmsFunctionReference a, CmsFunctionReference b) { return ComparisonChain.start().compare(a.getOrder(), b.getOrder()).compare(a.getName(), b.getName()).result(); } }); } /** * Helper method to correct paths in detail page beans if the corresponding resources have been moved.<p> * * @param detailPages the original list of detail pages * * @return the corrected list of detail pages */ protected List<CmsDetailPageInfo> updateUris(List<CmsDetailPageInfo> detailPages) { List<CmsDetailPageInfo> result = new ArrayList<CmsDetailPageInfo>(); for (CmsDetailPageInfo page : detailPages) { CmsUUID structureId = page.getId(); try { String rootPath = OpenCms.getADEManager().getRootPath( structureId, m_cms.getRequestContext().getCurrentProject().isOnlineProject()); CmsDetailPageInfo correctedPage = new CmsDetailPageInfo(structureId, rootPath, page.getType()); result.add(correctedPage); } catch (CmsException e) { LOG.warn(e.getLocalizedMessage(), e); } } return result; } }