/*
* This library is part of OpenCms -
* the Open Source Content Management System
*
* Copyright (c) Alkacon Software GmbH (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.sitemap;
import org.opencms.ade.configuration.CmsADEConfigData;
import org.opencms.ade.configuration.CmsADEManager;
import org.opencms.ade.configuration.CmsFunctionReference;
import org.opencms.ade.configuration.CmsModelPageConfig;
import org.opencms.ade.configuration.CmsResourceTypeConfig;
import org.opencms.ade.detailpage.CmsDetailPageConfigurationWriter;
import org.opencms.ade.detailpage.CmsDetailPageInfo;
import org.opencms.ade.sitemap.shared.CmsClientSitemapEntry;
import org.opencms.ade.sitemap.shared.CmsClientSitemapEntry.EntryType;
import org.opencms.ade.sitemap.shared.CmsDetailPageTable;
import org.opencms.ade.sitemap.shared.CmsNewResourceInfo;
import org.opencms.ade.sitemap.shared.CmsSitemapChange;
import org.opencms.ade.sitemap.shared.CmsSitemapChange.ChangeType;
import org.opencms.ade.sitemap.shared.CmsSitemapClipboardData;
import org.opencms.ade.sitemap.shared.CmsSitemapData;
import org.opencms.ade.sitemap.shared.CmsSitemapInfo;
import org.opencms.ade.sitemap.shared.rpc.I_CmsSitemapService;
import org.opencms.file.CmsFile;
import org.opencms.file.CmsObject;
import org.opencms.file.CmsProject;
import org.opencms.file.CmsProperty;
import org.opencms.file.CmsPropertyDefinition;
import org.opencms.file.CmsResource;
import org.opencms.file.CmsResourceFilter;
import org.opencms.file.CmsUser;
import org.opencms.file.CmsVfsResourceNotFoundException;
import org.opencms.file.history.CmsHistoryResourceHandler;
import org.opencms.file.types.CmsResourceTypeFolder;
import org.opencms.file.types.CmsResourceTypeFolderExtended;
import org.opencms.file.types.CmsResourceTypeXmlContainerPage;
import org.opencms.file.types.I_CmsResourceType;
import org.opencms.flex.CmsFlexController;
import org.opencms.gwt.CmsGwtService;
import org.opencms.gwt.CmsRpcException;
import org.opencms.gwt.CmsTemplateFinder;
import org.opencms.gwt.shared.CmsBrokenLinkBean;
import org.opencms.gwt.shared.CmsClientLock;
import org.opencms.gwt.shared.CmsCoreData;
import org.opencms.gwt.shared.property.CmsClientProperty;
import org.opencms.gwt.shared.property.CmsPropertyModification;
import org.opencms.i18n.CmsLocaleManager;
import org.opencms.json.JSONArray;
import org.opencms.jsp.CmsJspNavBuilder;
import org.opencms.jsp.CmsJspNavElement;
import org.opencms.loader.CmsLoaderException;
import org.opencms.lock.CmsLock;
import org.opencms.main.CmsException;
import org.opencms.main.CmsLog;
import org.opencms.main.OpenCms;
import org.opencms.search.galleries.CmsGallerySearch;
import org.opencms.search.galleries.CmsGallerySearchResult;
import org.opencms.security.CmsPermissionSet;
import org.opencms.security.CmsSecurityException;
import org.opencms.site.CmsSite;
import org.opencms.util.CmsDateUtil;
import org.opencms.util.CmsStringUtil;
import org.opencms.util.CmsUUID;
import org.opencms.workplace.CmsWorkplaceMessages;
import org.opencms.xml.CmsXmlException;
import org.opencms.xml.I_CmsXmlDocument;
import org.opencms.xml.containerpage.CmsContainerBean;
import org.opencms.xml.containerpage.CmsContainerElementBean;
import org.opencms.xml.containerpage.CmsContainerPageBean;
import org.opencms.xml.containerpage.CmsXmlContainerPage;
import org.opencms.xml.containerpage.CmsXmlContainerPageFactory;
import org.opencms.xml.containerpage.CmsXmlDynamicFunctionHandler;
import org.opencms.xml.content.CmsXmlContentFactory;
import org.opencms.xml.content.CmsXmlContentProperty;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.logging.Log;
import com.google.common.collect.ComparisonChain;
import com.google.common.collect.Ordering;
/**
* Handles all RPC services related to the vfs sitemap.<p>
*
* @since 8.0.0
*
* @see org.opencms.ade.sitemap.shared.rpc.I_CmsSitemapService
* @see org.opencms.ade.sitemap.shared.rpc.I_CmsSitemapServiceAsync
*/
public class CmsVfsSitemapService extends CmsGwtService implements I_CmsSitemapService {
/** Helper class for representing information about a lock. */
protected class LockInfo {
/** The lock state. */
private CmsLock m_lock;
/** True if the lock was just locked. */
private boolean m_wasJustLocked;
/**
* Creates a new LockInfo object.<p>
*
* @param lock the lock state
* @param wasJustLocked true if the lock was just locked
*/
public LockInfo(CmsLock lock, boolean wasJustLocked) {
m_lock = lock;
m_wasJustLocked = wasJustLocked;
}
/**
* Returns the lock state.<p>
*
* @return the lock state
*/
public CmsLock getLock() {
return m_lock;
}
/**
* Returns true if the lock was just locked.<p>
*
* @return true if the lock was just locked
*/
public boolean wasJustLocked() {
return m_wasJustLocked;
}
}
/** The configuration key for the functionDetail attribute in the container.info property. */
public static final String KEY_FUNCTION_DETAIL = "functionDetail";
/** The additional user info key for deleted list. */
private static final String ADDINFO_ADE_DELETED_LIST = "ADE_DELETED_LIST";
/** The additional user info key for modified list. */
private static final String ADDINFO_ADE_MODIFIED_LIST = "ADE_MODIFIED_LIST";
/** The static log object for this class. */
private static final Log LOG = CmsLog.getLog(CmsVfsSitemapService.class);
/** The redirect recource type name. */
private static final String RECOURCE_TYPE_NAME_REDIRECT = "htmlredirect";
/** The redirect target XPath. */
private static final String REDIRECT_LINK_TARGET_XPATH = "Link";
/** Serialization uid. */
private static final long serialVersionUID = -7236544324371767330L;
/** The navigation builder. */
private CmsJspNavBuilder m_navBuilder;
/**
* Returns a new configured service instance.<p>
*
* @param request the current request
*
* @return a new service instance
*/
public static CmsVfsSitemapService newInstance(HttpServletRequest request) {
CmsVfsSitemapService service = new CmsVfsSitemapService();
service.setCms(CmsFlexController.getCmsObject(request));
service.setRequest(request);
return service;
}
/**
* @see org.opencms.ade.sitemap.shared.rpc.I_CmsSitemapService#createSubSitemap(org.opencms.util.CmsUUID)
*/
public CmsSitemapChange createSubSitemap(CmsUUID entryId) throws CmsRpcException {
CmsObject cms = getCmsObject();
try {
ensureSession();
CmsResource subSitemapFolder = cms.readResource(entryId);
ensureLock(subSitemapFolder);
String sitePath = cms.getSitePath(subSitemapFolder);
String folderName = CmsStringUtil.joinPaths(sitePath, CmsADEManager.CONFIG_FOLDER_NAME + "/");
String sitemapConfigName = CmsStringUtil.joinPaths(folderName, CmsADEManager.CONFIG_FILE_NAME);
if (!cms.existsResource(folderName)) {
cms.createResource(
folderName,
OpenCms.getResourceManager().getResourceType(CmsADEManager.CONFIG_FOLDER_TYPE).getTypeId());
}
I_CmsResourceType configType = OpenCms.getResourceManager().getResourceType(CmsADEManager.CONFIG_TYPE);
if (cms.existsResource(sitemapConfigName)) {
CmsResource configFile = cms.readResource(sitemapConfigName);
if (configFile.getTypeId() != configType.getTypeId()) {
throw new CmsException(Messages.get().container(
Messages.ERR_CREATING_SUB_SITEMAP_WRONG_CONFIG_FILE_TYPE_2,
sitemapConfigName,
CmsADEManager.CONFIG_TYPE));
}
} else {
cms.createResource(
sitemapConfigName,
OpenCms.getResourceManager().getResourceType(CmsADEManager.CONFIG_TYPE).getTypeId());
}
subSitemapFolder.setType(getEntryPointType());
cms.writeResource(subSitemapFolder);
tryUnlock(subSitemapFolder);
CmsSitemapClipboardData clipboard = getClipboardData();
CmsClientSitemapEntry entry = toClientEntry(
getNavBuilder().getNavigationForResource(sitePath, CmsResourceFilter.ONLY_VISIBLE),
false);
clipboard.addModified(entry);
setClipboardData(clipboard);
CmsSitemapChange result = new CmsSitemapChange(entry.getId(), entry.getSitePath(), ChangeType.modify);
result.setUpdatedEntry(entry);
return result;
} catch (Exception e) {
error(e);
}
return null;
}
/**
* @see org.opencms.ade.sitemap.shared.rpc.I_CmsSitemapService#getChildren(java.lang.String, org.opencms.util.CmsUUID, int)
*/
public CmsClientSitemapEntry getChildren(String entryPointUri, CmsUUID entryId, int levels) throws CmsRpcException {
CmsClientSitemapEntry entry = null;
try {
CmsObject cms = getCmsObject();
//ensure that root ends with a '/' if it's a folder
CmsResource rootRes = cms.readResource(entryId, CmsResourceFilter.ONLY_VISIBLE);
String root = cms.getSitePath(rootRes);
CmsJspNavElement navElement = getNavBuilder().getNavigationForResource(root, CmsResourceFilter.ONLY_VISIBLE);
boolean isRoot = root.equals(entryPointUri);
entry = toClientEntry(navElement, isRoot);
if ((levels > 0) && (isRoot || (rootRes.isFolder() && (!isSubSitemap(navElement))))) {
entry.setSubEntries(getChildren(root, levels, null), null);
}
} catch (Throwable e) {
error(e);
}
return entry;
}
/**
* @see org.opencms.ade.sitemap.shared.rpc.I_CmsSitemapService#mergeSubSitemap(java.lang.String, org.opencms.util.CmsUUID)
*/
public CmsSitemapChange mergeSubSitemap(String entryPoint, CmsUUID subSitemapId) throws CmsRpcException {
CmsObject cms = getCmsObject();
try {
ensureSession();
CmsResource subSitemapFolder = cms.readResource(subSitemapId, CmsResourceFilter.ONLY_VISIBLE);
ensureLock(subSitemapFolder);
subSitemapFolder.setType(OpenCms.getResourceManager().getResourceType(
CmsResourceTypeFolder.RESOURCE_TYPE_NAME).getTypeId());
cms.writeResource(subSitemapFolder);
String sitePath = cms.getSitePath(subSitemapFolder);
String sitemapConfigName = CmsStringUtil.joinPaths(
sitePath,
CmsADEManager.CONFIG_FOLDER_NAME,
CmsADEManager.CONFIG_FILE_NAME);
if (cms.existsResource(sitemapConfigName)) {
cms.deleteResource(sitemapConfigName, CmsResource.DELETE_PRESERVE_SIBLINGS);
}
tryUnlock(subSitemapFolder);
CmsSitemapClipboardData clipboard = getClipboardData();
CmsClientSitemapEntry entry = toClientEntry(
getNavBuilder().getNavigationForResource(
cms.getSitePath(subSitemapFolder),
CmsResourceFilter.ONLY_VISIBLE),
false);
clipboard.addModified(entry);
setClipboardData(clipboard);
entry = getChildren(entryPoint, subSitemapId, 1);
CmsSitemapChange result = new CmsSitemapChange(entry.getId(), entry.getSitePath(), ChangeType.modify);
result.setUpdatedEntry(entry);
return result;
} catch (Exception e) {
error(e);
}
return null;
}
/**
* @see org.opencms.ade.sitemap.shared.rpc.I_CmsSitemapService#prefetch(java.lang.String)
*/
public CmsSitemapData prefetch(String sitemapUri) throws CmsRpcException {
CmsSitemapData result = null;
CmsObject cms = getCmsObject();
try {
String openPath = getRequest().getParameter(CmsCoreData.PARAM_PATH);
if (!isValidOpenPath(cms, openPath)) {
// if no path is supplied, start from root
openPath = "/";
}
CmsADEConfigData configData = OpenCms.getADEManager().lookupConfiguration(
cms,
cms.getRequestContext().addSiteRoot(openPath));
Map<String, CmsXmlContentProperty> propertyConfig = new LinkedHashMap<String, CmsXmlContentProperty>(
configData.getPropertyConfigurationAsMap());
Map<String, CmsClientProperty> parentProperties = generateParentProperties(configData.getBasePath());
String siteRoot = cms.getRequestContext().getSiteRoot();
String exportRfsPrefix = OpenCms.getStaticExportManager().getDefaultRfsPrefix();
CmsSite site = OpenCms.getSiteManager().getSiteForSiteRoot(siteRoot);
boolean isSecure = site.hasSecureServer();
String parentSitemap = null;
if (configData.getBasePath() != null) {
CmsADEConfigData parentConfigData = OpenCms.getADEManager().lookupConfiguration(
cms,
CmsResource.getParentFolder(configData.getBasePath()));
parentSitemap = parentConfigData.getBasePath();
if (parentSitemap != null) {
parentSitemap = cms.getRequestContext().removeSiteRoot(parentSitemap);
}
}
String noEdit = "";
CmsNewResourceInfo defaultNewInfo = null;
List<CmsNewResourceInfo> newResourceInfos = null;
CmsDetailPageTable detailPages = null;
List<CmsNewResourceInfo> resourceTypeInfos = null;
boolean canEditDetailPages = false;
boolean isOnlineProject = CmsProject.isOnlineProject(cms.getRequestContext().getCurrentProject().getUuid());
Locale locale = CmsLocaleManager.getDefaultLocale();
try {
String basePath = configData.getBasePath();
CmsObject rootCms = OpenCms.initCmsObject(cms);
rootCms.getRequestContext().setSiteRoot("");
CmsResource baseDir = rootCms.readResource(basePath, CmsResourceFilter.ONLY_VISIBLE);
OpenCms.getLocaleManager();
locale = CmsLocaleManager.getMainLocale(cms, baseDir);
} catch (CmsException e) {
LOG.warn(e.getLocalizedMessage(), e);
}
detailPages = new CmsDetailPageTable(configData.getAllDetailPages());
if (!isOnlineProject) {
newResourceInfos = getNewResourceInfos(cms, configData, locale);
CmsResource modelResource = null;
if (configData.getDefaultModelPage() != null) {
if (cms.existsResource(configData.getDefaultModelPage().getResource().getStructureId())) {
modelResource = configData.getDefaultModelPage().getResource();
} else {
try {
modelResource = cms.readResource(
cms.getSitePath(configData.getDefaultModelPage().getResource()),
CmsResourceFilter.ONLY_VISIBLE);
} catch (CmsException e) {
LOG.warn(e.getLocalizedMessage(), e);
}
}
}
if ((modelResource == null) && !newResourceInfos.isEmpty()) {
try {
modelResource = cms.readResource(newResourceInfos.get(0).getCopyResourceId());
} catch (CmsException e) {
LOG.warn(e.getLocalizedMessage(), e);
}
}
if (modelResource != null) {
resourceTypeInfos = getResourceTypeInfos(
getCmsObject(),
configData.getResourceTypes(),
configData.getFunctionReferences(),
modelResource,
locale);
try {
defaultNewInfo = createNewResourceInfo(cms, modelResource, locale);
} catch (CmsException e) {
LOG.warn(e.getLocalizedMessage(), e);
}
}
canEditDetailPages = !(configData.isModuleConfiguration());
}
if (isOnlineProject) {
noEdit = Messages.get().getBundle(getWorkplaceLocale()).key(Messages.GUI_SITEMAP_NO_EDIT_ONLINE_0);
}
List<String> allPropNames = getPropertyNames(cms);
String returnCode = getRequest().getParameter(CmsCoreData.PARAM_RETURNCODE);
if (!isValidReturnCode(returnCode)) {
returnCode = null;
}
cms.getRequestContext().getSiteRoot();
result = new CmsSitemapData(
(new CmsTemplateFinder(cms)).getTemplates(),
propertyConfig,
getClipboardData(),
parentProperties,
allPropNames,
exportRfsPrefix,
isSecure,
noEdit,
isDisplayToolbar(getRequest()),
defaultNewInfo,
newResourceInfos,
createResourceTypeInfo(OpenCms.getResourceManager().getResourceType(RECOURCE_TYPE_NAME_REDIRECT), null),
getSitemapInfo(configData.getBasePath()),
parentSitemap,
getRootEntry(configData.getBasePath(), openPath),
openPath,
30,
detailPages,
resourceTypeInfos,
returnCode,
canEditDetailPages);
} catch (Throwable e) {
error(e);
}
return result;
}
/**
* @see org.opencms.ade.sitemap.shared.rpc.I_CmsSitemapService#save(java.lang.String, org.opencms.ade.sitemap.shared.CmsSitemapChange)
*/
public CmsSitemapChange save(String entryPoint, CmsSitemapChange change) throws CmsRpcException {
CmsSitemapChange result = null;
try {
result = saveInternal(entryPoint, change);
} catch (Exception e) {
error(e);
}
return result;
}
/**
* @see org.opencms.ade.sitemap.shared.rpc.I_CmsSitemapService#saveSync(java.lang.String, org.opencms.ade.sitemap.shared.CmsSitemapChange)
*/
public CmsSitemapChange saveSync(String entryPoint, CmsSitemapChange change) throws CmsRpcException {
return save(entryPoint, change);
}
/**
* Creates a "broken link" bean based on a resource.<p>
*
* @param resource the resource
*
* @return the "broken link" bean with the data from the resource
*
* @throws CmsException if something goes wrong
*/
protected CmsBrokenLinkBean createSitemapBrokenLinkBean(CmsResource resource) throws CmsException {
CmsObject cms = getCmsObject();
CmsProperty titleProp = cms.readPropertyObject(resource, CmsPropertyDefinition.PROPERTY_TITLE, true);
String defaultTitle = "";
String title = titleProp.getValue(defaultTitle);
String path = cms.getSitePath(resource);
String subtitle = path;
return new CmsBrokenLinkBean(title, subtitle);
}
/**
* Locks the given resource with a temporary, if not already locked by the current user.
* Will throw an exception if the resource could not be locked for the current user.<p>
*
* @param resource the resource to lock
*
* @return the assigned lock
*
* @throws CmsException if the resource could not be locked
*/
protected LockInfo ensureLockAndGetInfo(CmsResource resource) throws CmsException {
CmsObject cms = getCmsObject();
boolean justLocked = false;
List<CmsResource> blockingResources = cms.getBlockingLockedResources(resource);
if ((blockingResources != null) && !blockingResources.isEmpty()) {
throw new CmsException(org.opencms.gwt.Messages.get().container(
org.opencms.gwt.Messages.ERR_RESOURCE_HAS_BLOCKING_LOCKED_CHILDREN_1,
cms.getSitePath(resource)));
}
CmsUser user = cms.getRequestContext().getCurrentUser();
CmsLock lock = cms.getLock(resource);
if (!lock.isOwnedBy(user)) {
cms.lockResourceTemporary(resource);
lock = cms.getLock(resource);
justLocked = true;
} else if (!lock.isOwnedInProjectBy(user, cms.getRequestContext().getCurrentProject())) {
cms.changeLock(resource);
lock = cms.getLock(resource);
justLocked = true;
}
return new LockInfo(lock, justLocked);
}
/**
* Internal method for saving a sitemap.<p>
*
* @param entryPoint the URI of the sitemap to save
* @param change the change to save
*
* @return list of changed sitemap entries
*
* @throws CmsException
*/
protected CmsSitemapChange saveInternal(String entryPoint, CmsSitemapChange change) throws CmsException {
ensureSession();
switch (change.getChangeType()) {
case clipboardOnly:
// do nothing
break;
case remove:
change = removeEntryFromNavigation(change);
break;
case undelete:
change = undelete(change);
break;
default:
change = applyChange(entryPoint, change);
}
setClipboardData(change.getClipBoardData());
return change;
}
/**
* Converts a sequence of properties to a map of client-side property beans.<p>
*
* @param props the sequence of properties
* @param preserveOrigin if true, the origin of the properties should be copied to the client properties
*
* @return the map of client properties
*
*/
Map<String, CmsClientProperty> createClientProperties(Iterable<CmsProperty> props, boolean preserveOrigin) {
Map<String, CmsClientProperty> result = new HashMap<String, CmsClientProperty>();
for (CmsProperty prop : props) {
CmsClientProperty clientProp = createClientProperty(prop, preserveOrigin);
result.put(prop.getName(), clientProp);
}
return result;
}
/**
* Removes unnecessary locales from a container page.<p>
*
* @param containerPage the container page which should be changed
* @param localeRes the resource used to determine the locale
*
* @throws CmsException if something goes wrong
*/
void ensureSingleLocale(CmsXmlContainerPage containerPage, CmsResource localeRes) throws CmsException {
CmsObject cms = getCmsObject();
Locale mainLocale = CmsLocaleManager.getMainLocale(cms, localeRes);
OpenCms.getLocaleManager();
Locale defaultLocale = CmsLocaleManager.getDefaultLocale();
if (containerPage.hasLocale(mainLocale)) {
removeAllLocalesExcept(containerPage, mainLocale);
// remove other locales
} else if (containerPage.hasLocale(defaultLocale)) {
containerPage.copyLocale(defaultLocale, mainLocale);
removeAllLocalesExcept(containerPage, mainLocale);
} else if (containerPage.getLocales().size() > 0) {
containerPage.copyLocale(containerPage.getLocales().get(0), mainLocale);
removeAllLocalesExcept(containerPage, mainLocale);
} else {
containerPage.addLocale(cms, mainLocale);
}
}
/**
* Gets the properties of a resource as a map of client properties.<p>
*
* @param cms the CMS context to use
* @param res the resource whose properties to read
* @param search true if the inherited properties should be read
*
* @return the client properties as a map
*
* @throws CmsException if something goes wrong
*/
Map<String, CmsClientProperty> getClientProperties(CmsObject cms, CmsResource res, boolean search)
throws CmsException {
List<CmsProperty> props = cms.readPropertyObjects(res, search);
Map<String, CmsClientProperty> result = createClientProperties(props, false);
return result;
}
/**
* Adds a function detail element to a container page.<p>
*
* @param cms the current CMS context
* @param page the container page which should be changed
* @param containerName the name of the container which should be used for function detail elements
* @param elementId the structure id of the element to add
* @param formatterId the structure id of the formatter for the element
*
* @throws CmsException if something goes wrong
*/
private void addFunctionDetailElement(
CmsObject cms,
CmsXmlContainerPage page,
String containerName,
CmsUUID elementId,
CmsUUID formatterId) throws CmsException {
List<Locale> pageLocales = page.getLocales();
for (Locale locale : pageLocales) {
CmsContainerPageBean bean = page.getContainerPage(cms, locale);
List<CmsContainerBean> containerBeans = new ArrayList<CmsContainerBean>();
Collection<CmsContainerBean> originalContainers = bean.getContainers().values();
if ((containerName == null) && !originalContainers.isEmpty()) {
CmsContainerBean firstContainer = originalContainers.iterator().next();
containerName = firstContainer.getName();
}
boolean foundContainer = false;
for (CmsContainerBean cntBean : originalContainers) {
boolean isDetailTarget = cntBean.getName().equals(containerName);
if (isDetailTarget && !foundContainer) {
foundContainer = true;
List<CmsContainerElementBean> newElems = new ArrayList<CmsContainerElementBean>();
newElems.addAll(cntBean.getElements());
CmsContainerElementBean newElement = new CmsContainerElementBean(
elementId,
formatterId,
new HashMap<String, String>(),
false);
newElems.add(0, newElement);
CmsContainerBean newCntBean = new CmsContainerBean(cntBean.getName(), cntBean.getType(), newElems);
containerBeans.add(newCntBean);
} else {
containerBeans.add(cntBean);
}
}
if (!foundContainer) {
throw new CmsException(Messages.get().container(
Messages.ERR_NO_FUNCTION_DETAIL_CONTAINER_1,
page.getFile().getRootPath()));
}
CmsContainerPageBean bean2 = new CmsContainerPageBean(locale, new ArrayList<CmsContainerBean>(
containerBeans));
page.writeContainerPage(cms, locale, bean2);
}
}
/**
* Applys the given change to the VFS.<p>
*
* @param entryPoint the sitemap entry-point
* @param change the change
*
* @return the updated entry
*
* @throws CmsException if something goes wrong
*/
private CmsSitemapChange applyChange(String entryPoint, CmsSitemapChange change) throws CmsException {
CmsObject cms = getCmsObject();
CmsResource configFile = null;
// lock the config file first, to avoid half done changes
if (change.hasDetailPageInfos()) {
CmsADEConfigData configData = OpenCms.getADEManager().lookupConfiguration(
cms,
cms.getRequestContext().addSiteRoot(entryPoint));
if (!configData.isModuleConfiguration() && (configData.getResource() != null)) {
configFile = configData.getResource();
}
if (configFile != null) {
ensureLock(configFile);
}
}
if (change.isNew()) {
CmsClientSitemapEntry newEntry = createNewEntry(entryPoint, change);
change.setUpdatedEntry(newEntry);
change.setEntryId(newEntry.getId());
} else if (change.getChangeType() == ChangeType.delete) {
delete(change);
} else if (change.getEntryId() != null) {
modifyEntry(change);
}
if (change.hasDetailPageInfos() && (configFile != null)) {
saveDetailPages(change.getDetailPageInfos(), configFile, change.getEntryId());
tryUnlock(configFile);
}
return change;
}
/**
* Changes the navigation for a moved entry and its neighbors.<p>
*
* @param change the sitemap change
* @param entryFolder the moved entry
*
* @throws CmsException if something goes wrong
*/
private void applyNavigationChanges(CmsSitemapChange change, CmsResource entryFolder) throws CmsException {
CmsObject cms = getCmsObject();
String parentPath = null;
if (change.hasNewParent()) {
CmsResource parent = cms.readResource(change.getParentId());
parentPath = cms.getSitePath(parent);
} else {
parentPath = CmsResource.getParentFolder(cms.getSitePath(entryFolder));
}
List<CmsJspNavElement> navElements = getNavBuilder().getNavigationForFolder(
parentPath,
true,
CmsResourceFilter.ONLY_VISIBLE);
CmsSitemapNavPosCalculator npc = new CmsSitemapNavPosCalculator(navElements, entryFolder, change.getPosition());
List<CmsJspNavElement> navs = npc.getNavigationChanges();
List<CmsResource> needToUnlock = new ArrayList<CmsResource>();
try {
for (CmsJspNavElement nav : navs) {
LockInfo lockInfo = ensureLockAndGetInfo(nav.getResource());
if (!nav.getResource().equals(entryFolder) && lockInfo.wasJustLocked()) {
needToUnlock.add(nav.getResource());
}
}
for (CmsJspNavElement nav : navs) {
CmsProperty property = new CmsProperty(
CmsPropertyDefinition.PROPERTY_NAVPOS,
"" + nav.getNavPosition(),
null);
cms.writePropertyObject(cms.getSitePath(nav.getResource()), property);
}
} finally {
for (CmsResource lockedRes : needToUnlock) {
try {
cms.unlockResource(lockedRes);
} catch (CmsException e) {
// we catch this because we still want to unlock the other resources
LOG.error(e.getLocalizedMessage(), e);
}
}
}
}
/**
* Creates a client property bean from a server-side property.<p>
*
* @param prop the property from which to create the client property
* @param preserveOrigin if true, the origin will be copied into the new object
*
* @return the new client property
*/
private CmsClientProperty createClientProperty(CmsProperty prop, boolean preserveOrigin) {
CmsClientProperty result = new CmsClientProperty(
prop.getName(),
prop.getStructureValue(),
prop.getResourceValue());
if (preserveOrigin) {
result.setOrigin(prop.getOrigin());
}
return result;
}
/**
* Creates a new page in navigation.<p>
*
* @param entryPoint the site-map entry-point
* @param change the new change
*
* @return the updated entry
*
* @throws CmsException if something goes wrong
*/
private CmsClientSitemapEntry createNewEntry(String entryPoint, CmsSitemapChange change) throws CmsException {
CmsObject cms = getCmsObject();
CmsClientSitemapEntry newEntry = null;
if (change.getParentId() != null) {
CmsResource parentFolder = cms.readResource(change.getParentId(), CmsResourceFilter.ONLY_VISIBLE);
String entryPath = "";
CmsResource entryFolder = null;
CmsResource newRes = null;
byte[] content = null;
List<CmsProperty> properties = Collections.emptyList();
CmsResource copyPage = null;
if (change.getNewCopyResourceId() != null) {
copyPage = cms.readResource(change.getNewCopyResourceId(), CmsResourceFilter.ONLY_VISIBLE);
content = cms.readFile(copyPage).getContents();
properties = cms.readPropertyObjects(copyPage, false);
}
if (isRedirectType(change.getNewResourceTypeId())) {
entryPath = CmsStringUtil.joinPaths(cms.getSitePath(parentFolder), change.getName());
newRes = cms.createResource(
entryPath,
change.getNewResourceTypeId(),
null,
Collections.singletonList(new CmsProperty(
CmsPropertyDefinition.PROPERTY_TITLE,
change.getName(),
null)));
cms.writePropertyObjects(newRes, generateInheritProperties(change, newRes));
applyNavigationChanges(change, newRes);
} else {
String entryFolderPath = CmsStringUtil.joinPaths(cms.getSitePath(parentFolder), change.getName() + "/");
boolean idWasNull = change.getEntryId() == null;
// we don'T really need to create a folder object here anymore.
if (idWasNull) {
// need this for calculateNavPosition, even though the id will get overwritten
change.setEntryId(new CmsUUID());
}
boolean isFunctionDetail = false;
if (change.getCreateParameter() != null) {
if (CmsUUID.isValidUUID(change.getCreateParameter())) {
isFunctionDetail = true;
}
}
entryFolder = new CmsResource(
change.getEntryId(),
new CmsUUID(),
entryFolderPath,
CmsResourceTypeFolder.getStaticTypeId(),
true,
0,
cms.getRequestContext().getCurrentProject().getUuid(),
CmsResource.STATE_NEW,
System.currentTimeMillis(),
cms.getRequestContext().getCurrentUser().getId(),
System.currentTimeMillis(),
cms.getRequestContext().getCurrentUser().getId(),
CmsResource.DATE_RELEASED_DEFAULT,
CmsResource.DATE_EXPIRED_DEFAULT,
1,
0,
System.currentTimeMillis(),
0);
List<CmsProperty> folderProperties = generateInheritProperties(change, entryFolder);
entryFolder = cms.createResource(
entryFolderPath,
OpenCms.getResourceManager().getResourceType(CmsResourceTypeFolder.getStaticTypeName()).getTypeId(),
null,
folderProperties);
if (idWasNull) {
change.setEntryId(entryFolder.getStructureId());
}
applyNavigationChanges(change, entryFolder);
entryPath = CmsStringUtil.joinPaths(entryFolderPath, "index.html");
boolean isContainerPage = change.getNewResourceTypeId() == CmsResourceTypeXmlContainerPage.getContainerPageTypeIdSafely();
if (isContainerPage && (copyPage != null)) {
// do *NOT* get this from the cache, because we perform some destructive operation on the XML content
CmsXmlContainerPage page = CmsXmlContainerPageFactory.unmarshal(
cms,
cms.readFile(copyPage),
true,
true);
ensureSingleLocale(page, entryFolder);
if (isFunctionDetail) {
String functionDetailContainer = getFunctionDetailContainerName(parentFolder);
CmsUUID functionStructureId = new CmsUUID(change.getCreateParameter());
CmsResource functionFormatter = cms.readResource(
CmsXmlDynamicFunctionHandler.FORMATTER_PATH,
CmsResourceFilter.ONLY_VISIBLE);
addFunctionDetailElement(
cms,
page,
functionDetailContainer,
functionStructureId,
functionFormatter.getStructureId());
}
content = page.marshal();
}
newRes = cms.createResource(entryPath, change.getNewResourceTypeId(), content, properties);
cms.writePropertyObjects(newRes, generateOwnProperties(change));
}
if (entryFolder != null) {
tryUnlock(entryFolder);
String sitePath = cms.getSitePath(entryFolder);
newEntry = toClientEntry(
getNavBuilder().getNavigationForResource(sitePath, CmsResourceFilter.ONLY_VISIBLE),
false);
newEntry.setSubEntries(getChildren(sitePath, 1, null), null);
newEntry.setChildrenLoadedInitially(true);
}
if (newRes != null) {
tryUnlock(newRes);
}
if (newEntry == null) {
newEntry = toClientEntry(
getNavBuilder().getNavigationForResource(cms.getSitePath(newRes), CmsResourceFilter.ONLY_VISIBLE),
false);
}
// mark position as not set
newEntry.setPosition(-1);
newEntry.setNew(true);
change.getClipBoardData().getModifications().remove(null);
change.getClipBoardData().getModifications().put(newEntry.getId(), newEntry);
}
return newEntry;
}
/**
* Creates a new resource info to a given model page resource.<p>
*
* @param cms the current CMS context
* @param modelResource the model page resource
* @param locale the locale used for retrieving descriptions/titles
*
* @return the new resource info
*
* @throws CmsException if something goes wrong
*/
private CmsNewResourceInfo createNewResourceInfo(CmsObject cms, CmsResource modelResource, Locale locale)
throws CmsException {
// if model page got overwritten by another resource, reread from site path
if (!cms.existsResource(modelResource.getStructureId(), CmsResourceFilter.ONLY_VISIBLE)) {
modelResource = cms.readResource(cms.getSitePath(modelResource), CmsResourceFilter.ONLY_VISIBLE);
}
int typeId = modelResource.getTypeId();
String name = OpenCms.getResourceManager().getResourceType(typeId).getTypeName();
String title = cms.readPropertyObject(modelResource, CmsPropertyDefinition.PROPERTY_TITLE, false).getValue();
String description = cms.readPropertyObject(modelResource, CmsPropertyDefinition.PROPERTY_DESCRIPTION, false).getValue();
try {
CmsGallerySearchResult result = CmsGallerySearch.searchById(cms, modelResource.getStructureId(), locale);
if (!CmsStringUtil.isEmptyOrWhitespaceOnly(result.getTitle())) {
title = result.getTitle();
}
if (!CmsStringUtil.isEmptyOrWhitespaceOnly(result.getDescription())) {
description = result.getDescription();
}
} catch (CmsException e) {
LOG.warn(e.getLocalizedMessage(), e);
}
boolean editable = false;
try {
CmsResource freshModelResource = cms.readResource(
modelResource.getStructureId(),
CmsResourceFilter.ONLY_VISIBLE);
editable = cms.hasPermissions(
freshModelResource,
CmsPermissionSet.ACCESS_WRITE,
false,
CmsResourceFilter.DEFAULT);
} catch (CmsException e) {
LOG.warn(e.getLocalizedMessage(), e);
}
CmsNewResourceInfo info = new CmsNewResourceInfo(
typeId,
name,
title,
description,
modelResource.getStructureId(),
editable,
description);
Float navpos = null;
try {
CmsProperty navposProp = cms.readPropertyObject(modelResource, CmsPropertyDefinition.PROPERTY_NAVPOS, true);
String navposStr = navposProp.getValue();
if (navposStr != null) {
try {
navpos = Float.valueOf(navposStr);
} catch (NumberFormatException e) {
// noop
}
}
} catch (CmsException e) {
LOG.warn(e.getLocalizedMessage(), e);
}
info.setNavPos(navpos);
info.setDate(CmsDateUtil.getDate(
new Date(modelResource.getDateLastModified()),
DateFormat.LONG,
getWorkplaceLocale()));
info.setVfsPath(modelResource.getRootPath());
return info;
}
/**
* Creates a resource type info bean for a given resource type.<p>
*
* @param resType the resource type
* @param copyResource the structure id of the copy resource
*
* @return the resource type info bean
*/
private CmsNewResourceInfo createResourceTypeInfo(I_CmsResourceType resType, CmsResource copyResource) {
String name = resType.getTypeName();
Locale locale = getWorkplaceLocale();
String subtitle = CmsWorkplaceMessages.getResourceTypeDescription(locale, name);
if (CmsStringUtil.isEmptyOrWhitespaceOnly(subtitle)) {
subtitle = CmsWorkplaceMessages.getResourceTypeName(locale, name);
}
if (copyResource != null) {
return new CmsNewResourceInfo(
copyResource.getTypeId(),
name,
CmsWorkplaceMessages.getResourceTypeName(locale, name),
CmsWorkplaceMessages.getResourceTypeDescription(locale, name),
copyResource.getStructureId(),
false,
subtitle);
} else {
return new CmsNewResourceInfo(resType.getTypeId(), name, CmsWorkplaceMessages.getResourceTypeName(
locale,
name), CmsWorkplaceMessages.getResourceTypeDescription(locale, name), null, false, subtitle);
}
}
/**
* Deletes a resource according to the change data.<p>
*
* @param change the change data
*
* @return CmsClientSitemapEntry always null
*
*
* @throws CmsException if something goes wrong
*/
private CmsClientSitemapEntry delete(CmsSitemapChange change) throws CmsException {
CmsObject cms = getCmsObject();
CmsResource resource = cms.readResource(change.getEntryId(), CmsResourceFilter.ONLY_VISIBLE);
ensureLock(resource);
cms.deleteResource(cms.getSitePath(resource), CmsResource.DELETE_PRESERVE_SIBLINGS);
tryUnlock(resource);
return null;
}
/**
* Generates a client side lock info object representing the current lock state of the given resource.<p>
*
* @param resource the resource
*
* @return the client lock
*
* @throws CmsException if something goes wrong
*/
private CmsClientLock generateClientLock(CmsResource resource) throws CmsException {
CmsObject cms = getCmsObject();
CmsLock lock = cms.getLock(resource);
CmsClientLock clientLock = new CmsClientLock();
clientLock.setLockType(CmsClientLock.LockType.valueOf(lock.getType().getMode()));
CmsUUID ownerId = lock.getUserId();
if (!lock.isUnlocked() && (ownerId != null)) {
clientLock.setLockOwner(cms.readUser(ownerId).getDisplayName(cms, cms.getRequestContext().getLocale()));
clientLock.setOwnedByUser(cms.getRequestContext().getCurrentUser().getId().equals(ownerId));
}
return clientLock;
}
/**
* Generates a list of property object to save to the sitemap entry folder to apply the given change.<p>
*
* @param change the change
* @param entryFolder the entry folder
*
* @return the property objects
*/
private List<CmsProperty> generateInheritProperties(CmsSitemapChange change, CmsResource entryFolder) {
List<CmsProperty> result = new ArrayList<CmsProperty>();
Map<String, CmsClientProperty> clientProps = change.getOwnInternalProperties();
if (clientProps != null) {
for (CmsClientProperty clientProp : clientProps.values()) {
CmsProperty prop = new CmsProperty(
clientProp.getName(),
clientProp.getStructureValue(),
clientProp.getResourceValue());
result.add(prop);
}
}
result.add(new CmsProperty(CmsPropertyDefinition.PROPERTY_TITLE, change.getName(), null));
return result;
}
/**
* Generates a list of property object to save to the sitemap entry resource to apply the given change.<p>
*
* @param change the change
*
* @return the property objects
*/
private List<CmsProperty> generateOwnProperties(CmsSitemapChange change) {
List<CmsProperty> result = new ArrayList<CmsProperty>();
Map<String, CmsClientProperty> clientProps = change.getDefaultFileProperties();
if (clientProps != null) {
for (CmsClientProperty clientProp : clientProps.values()) {
CmsProperty prop = new CmsProperty(
clientProp.getName(),
clientProp.getStructureValue(),
clientProp.getResourceValue());
result.add(prop);
}
}
result.add(new CmsProperty(CmsPropertyDefinition.PROPERTY_TITLE, change.getName(), null));
return result;
}
/**
* Generates a list of property values inherited to the site-map root entry.<p>
*
* @param rootPath the root entry name
*
* @return the list of property values inherited to the site-map root entry
*
* @throws CmsException if something goes wrong reading the properties
*/
private Map<String, CmsClientProperty> generateParentProperties(String rootPath) throws CmsException {
CmsObject cms = getCmsObject();
if (rootPath == null) {
rootPath = cms.getRequestContext().addSiteRoot("/");
}
CmsObject rootCms = OpenCms.initCmsObject(cms);
rootCms.getRequestContext().setSiteRoot("");
String parentRootPath = CmsResource.getParentFolder(rootPath);
Map<String, CmsClientProperty> result = new HashMap<String, CmsClientProperty>();
if (parentRootPath != null) {
List<CmsProperty> props = rootCms.readPropertyObjects(parentRootPath, true);
for (CmsProperty prop : props) {
CmsClientProperty clientProp = createClientProperty(prop, true);
result.put(clientProp.getName(), clientProp);
}
}
return result;
}
/**
* Returns the sitemap children for the given path with all descendants up to the given level or to the given target path, ie.
* <dl><dt>levels=1 </dt><dd>only children</dd><dt>levels=2</dt><dd>children and great children</dd></dl>
* and so on.<p>
*
* @param root the site relative root
* @param levels the levels to recurse
* @param targetPath the target path
*
* @return the sitemap children
*
* @throws CmsException if something goes wrong
*/
private List<CmsClientSitemapEntry> getChildren(String root, int levels, String targetPath) throws CmsException {
List<CmsClientSitemapEntry> children = new ArrayList<CmsClientSitemapEntry>();
int i = 0;
for (CmsJspNavElement navElement : getNavBuilder().getNavigationForFolder(
root,
true,
CmsResourceFilter.ONLY_VISIBLE)) {
CmsClientSitemapEntry child = toClientEntry(navElement, false);
if (child != null) {
child.setPosition(i);
children.add(child);
int nextLevels = levels;
if ((nextLevels == 1) && (targetPath != null) && targetPath.startsWith(child.getSitePath())) {
nextLevels = 2;
}
if (child.isFolderType() && ((nextLevels > 1) || (nextLevels == -1)) && !isSubSitemap(navElement)) {
child.setSubEntries(getChildren(child.getSitePath(), nextLevels - 1, targetPath), null);
child.setChildrenLoadedInitially(true);
}
i++;
}
}
return children;
}
/**
* Returns the clipboard data from the current user.<p>
*
* @return the clipboard data
*/
private CmsSitemapClipboardData getClipboardData() {
CmsSitemapClipboardData result = new CmsSitemapClipboardData();
result.setModifications(getModifiedList());
result.setDeletions(getDeletedList());
return result;
}
/**
* Returns the deleted list from the current user.<p>
*
* @return the deleted list
*/
private LinkedHashMap<CmsUUID, CmsClientSitemapEntry> getDeletedList() {
CmsObject cms = getCmsObject();
CmsUser user = cms.getRequestContext().getCurrentUser();
Object obj = user.getAdditionalInfo(ADDINFO_ADE_DELETED_LIST);
LinkedHashMap<CmsUUID, CmsClientSitemapEntry> result = new LinkedHashMap<CmsUUID, CmsClientSitemapEntry>();
if (obj instanceof String) {
try {
JSONArray array = new JSONArray((String)obj);
for (int i = 0; i < array.length(); i++) {
try {
CmsUUID delId = new CmsUUID(array.getString(i));
CmsResource res = cms.readResource(delId, CmsResourceFilter.ALL);
if (res.getState().isDeleted()) {
// make sure resource is still deleted
CmsClientSitemapEntry delEntry = new CmsClientSitemapEntry();
delEntry.setSitePath(cms.getSitePath(res));
delEntry.setOwnProperties(getClientProperties(cms, res, false));
delEntry.setName(res.getName());
delEntry.setVfsPath(cms.getSitePath(res));
delEntry.setEntryType(res.isFolder() ? EntryType.folder : isRedirectType(res.getTypeId())
? EntryType.redirect
: EntryType.leaf);
delEntry.setId(delId);
result.put(delId, delEntry);
}
} catch (Throwable e) {
// should never happen, catches wrong or no longer existing values
LOG.warn(e.getLocalizedMessage());
}
}
} catch (Throwable e) {
// should never happen, catches json parsing
LOG.warn(e.getLocalizedMessage());
}
}
return result;
}
/**
* Gets the type id for entry point folders.<p>
*
* @return the type id for entry point folders
*
* @throws CmsException if something goes wrong
*/
private int getEntryPointType() throws CmsException {
return OpenCms.getResourceManager().getResourceType(CmsResourceTypeFolderExtended.TYPE_ENTRY_POINT).getTypeId();
}
/**
* Gets the container name for function detail elements depending on the parent folder.<p>
*
* @param parent the parent folder
* @return the name of the function detail container
*/
private String getFunctionDetailContainerName(CmsResource parent) {
try {
CmsObject cms = getCmsObject();
CmsObject rootCms = OpenCms.initCmsObject(cms);
rootCms.getRequestContext().setSiteRoot("");
CmsProperty templateProp = cms.readPropertyObject(parent, CmsPropertyDefinition.PROPERTY_TEMPLATE, true);
String templateVal = templateProp.getValue();
if (templateVal == null) {
return null;
}
CmsResource templateRes;
try {
templateRes = cms.readResource(templateVal, CmsResourceFilter.ONLY_VISIBLE);
} catch (CmsVfsResourceNotFoundException e) {
templateRes = rootCms.readResource(templateVal, CmsResourceFilter.ONLY_VISIBLE);
}
CmsProperty containerInfoProp = cms.readPropertyObject(
templateRes,
CmsPropertyDefinition.PROPERTY_CONTAINER_INFO,
true);
String containerInfo = containerInfoProp.getValue() == null ? "" : containerInfoProp.getValue();
Map<String, String> attrs = CmsStringUtil.splitAsMap(containerInfo, "|", "=");
String functionDetailContainerName = attrs.get(KEY_FUNCTION_DETAIL);
return functionDetailContainerName;
} catch (CmsException e) {
LOG.warn(e.getLocalizedMessage(), e);
return null;
}
}
/**
* Returns the modified list from the current user.<p>
*
* @return the modified list
*/
private LinkedHashMap<CmsUUID, CmsClientSitemapEntry> getModifiedList() {
CmsObject cms = getCmsObject();
CmsUser user = cms.getRequestContext().getCurrentUser();
Object obj = user.getAdditionalInfo(ADDINFO_ADE_MODIFIED_LIST);
LinkedHashMap<CmsUUID, CmsClientSitemapEntry> result = new LinkedHashMap<CmsUUID, CmsClientSitemapEntry>();
if (obj instanceof String) {
try {
JSONArray array = new JSONArray((String)obj);
for (int i = 0; i < array.length(); i++) {
try {
CmsUUID modId = new CmsUUID(array.getString(i));
CmsResource res = cms.readResource(modId, CmsResourceFilter.ONLY_VISIBLE);
String sitePath = cms.getSitePath(res);
CmsJspNavElement navEntry = getNavBuilder().getNavigationForResource(
sitePath,
CmsResourceFilter.ONLY_VISIBLE);
if (navEntry.isInNavigation()) {
CmsClientSitemapEntry modEntry = toClientEntry(navEntry, false);
result.put(modId, modEntry);
}
} catch (Throwable e) {
// should never happen, catches wrong or no longer existing values
LOG.warn(e.getLocalizedMessage());
}
}
} catch (Throwable e) {
// should never happen, catches json parsing
LOG.warn(e.getLocalizedMessage());
}
}
return result;
}
/**
* Returns a navigation builder reference.<p>
*
* @return the navigation builder
*/
private CmsJspNavBuilder getNavBuilder() {
if (m_navBuilder == null) {
m_navBuilder = new CmsJspNavBuilder(getCmsObject());
}
return m_navBuilder;
}
/**
* Returns the new resource infos.<p>
*
* @param cms the current CMS context
* @param configData the configuration data from which the new resource infos should be read
* @param locale locale used for retrieving descriptions/titles
*
* @return the new resource infos
*/
private List<CmsNewResourceInfo> getNewResourceInfos(CmsObject cms, CmsADEConfigData configData, Locale locale) {
List<CmsNewResourceInfo> result = new ArrayList<CmsNewResourceInfo>();
for (CmsModelPageConfig modelConfig : configData.getModelPages()) {
try {
result.add(createNewResourceInfo(cms, modelConfig.getResource(), locale));
} catch (CmsException e) {
LOG.debug(e.getLocalizedMessage(), e);
}
}
Collections.sort(result, new Comparator<CmsNewResourceInfo>() {
public int compare(CmsNewResourceInfo a, CmsNewResourceInfo b) {
return ComparisonChain.start().compare(a.getNavPos(), b.getNavPos(), Ordering.natural().nullsLast()).result();
}
});
return result;
}
/**
* Gets the names of all available properties.<p>
*
* @param cms the CMS context
*
* @return the list of all property names
*
* @throws CmsException
*/
private List<String> getPropertyNames(CmsObject cms) throws CmsException {
List<CmsPropertyDefinition> propDefs = cms.readAllPropertyDefinitions();
List<String> result = new ArrayList<String>();
for (CmsPropertyDefinition propDef : propDefs) {
result.add(propDef.getName());
}
return result;
}
/**
* Gets the resource type info beans for types for which new detail pages can be created.<p>
*
* @param cms the current CMS context
* @param resourceTypeConfigs the resource type configurations
* @param functionReferences the function references
* @param modelResource the model resource
* @param locale the locale used for retrieving descriptions/titles
*
* @return the resource type info beans for types for which new detail pages can be created
*/
private List<CmsNewResourceInfo> getResourceTypeInfos(
CmsObject cms,
List<CmsResourceTypeConfig> resourceTypeConfigs,
List<CmsFunctionReference> functionReferences,
CmsResource modelResource,
Locale locale) {
List<CmsNewResourceInfo> result = new ArrayList<CmsNewResourceInfo>();
for (CmsResourceTypeConfig typeConfig : resourceTypeConfigs) {
if (typeConfig.isDetailPagesDisabled()) {
continue;
}
String typeName = typeConfig.getTypeName();
try {
I_CmsResourceType resourceType = OpenCms.getResourceManager().getResourceType(typeName);
result.add(createResourceTypeInfo(resourceType, modelResource));
} catch (CmsLoaderException e) {
LOG.error(e.getLocalizedMessage(), e);
}
}
for (CmsFunctionReference functionRef : functionReferences) {
try {
CmsResource functionRes = cms.readResource(functionRef.getStructureId());
String description = cms.readPropertyObject(
functionRes,
CmsPropertyDefinition.PROPERTY_DESCRIPTION,
false).getValue();
String subtitle = description;
try {
CmsGallerySearchResult searchResult = CmsGallerySearch.searchById(
cms,
functionRef.getStructureId(),
getWorkplaceLocale());
subtitle = searchResult.getDescription();
} catch (CmsException e) {
LOG.warn(e.getLocalizedMessage(), e);
}
CmsNewResourceInfo info = new CmsNewResourceInfo(
modelResource.getTypeId(),
CmsDetailPageInfo.FUNCTION_PREFIX + functionRef.getName(),
functionRef.getName(),
description,
modelResource.getStructureId(),
false,
subtitle);
info.setCreateParameter(functionRef.getStructureId().toString());
info.setIsFunction(true);
result.add(info);
} catch (CmsVfsResourceNotFoundException e) {
LOG.warn(e.getLocalizedMessage(), e);
} catch (CmsException e) {
LOG.error(e.getLocalizedMessage(), e);
}
}
return result;
}
/**
* Reeds the site root entry.<p>
*
* @param rootPath the root path of the sitemap root
* @param targetPath the target path to open
*
* @return the site root entry
*
* @throws CmsSecurityException in case of insufficient permissions
* @throws CmsException if something goes wrong
*/
private CmsClientSitemapEntry getRootEntry(String rootPath, String targetPath)
throws CmsSecurityException, CmsException {
String sitePath = "/";
if (rootPath != null) {
sitePath = getCmsObject().getRequestContext().removeSiteRoot(rootPath);
}
CmsJspNavElement navElement = getNavBuilder().getNavigationForResource(sitePath, CmsResourceFilter.ONLY_VISIBLE);
CmsClientSitemapEntry result = toClientEntry(navElement, true);
if (result != null) {
result.setPosition(0);
result.setChildrenLoadedInitially(true);
result.setSubEntries(getChildren(sitePath, 2, targetPath), null);
}
return result;
}
/**
* Returns the sitemap info for the given base path.<p>
*
* @param basePath the base path
*
* @return the sitemap info
*
* @throws CmsException if something goes wrong reading the resources
*/
private CmsSitemapInfo getSitemapInfo(String basePath) throws CmsException {
CmsObject cms = getCmsObject();
CmsResource baseFolder = null;
if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(basePath)) {
baseFolder = cms.readResource(
cms.getRequestContext().removeSiteRoot(basePath),
CmsResourceFilter.ONLY_VISIBLE);
} else {
// in case of an empty base path, use base folder of the current site
basePath = "/";
baseFolder = cms.readResource("/");
}
CmsResource defaultFile = cms.readDefaultFile(baseFolder, CmsResourceFilter.ONLY_VISIBLE);
String title = cms.readPropertyObject(baseFolder, CmsPropertyDefinition.PROPERTY_TITLE, false).getValue();
if (CmsStringUtil.isEmptyOrWhitespaceOnly(title) && (defaultFile != null)) {
title = cms.readPropertyObject(defaultFile, CmsPropertyDefinition.PROPERTY_TITLE, false).getValue();
}
String description = cms.readPropertyObject(baseFolder, CmsPropertyDefinition.PROPERTY_DESCRIPTION, false).getValue();
if (CmsStringUtil.isEmptyOrWhitespaceOnly(description) && (defaultFile != null)) {
description = cms.readPropertyObject(defaultFile, CmsPropertyDefinition.PROPERTY_DESCRIPTION, false).getValue();
}
return new CmsSitemapInfo(
cms.getRequestContext().getCurrentProject().getName(),
description,
OpenCms.getLocaleManager().getDefaultLocale(cms, baseFolder).toString(),
OpenCms.getSiteManager().getCurrentSite(cms).getUrl()
+ OpenCms.getLinkManager().substituteLinkForUnknownTarget(cms, basePath),
title);
}
/**
* Returns the workplace locale for the current user.<p>
*
* @return the workplace locale
*/
private Locale getWorkplaceLocale() {
Locale result = OpenCms.getWorkplaceManager().getWorkplaceLocale(getCmsObject());
if (result == null) {
result = CmsLocaleManager.getDefaultLocale();
}
if (result == null) {
result = Locale.getDefault();
}
return result;
}
/**
* Checks whether the sitemap change has default file changes.<p>
*
* @param change a sitemap change
* @return true if the change would change the default file
*/
private boolean hasDefaultFileChanges(CmsSitemapChange change) {
return (change.getDefaultFileId() != null) && !change.isNew();
//TODO: optimize this!
}
/**
* Checks whether the sitemap change has changes for the sitemap entry resource.<p>
*
* @param change the sitemap change
* @return true if the change would change the original sitemap entry resource
*/
private boolean hasOwnChanges(CmsSitemapChange change) {
return !change.isNew();
//TODO: optimize this!
}
/**
* Checks whether a resource is a default file of a folder.<p>
*
* @param resource the resource to check
*
* @return true if the resource is the default file of a folder
*
* @throws CmsException if something goes wrong
*/
private boolean isDefaultFile(CmsResource resource) throws CmsException {
CmsObject cms = getCmsObject();
if (resource.isFolder()) {
return false;
}
CmsResource parent = cms.readResource(
CmsResource.getParentFolder(cms.getSitePath(resource)),
CmsResourceFilter.ONLY_VISIBLE);
CmsResource defaultFile = cms.readDefaultFile(parent, CmsResourceFilter.ONLY_VISIBLE);
return resource.equals(defaultFile);
}
/**
* Checks if the toolbar should be displayed.<p>
*
* @param request the current request to get the default locale from
*
* @return <code>true</code> if the toolbar should be displayed
*/
private boolean isDisplayToolbar(HttpServletRequest request) {
// display the toolbar by default
boolean displayToolbar = true;
if (CmsHistoryResourceHandler.isHistoryRequest(request)) {
// we do not want to display the toolbar in case of an historical request
displayToolbar = false;
}
return displayToolbar;
}
/**
* Returns if the given type id matches the xml-redirect resource type.<p>
*
* @param typeId the resource type id
*
* @return <code>true</code> if the given type id matches the xml-redirect resource type
*/
private boolean isRedirectType(int typeId) {
try {
return typeId == OpenCms.getResourceManager().getResourceType(RECOURCE_TYPE_NAME_REDIRECT).getTypeId();
} catch (Exception e) {
return false;
}
}
/**
* Returns if the given nav-element resembles a sub-sitemap entry-point.<p>
*
* @param navElement the nav-element
*
* @return <code>true</code> if the given nav-element resembles a sub-sitemap entry-point.<p>
* @throws CmsException if something goes wrong
*/
private boolean isSubSitemap(CmsJspNavElement navElement) throws CmsException {
return navElement.getResource().getTypeId() == getEntryPointType();
}
/**
* Checks if the given open path is valid.<p>
*
* @param cms the cms context
* @param openPath the open path
*
* @return <code>true</code> if the given open path is valid
*/
private boolean isValidOpenPath(CmsObject cms, String openPath) {
if (CmsStringUtil.isEmptyOrWhitespaceOnly(openPath)) {
return false;
}
if (!cms.existsResource(openPath)) {
// in case of a detail-page check the parent folder
String parent = CmsResource.getParentFolder(openPath);
if (CmsStringUtil.isEmptyOrWhitespaceOnly(parent) || !cms.existsResource(parent)) {
return false;
}
}
return true;
}
/**
* Returns if the given return code is valid.<p>
*
* @param returnCode the return code to check
*
* @return <code>true</code> if the return code is valid
*/
private boolean isValidReturnCode(String returnCode) {
if (CmsStringUtil.isEmptyOrWhitespaceOnly(returnCode)) {
return false;
}
int pos = returnCode.indexOf(":");
if (pos > 0) {
return CmsUUID.isValidUUID(returnCode.substring(0, pos))
&& CmsUUID.isValidUUID(returnCode.substring(pos + 1));
} else {
return CmsUUID.isValidUUID(returnCode);
}
}
/**
* Applys the given changes to the entry.<p>
*
* @param change the change to apply
*
* @throws CmsException if something goes wrong
*/
private void modifyEntry(CmsSitemapChange change) throws CmsException {
CmsObject cms = getCmsObject();
CmsResource entryPage = null;
CmsResource entryFolder = null;
CmsResource ownRes = null;
CmsResource defaultFileRes = null;
try {
// lock all resources necessary first to avoid doing changes only half way through
if (hasOwnChanges(change)) {
ownRes = cms.readResource(change.getEntryId(), CmsResourceFilter.ONLY_VISIBLE);
ensureLock(ownRes);
}
if (hasDefaultFileChanges(change)) {
defaultFileRes = cms.readResource(change.getDefaultFileId(), CmsResourceFilter.ONLY_VISIBLE);
ensureLock(defaultFileRes);
}
if ((ownRes != null) && ownRes.isFolder()) {
entryFolder = ownRes;
}
if ((ownRes != null) && ownRes.isFile()) {
entryPage = ownRes;
}
if (defaultFileRes != null) {
entryPage = defaultFileRes;
}
if (change.isLeafType()) {
entryFolder = entryPage;
}
updateProperties(cms, ownRes, defaultFileRes, change.getPropertyChanges());
if (change.hasChangedPosition()) {
updateNavPos(ownRes, change);
}
if (entryFolder != null) {
if (change.hasNewParent() || change.hasChangedName()) {
String destinationPath;
if (change.hasNewParent()) {
CmsResource futureParent = cms.readResource(
change.getParentId(),
CmsResourceFilter.ONLY_VISIBLE);
destinationPath = CmsStringUtil.joinPaths(cms.getSitePath(futureParent), change.getName());
} else {
destinationPath = CmsStringUtil.joinPaths(
CmsResource.getParentFolder(cms.getSitePath(entryFolder)),
change.getName());
}
if (change.isLeafType() && destinationPath.endsWith("/")) {
destinationPath = destinationPath.substring(0, destinationPath.length() - 1);
}
// only if the site-path has really changed
if (!cms.getSitePath(entryFolder).equals(destinationPath)) {
cms.moveResource(cms.getSitePath(entryFolder), destinationPath);
}
entryFolder = cms.readResource(entryFolder.getStructureId(), CmsResourceFilter.ONLY_VISIBLE);
}
}
} finally {
if (entryPage != null) {
tryUnlock(entryPage);
}
if (entryFolder != null) {
tryUnlock(entryFolder);
}
}
}
/**
* Helper method for removing all locales except one from a container page.<p>
*
* @param page the container page to proces
* @param localeToKeep the locale which should be kept
*
* @throws CmsXmlException if something goes wrong
*/
private void removeAllLocalesExcept(CmsXmlContainerPage page, Locale localeToKeep) throws CmsXmlException {
List<Locale> locales = page.getLocales();
for (Locale locale : locales) {
if (!locale.equals(localeToKeep)) {
page.removeLocale(locale);
}
}
}
/**
* Applys the given remove change.<p>
*
* @param change the change to apply
*
* @return the changed client sitemap entry or <code>null</code>
*
* @throws CmsException if something goes wrong
*/
private CmsSitemapChange removeEntryFromNavigation(CmsSitemapChange change) throws CmsException {
CmsObject cms = getCmsObject();
CmsResource entryFolder = cms.readResource(change.getEntryId(), CmsResourceFilter.ONLY_VISIBLE);
ensureLock(entryFolder);
List<CmsProperty> properties = new ArrayList<CmsProperty>();
properties.add(new CmsProperty(
CmsPropertyDefinition.PROPERTY_NAVTEXT,
CmsProperty.DELETE_VALUE,
CmsProperty.DELETE_VALUE));
properties.add(new CmsProperty(
CmsPropertyDefinition.PROPERTY_NAVPOS,
CmsProperty.DELETE_VALUE,
CmsProperty.DELETE_VALUE));
cms.writePropertyObjects(cms.getSitePath(entryFolder), properties);
tryUnlock(entryFolder);
return change;
}
/**
* Saves the detail page information of a sitemap to the sitemap's configuration file.<p>
*
* @param detailPages saves the detailpage configuration
* @param resource the configuration file resource
* @param newId the structure id to use for new detail page entries
*
* @throws CmsException
*/
private void saveDetailPages(List<CmsDetailPageInfo> detailPages, CmsResource resource, CmsUUID newId)
throws CmsException {
CmsObject cms = getCmsObject();
CmsDetailPageConfigurationWriter writer = new CmsDetailPageConfigurationWriter(cms, resource);
writer.updateAndSave(detailPages, newId);
}
/**
* Saves the given clipboard data to the session.<p>
*
* @param clipboardData the clipboard data to save
*
* @throws CmsException if something goes wrong writing the user
*/
private void setClipboardData(CmsSitemapClipboardData clipboardData) throws CmsException {
CmsObject cms = getCmsObject();
CmsUser user = cms.getRequestContext().getCurrentUser();
if (clipboardData != null) {
JSONArray modified = new JSONArray();
if (clipboardData.getModifications() != null) {
for (CmsUUID id : clipboardData.getModifications().keySet()) {
if (id != null) {
modified.put(id.toString());
}
}
}
user.setAdditionalInfo(ADDINFO_ADE_MODIFIED_LIST, modified.toString());
JSONArray deleted = new JSONArray();
if (clipboardData.getDeletions() != null) {
for (CmsUUID id : clipboardData.getDeletions().keySet()) {
if (id != null) {
deleted.put(id.toString());
}
}
}
user.setAdditionalInfo(ADDINFO_ADE_DELETED_LIST, deleted.toString());
cms.writeUser(user);
}
}
/**
* Determines if the title property of the default file should be changed.<p>
*
* @param properties the current default file properties
* @param folderNavtext the 'NavText' property of the folder
*
* @return <code>true</code> if the title property should be changed
*/
private boolean shouldChangeDefaultFileTitle(Map<String, CmsProperty> properties, CmsProperty folderNavtext) {
return (properties == null)
|| (properties.get(CmsPropertyDefinition.PROPERTY_TITLE) == null)
|| (properties.get(CmsPropertyDefinition.PROPERTY_TITLE).getValue() == null)
|| ((folderNavtext != null) && properties.get(CmsPropertyDefinition.PROPERTY_TITLE).getValue().equals(
folderNavtext.getValue()));
}
/**
* Determines if the title property should be changed in case of a 'NavText' change.<p>
*
* @param properties the current resource properties
*
* @return <code>true</code> if the title property should be changed in case of a 'NavText' change
*/
private boolean shouldChangeTitle(Map<String, CmsProperty> properties) {
return (properties == null)
|| (properties.get(CmsPropertyDefinition.PROPERTY_TITLE) == null)
|| (properties.get(CmsPropertyDefinition.PROPERTY_TITLE).getValue() == null)
|| ((properties.get(CmsPropertyDefinition.PROPERTY_NAVTEXT) != null) && properties.get(
CmsPropertyDefinition.PROPERTY_TITLE).getValue().equals(
properties.get(CmsPropertyDefinition.PROPERTY_NAVTEXT).getValue()));
}
/**
* Converts a jsp navigation element into a client sitemap entry.<p>
*
* @param navElement the jsp navigation element
* @param isRoot true if the entry is a root entry
*
* @return the client sitemap entry
* @throws CmsException
*/
private CmsClientSitemapEntry toClientEntry(CmsJspNavElement navElement, boolean isRoot) throws CmsException {
CmsResource entryPage = null;
CmsObject cms = getCmsObject();
CmsClientSitemapEntry clientEntry = new CmsClientSitemapEntry();
CmsResource entryFolder = null;
CmsResource ownResource = navElement.getResource();
clientEntry.setResourceState(ownResource.getState());
CmsResource defaultFileResource = null;
if (ownResource.isFolder()) {
defaultFileResource = cms.readDefaultFile(ownResource, CmsResourceFilter.ONLY_VISIBLE);
}
Map<String, CmsClientProperty> ownProps = getClientProperties(cms, ownResource, false);
Map<String, CmsClientProperty> defaultFileProps = null;
if (defaultFileResource != null) {
defaultFileProps = getClientProperties(cms, defaultFileResource, false);
clientEntry.setDefaultFileId(defaultFileResource.getStructureId());
clientEntry.setDefaultFileType(OpenCms.getResourceManager().getResourceType(defaultFileResource.getTypeId()).getTypeName());
} else {
defaultFileProps = new HashMap<String, CmsClientProperty>();
}
boolean isDefault = isDefaultFile(ownResource);
clientEntry.setId(ownResource.getStructureId());
clientEntry.setFolderDefaultPage(isDefault);
if (navElement.getResource().isFolder()) {
entryFolder = navElement.getResource();
entryPage = defaultFileResource;
clientEntry.setName(entryFolder.getName());
if (entryPage == null) {
entryPage = entryFolder;
}
if (!isRoot && isSubSitemap(navElement)) {
clientEntry.setEntryType(EntryType.subSitemap);
clientEntry.setDefaultFileType(null);
}
CmsLock folderLock = cms.getLock(entryFolder);
clientEntry.setHasForeignFolderLock(!folderLock.isUnlocked()
&& !folderLock.isOwnedBy(cms.getRequestContext().getCurrentUser()));
if (!cms.getRequestContext().getCurrentProject().isOnlineProject()) {
List<CmsResource> blockingChildren = cms.getBlockingLockedResources(entryFolder);
clientEntry.setBlockingLockedChildren((blockingChildren != null) && !blockingChildren.isEmpty());
}
} else {
entryPage = navElement.getResource();
clientEntry.setName(entryPage.getName());
if (isRedirectType(entryPage.getTypeId())) {
clientEntry.setEntryType(EntryType.redirect);
CmsFile file = cms.readFile(entryPage);
I_CmsXmlDocument content = CmsXmlContentFactory.unmarshal(cms, file);
Locale contentLocale = OpenCms.getLocaleManager().getDefaultLocale(cms, entryPage);
// ensure the content contains the default locale
contentLocale = content.getBestMatchingLocale(contentLocale);
if (contentLocale == null) {
// no best matching locale, use the first available
List<Locale> locales = content.getLocales();
if (!locales.isEmpty()) {
contentLocale = locales.get(0);
}
}
String link = "";
if (contentLocale != null) {
link = content.getValue(REDIRECT_LINK_TARGET_XPATH, contentLocale).getStringValue(getCmsObject());
}
clientEntry.setRedirectTarget(link);
} else {
clientEntry.setEntryType(EntryType.leaf);
}
}
long dateExpired = navElement.getResource().getDateExpired();
if (dateExpired != CmsResource.DATE_EXPIRED_DEFAULT) {
clientEntry.setDateExpired(CmsDateUtil.getDate(
new Date(dateExpired),
DateFormat.SHORT,
getWorkplaceLocale()));
}
long dateReleased = navElement.getResource().getDateReleased();
if (dateReleased != CmsResource.DATE_RELEASED_DEFAULT) {
clientEntry.setDateReleased(CmsDateUtil.getDate(
new Date(dateReleased),
DateFormat.SHORT,
getWorkplaceLocale()));
}
clientEntry.setResleasedAndNotExpired(navElement.getResource().isReleasedAndNotExpired(
System.currentTimeMillis()));
String path = cms.getSitePath(entryPage);
clientEntry.setVfsPath(path);
clientEntry.setOwnProperties(ownProps);
clientEntry.setDefaultFileProperties(defaultFileProps);
clientEntry.setSitePath(entryFolder != null ? cms.getSitePath(entryFolder) : path);
//CHECK: assuming that, if entryPage refers to the default file, the lock state of the folder
clientEntry.setLock(generateClientLock(entryPage));
clientEntry.setInNavigation(isRoot || navElement.isInNavigation());
String type = OpenCms.getResourceManager().getResourceType(ownResource).getTypeName();
clientEntry.setResourceTypeName(type);
return clientEntry;
}
/**
* Un-deletes a resource according to the change data.<p>
*
* @param change the change data
*
* @return the changed entry or <code>null</code>
*
* @throws CmsException if something goes wrong
*/
private CmsSitemapChange undelete(CmsSitemapChange change) throws CmsException {
CmsObject cms = getCmsObject();
CmsResource deleted = cms.readResource(change.getEntryId(), CmsResourceFilter.ALL);
if (deleted.getState().isDeleted()) {
ensureLock(deleted);
cms.undeleteResource(getCmsObject().getSitePath(deleted), true);
tryUnlock(deleted);
}
String parentPath = CmsResource.getParentFolder(cms.getSitePath(deleted));
CmsJspNavElement navElement = getNavBuilder().getNavigationForResource(
parentPath,
CmsResourceFilter.ONLY_VISIBLE);
CmsClientSitemapEntry entry = toClientEntry(navElement, navElement.isInNavigation());
entry.setSubEntries(getChildren(parentPath, 2, null), null);
change.setUpdatedEntry(entry);
return change;
}
/**
* Updates the navigation position for a resource.<p>
*
* @param res the resource for which to update the navigation position
* @param change the sitemap change
*
* @throws CmsException if something goes wrong
*/
private void updateNavPos(CmsResource res, CmsSitemapChange change) throws CmsException {
if (change.hasChangedPosition()) {
applyNavigationChanges(change, res);
}
}
/**
* Updates properties for a resource and possibly its detail page.<p>
*
* @param cms the CMS context
* @param ownRes the resource
* @param defaultFileRes the default file resource (possibly null)
* @param propertyModifications the property modifications
*
* @throws CmsException if something goes wrong
*/
private void updateProperties(
CmsObject cms,
CmsResource ownRes,
CmsResource defaultFileRes,
List<CmsPropertyModification> propertyModifications) throws CmsException {
Map<String, CmsProperty> ownProps = getPropertiesByName(cms.readPropertyObjects(ownRes, false));
// determine if the title property should be changed in case of a 'NavText' change
boolean changeOwnTitle = shouldChangeTitle(ownProps);
boolean changeDefaultFileTitle = false;
Map<String, CmsProperty> defaultFileProps = Collections.emptyMap();
if (defaultFileRes != null) {
defaultFileProps = getPropertiesByName(cms.readPropertyObjects(defaultFileRes, false));
// determine if the title property of the default file should be changed
changeDefaultFileTitle = shouldChangeDefaultFileTitle(
defaultFileProps,
ownProps.get(CmsPropertyDefinition.PROPERTY_NAVTEXT));
}
String hasNavTextChange = null;
List<CmsProperty> ownPropertyChanges = new ArrayList<CmsProperty>();
List<CmsProperty> defaultFilePropertyChanges = new ArrayList<CmsProperty>();
for (CmsPropertyModification propMod : propertyModifications) {
CmsProperty propToModify = null;
if (ownRes.getStructureId().equals(propMod.getId())) {
if (CmsPropertyDefinition.PROPERTY_NAVTEXT.equals(propMod.getName())) {
hasNavTextChange = propMod.getValue();
} else if (CmsPropertyDefinition.PROPERTY_TITLE.equals(propMod.getName())) {
changeOwnTitle = false;
}
propToModify = ownProps.get(propMod.getName());
if (propToModify == null) {
propToModify = new CmsProperty(propMod.getName(), null, null);
}
ownPropertyChanges.add(propToModify);
} else {
if (CmsPropertyDefinition.PROPERTY_TITLE.equals(propMod.getName())) {
changeDefaultFileTitle = false;
}
propToModify = defaultFileProps.get(propMod.getName());
if (propToModify == null) {
propToModify = new CmsProperty(propMod.getName(), null, null);
}
defaultFilePropertyChanges.add(propToModify);
}
String newValue = propMod.getValue();
if (newValue == null) {
newValue = "";
}
if (propMod.isStructureValue()) {
propToModify.setStructureValue(newValue);
} else {
propToModify.setResourceValue(newValue);
}
}
if (hasNavTextChange != null) {
if (changeOwnTitle) {
CmsProperty titleProp = ownProps.get(CmsPropertyDefinition.PROPERTY_TITLE);
if (titleProp == null) {
titleProp = new CmsProperty(CmsPropertyDefinition.PROPERTY_TITLE, null, null);
}
titleProp.setStructureValue(hasNavTextChange);
ownPropertyChanges.add(titleProp);
}
if (changeDefaultFileTitle) {
CmsProperty titleProp = defaultFileProps.get(CmsPropertyDefinition.PROPERTY_TITLE);
if (titleProp == null) {
titleProp = new CmsProperty(CmsPropertyDefinition.PROPERTY_TITLE, null, null);
}
titleProp.setStructureValue(hasNavTextChange);
defaultFilePropertyChanges.add(titleProp);
}
}
if (!ownPropertyChanges.isEmpty()) {
cms.writePropertyObjects(ownRes, ownPropertyChanges);
}
if (!defaultFilePropertyChanges.isEmpty() && (defaultFileRes != null)) {
cms.writePropertyObjects(defaultFileRes, defaultFilePropertyChanges);
}
}
}