org.opencms.gwt.CmsPropertyEditorHelper Maven / Gradle / Ivy
Show all versions of opencms-test Show documentation
/*
* This library is part of OpenCms -
* the Open Source Content Management System
*
* Copyright (c) Alkacon Software GmbH & Co. KG (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.gwt;
import org.opencms.file.CmsObject;
import org.opencms.file.CmsProperty;
import org.opencms.file.CmsPropertyDefinition;
import org.opencms.file.CmsResource;
import org.opencms.file.CmsResourceFilter;
import org.opencms.file.types.CmsResourceTypeXmlContainerPage;
import org.opencms.gwt.shared.property.CmsClientProperty;
import org.opencms.gwt.shared.property.CmsPropertiesBean;
import org.opencms.gwt.shared.property.CmsPropertyChangeSet;
import org.opencms.gwt.shared.property.CmsPropertyModification;
import org.opencms.lock.CmsLock;
import org.opencms.lock.CmsLockActionRecord;
import org.opencms.lock.CmsLockActionRecord.LockChange;
import org.opencms.lock.CmsLockUtil;
import org.opencms.main.CmsException;
import org.opencms.main.OpenCms;
import org.opencms.security.CmsPermissionSet;
import org.opencms.util.CmsFileUtil;
import org.opencms.util.CmsMacroResolver;
import org.opencms.util.CmsStringUtil;
import org.opencms.util.CmsUUID;
import org.opencms.workplace.explorer.CmsExplorerTypeSettings;
import org.opencms.workplace.explorer.CmsResourceUtil;
import org.opencms.xml.content.CmsXmlContentProperty;
import org.opencms.xml.content.CmsXmlContentPropertyHelper;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import com.google.common.collect.Maps;
/**
* Helper class responsible for loading / saving properties when using the property dialog.
*/
public class CmsPropertyEditorHelper {
/** The CMS context. */
private CmsObject m_cms;
/** Structure id which should be used instead of the structure id in a property change set (can be null). */
private CmsUUID m_overrideStructureId;
/**
* Creates a new instance.
*
* @param cms the CMS context
*/
public CmsPropertyEditorHelper(CmsObject cms) {
m_cms = cms;
}
/**
* Internal method for computing the default property configurations for a list of structure ids.
*
* @param structureIds the structure ids for which we want the default property configurations
* @return a map from the given structure ids to their default property configurations
*
* @throws CmsException if something goes wrong
*/
public Map> getDefaultProperties(
List structureIds) throws CmsException {
CmsObject cms = m_cms;
Map> result = Maps.newHashMap();
for (CmsUUID structureId : structureIds) {
CmsResource resource = cms.readResource(structureId, CmsResourceFilter.ALL);
String typeName = OpenCms.getResourceManager().getResourceType(resource).getTypeName();
Map propertyConfig = getDefaultPropertiesForType(typeName);
result.put(structureId, propertyConfig);
}
return result;
}
/**
* Loads the data needed for editing the properties of a resource.
*
* @param id the structure id of the resource
* @return the data needed for editing the properties
*
* @throws CmsException if something goes wrong
*/
public CmsPropertiesBean loadPropertyData(CmsUUID id) throws CmsException {
CmsObject cms = m_cms;
String originalSiteRoot = cms.getRequestContext().getSiteRoot();
CmsPropertiesBean result = new CmsPropertiesBean();
CmsResource resource = cms.readResource(id, CmsResourceFilter.IGNORE_EXPIRATION);
result.setReadOnly(!isWritable(cms, resource));
result.setFolder(resource.isFolder());
result.setContainerPage(CmsResourceTypeXmlContainerPage.isContainerPage(resource));
String sitePath = cms.getSitePath(resource);
Map propertyConfig = OpenCms.getADEManager().lookupConfiguration(
cms,
resource.getRootPath()).getPropertyConfigurationAsMap();
Map defaultProperties = getDefaultProperties(
Collections.singletonList(resource.getStructureId())).get(resource.getStructureId());
Map mergedConfig = new LinkedHashMap();
mergedConfig.putAll(defaultProperties);
mergedConfig.putAll(propertyConfig);
propertyConfig = mergedConfig;
// Resolve macros in the property configuration
propertyConfig = CmsXmlContentPropertyHelper.resolveMacrosInProperties(
propertyConfig,
CmsMacroResolver.newWorkplaceLocaleResolver(cms));
result.setPropertyDefinitions(new LinkedHashMap(propertyConfig));
try {
cms.getRequestContext().setSiteRoot("");
String parentPath = CmsResource.getParentFolder(resource.getRootPath());
CmsResource parent = cms.readResource(parentPath, CmsResourceFilter.IGNORE_EXPIRATION);
List parentProperties = cms.readPropertyObjects(parent, true);
List ownProperties = cms.readPropertyObjects(resource, false);
result.setOwnProperties(convertProperties(ownProperties));
result.setInheritedProperties(convertProperties(parentProperties));
result.setPageInfo(CmsVfsService.getPageInfo(cms, resource));
List propDefs = cms.readAllPropertyDefinitions();
List propNames = new ArrayList();
for (CmsPropertyDefinition propDef : propDefs) {
propNames.add(propDef.getName());
}
CmsTemplateFinder templateFinder = new CmsTemplateFinder(cms);
result.setTemplates(templateFinder.getTemplates());
result.setAllProperties(propNames);
result.setStructureId(id);
result.setSitePath(sitePath);
return result;
} finally {
cms.getRequestContext().setSiteRoot(originalSiteRoot);
}
}
/**
* Sets a structure id that overrides the one stored in a property change set.
*
* @param structureId the new structure id
*/
public void overrideStructureId(CmsUUID structureId) {
m_overrideStructureId = structureId;
}
/**
* Saves a set of property changes.
*
* @param changes the set of property changes
* @throws CmsException if something goes wrong
*/
public void saveProperties(CmsPropertyChangeSet changes) throws CmsException {
CmsObject cms = m_cms;
CmsUUID structureId = changes.getTargetStructureId();
if (m_overrideStructureId != null) {
structureId = m_overrideStructureId;
}
CmsResource resource = cms.readResource(structureId, CmsResourceFilter.IGNORE_EXPIRATION);
CmsLockActionRecord actionRecord = CmsLockUtil.ensureLock(cms, resource);
try {
Map ownProps = getPropertiesByName(cms.readPropertyObjects(resource, false));
// determine if the title property should be changed in case of a 'NavText' change
boolean changeOwnTitle = shouldChangeTitle(ownProps);
String hasNavTextChange = null;
List ownPropertyChanges = new ArrayList();
for (CmsPropertyModification propMod : changes.getChanges()) {
if (propMod.isFileNameProperty()) {
// in case of the file name property, the resource needs to be renamed
if ((m_overrideStructureId == null) && !resource.getStructureId().equals(propMod.getId())) {
if (propMod.getId() != null) {
throw new IllegalStateException("Invalid structure id in property changes.");
}
}
CmsResource.checkResourceName(propMod.getValue());
String oldSitePath = CmsFileUtil.removeTrailingSeparator(cms.getSitePath(resource));
String parentPath = CmsResource.getParentFolder(oldSitePath);
String newSitePath = CmsFileUtil.removeTrailingSeparator(
CmsStringUtil.joinPaths(parentPath, propMod.getValue()));
if (!oldSitePath.equals(newSitePath)) {
cms.moveResource(oldSitePath, newSitePath);
}
// read the resource again to update name and path
resource = cms.readResource(resource.getStructureId(), CmsResourceFilter.IGNORE_EXPIRATION);
} else {
CmsProperty propToModify = null;
if ((m_overrideStructureId != null) || resource.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 {
throw new IllegalStateException("Invalid structure id in property changes!");
}
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 (!ownPropertyChanges.isEmpty()) {
cms.writePropertyObjects(resource, ownPropertyChanges);
}
} finally {
if (actionRecord.getChange() == LockChange.locked) {
cms.unlockResource(resource);
}
}
}
/**
* Converts CmsProperty objects to CmsClientProperty objects.
*
* @param properties a list of server-side properties
*
* @return a map of client-side properties
*/
protected Map convertProperties(List properties) {
Map result = new HashMap();
for (CmsProperty prop : properties) {
CmsClientProperty clientProp = new CmsClientProperty(
prop.getName(),
prop.getStructureValue(),
prop.getResourceValue());
clientProp.setOrigin(prop.getOrigin());
result.put(clientProp.getName(), clientProp);
}
return result;
}
/**
* Helper method to get the default property configuration for the given resource type.
*
* @param typeName the name of the resource type
*
* @return the default property configuration for the given type
*/
protected Map getDefaultPropertiesForType(String typeName) {
Map propertyConfig = new LinkedHashMap();
CmsExplorerTypeSettings explorerType = OpenCms.getWorkplaceManager().getExplorerTypeSetting(typeName);
if (explorerType != null) {
List defaultProps = explorerType.getProperties();
for (String propName : defaultProps) {
CmsXmlContentProperty property = new CmsXmlContentProperty(
propName,
"string",
"string",
"",
"",
"",
"",
null,
"",
"",
"false");
propertyConfig.put(propName, property);
}
}
return propertyConfig;
}
/**
* Converts a list of properties to a map.
*
* @param properties the list of properties
*
* @return a map from property names to properties
*/
protected Map getPropertiesByName(List properties) {
Map result = new HashMap();
for (CmsProperty property : properties) {
String key = property.getName();
result.put(key, property.clone());
}
return result;
}
/**
* Returns whether the current user has write permissions, the resource is lockable or already locked by the current user and is in the current project.
*
* @param cms the cms context
* @param resource the resource
*
* @return true
if the resource is writable
*
* @throws CmsException in case checking the permissions fails
*/
protected boolean isWritable(CmsObject cms, CmsResource resource) throws CmsException {
boolean writable = cms.hasPermissions(
resource,
CmsPermissionSet.ACCESS_WRITE,
false,
CmsResourceFilter.IGNORE_EXPIRATION);
if (writable) {
CmsLock lock = cms.getLock(resource);
writable = lock.isUnlocked() || lock.isOwnedBy(cms.getRequestContext().getCurrentUser());
if (writable) {
CmsResourceUtil resUtil = new CmsResourceUtil(cms, resource);
writable = resUtil.isInsideProject() && !resUtil.getProjectState().isLockedForPublishing();
}
}
return writable;
}
/**
* Determines if the title property should be changed in case of a 'NavText' change.
*
* @param properties the current resource properties
*
* @return true
if the title property should be changed in case of a 'NavText' change
*/
private boolean shouldChangeTitle(Map 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()));
}
}