/*
* 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 GmbH, 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.file.types;
import org.opencms.configuration.CmsConfigurationCopyResource;
import org.opencms.configuration.CmsConfigurationException;
import org.opencms.configuration.CmsParameterConfiguration;
import org.opencms.db.CmsSecurityManager;
import org.opencms.file.CmsFile;
import org.opencms.file.CmsObject;
import org.opencms.file.CmsProperty;
import org.opencms.file.CmsResource;
import org.opencms.file.CmsResourceFilter;
import org.opencms.file.CmsVfsException;
import org.opencms.file.CmsVfsResourceNotFoundException;
import org.opencms.loader.CmsLoaderException;
import org.opencms.loader.CmsResourceManager;
import org.opencms.lock.CmsLockType;
import org.opencms.main.CmsException;
import org.opencms.main.CmsIllegalArgumentException;
import org.opencms.main.CmsLog;
import org.opencms.main.CmsRuntimeException;
import org.opencms.main.OpenCms;
import org.opencms.relations.CmsLink;
import org.opencms.relations.I_CmsLinkParseable;
import org.opencms.staticexport.CmsLinkManager;
import org.opencms.util.CmsFileUtil;
import org.opencms.util.CmsMacroResolver;
import org.opencms.util.CmsStringUtil;
import org.opencms.xml.containerpage.CmsFormatterConfiguration;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log;
/**
* Base implementation for resource type classes.<p>
*
* @since 6.0.0
*/
public abstract class A_CmsResourceType implements I_CmsResourceType {
/** Configuration key for optional javascript in galleries. */
public static final String CONFIGURATION_GALLERY_JAVASCRIPT_PATH = "gallery.javascript.path";
/** Configuration key for optional preview provider in galleries. */
public static final String CONFIGURATION_GALLERY_PREVIEW_PROVIDER = "gallery.preview.provider";
/** Configuration key for the optional folder class name. */
public static final String CONFIGURATION_GALLERY_TYPE_NAMES = "gallery.type.names";
/** Configuration key for the (optional) internal flag. */
public static final String CONFIGURATION_INTERNAL = "resource.flag.internal";
/** The default gallery preview provider. */
public static final String DEFAULT_GALLERY_PREVIEW_PROVIDER = "org.opencms.ade.galleries.preview.CmsBinaryPreviewProvider";
/** Macro for the folder path of the current resource. */
public static final String MACRO_RESOURCE_FOLDER_PATH = "resource.folder.path";
/** Macro for the folder path of the current resource, with touch enabled for the copied resources. */
public static final String MACRO_RESOURCE_FOLDER_PATH_TOUCH = "resource.folder.path.touch";
/** Macro for the name of the current resource. */
public static final String MACRO_RESOURCE_NAME = "resource.name";
/** Macro for the parent folder path of the current resource. */
public static final String MACRO_RESOURCE_PARENT_PATH = "resource.parent.path";
/** Macro for the root path of the current resource. */
public static final String MACRO_RESOURCE_ROOT_PATH = "resource.root.path";
/** Macro for the site path of the current resource. */
public static final String MACRO_RESOURCE_SITE_PATH = "resource.site.path";
/** The log object for this class. */
private static final Log LOG = CmsLog.getLog(A_CmsResourceType.class);
/** Flag for showing that this is an additional resource type which is defined in a module. */
protected boolean m_addititionalModuleResourceType;
/** The configured class name of this resource type. */
protected String m_className;
/** Configuration parameters. */
protected CmsParameterConfiguration m_configuration;
/** The list of resources to copy. */
protected List<CmsConfigurationCopyResource> m_copyResources;
/** The list of configured default properties. */
protected List<CmsProperty> m_defaultProperties;
/** Indicates that the configuration of the resource type has been frozen. */
protected boolean m_frozen;
/** Contains the file extensions mapped to this resource type. */
protected List<String> m_mappings;
/** The module name if this is an additional resource type which is defined in a module. */
protected String m_moduleName;
/** The configured id of this resource type. */
protected int m_typeId;
/** The configured name of this resource type. */
protected String m_typeName;
/** The folder for which links should be adjusted after copying the copy-resources. */
private String m_adjustLinksFolder;
/** The gallery preview provider. */
private String m_galleryPreviewProvider;
/** The gallery type name for this resource type. */
private String m_galleryTypeNames;
/** The gallery type for this resource type. */
private List<I_CmsResourceType> m_galleryTypes;
/** The optional internal parameter value. */
private Boolean m_internal;
/**
* Default constructor, used to initialize some member variables.<p>
*/
public A_CmsResourceType() {
m_typeId = -1;
m_mappings = new ArrayList<String>();
m_defaultProperties = new ArrayList<CmsProperty>();
m_copyResources = new ArrayList<CmsConfigurationCopyResource>();
m_configuration = new CmsParameterConfiguration();
}
/**
* @see org.opencms.configuration.I_CmsConfigurationParameterHandler#addConfigurationParameter(java.lang.String, java.lang.String)
*/
public void addConfigurationParameter(String paramName, String paramValue) {
m_configuration.add(paramName, paramValue);
if (CmsStringUtil.isNotEmpty(paramName) && CmsStringUtil.isNotEmpty(paramValue)) {
if (CONFIGURATION_INTERNAL.equalsIgnoreCase(paramName)) {
m_internal = Boolean.valueOf(paramValue.trim());
}
if (CONFIGURATION_GALLERY_TYPE_NAMES.equalsIgnoreCase(paramName)) {
m_galleryTypeNames = paramValue.trim();
}
}
}
/**
* Adds a new "copy resource" to this resource type,
* allowed only during the configuration phase.<p>
*
* The "copy resources" are copied to the specified location after
* a new resource of this type is created. Usually this feature is used to
* populate a newly created folder with some default resources.<p>
*
* If target is <code>null</code>, the macro {@link #MACRO_RESOURCE_FOLDER_PATH} is used as default.
* If type is <code>null</code>, the copy type {@link CmsResource#COPY_AS_NEW} is used as default.<p>
*
* @param source the source resource
* @param target the target resource (may contain macros)
* @param type the type of the copy, for example "as new", "as sibling" etc
*
* @throws CmsConfigurationException if the configuration is already frozen
*/
public void addCopyResource(String source, String target, String type) throws CmsConfigurationException {
if (LOG.isDebugEnabled()) {
LOG.debug(Messages.get().getBundle().key(
Messages.LOG_ADD_COPY_RESOURCE_4,
new Object[] {this, source, target, type}));
}
if (m_frozen) {
// configuration already frozen
throw new CmsConfigurationException(Messages.get().container(
Messages.ERR_CONFIG_FROZEN_3,
this.getClass().getName(),
getTypeName(),
new Integer(getTypeId())));
}
// create the copy resource object an add it to the list
CmsConfigurationCopyResource copyResource = new CmsConfigurationCopyResource(source, target, type);
m_copyResources.add(copyResource);
}
/**
* Adds a default property to this resource type,
* allowed only during the configuration phase.<p>
*
* @param property the default property to add
*
* @throws CmsConfigurationException if the configuration is already frozen
*/
public void addDefaultProperty(CmsProperty property) throws CmsConfigurationException {
if (LOG.isDebugEnabled()) {
LOG.debug(Messages.get().getBundle().key(Messages.LOG_ADD_DFLT_PROP_2, this, property));
}
if (m_frozen) {
// configuration already frozen
throw new CmsConfigurationException(Messages.get().container(
Messages.ERR_CONFIG_FROZEN_3,
this.getClass().getName(),
getTypeName(),
new Integer(getTypeId())));
}
m_defaultProperties.add(property);
}
/**
* @see org.opencms.file.types.I_CmsResourceType#addMappingType(java.lang.String)
*/
public void addMappingType(String mapping) {
// this configuration does not support parameters
if (LOG.isDebugEnabled()) {
LOG.debug(Messages.get().getBundle().key(Messages.LOG_ADD_MAPPING_TYPE_2, mapping, this));
}
if (m_mappings == null) {
m_mappings = new ArrayList<String>();
}
m_mappings.add(mapping);
}
/**
* @see org.opencms.file.types.I_CmsResourceType#changeLock(org.opencms.file.CmsObject, CmsSecurityManager, CmsResource)
*/
public void changeLock(CmsObject cms, CmsSecurityManager securityManager, CmsResource resource) throws CmsException {
securityManager.changeLock(cms.getRequestContext(), resource);
}
/**
* @see org.opencms.file.types.I_CmsResourceType#chflags(org.opencms.file.CmsObject, CmsSecurityManager, CmsResource, int)
*/
public void chflags(CmsObject cms, CmsSecurityManager securityManager, CmsResource resource, int flags)
throws CmsException {
securityManager.chflags(cms.getRequestContext(), resource, flags);
}
/**
* @see org.opencms.file.types.I_CmsResourceType#chtype(org.opencms.file.CmsObject, CmsSecurityManager, CmsResource, int)
*/
public void chtype(CmsObject cms, CmsSecurityManager securityManager, CmsResource resource, int type)
throws CmsException {
// change type
securityManager.chtype(cms.getRequestContext(), resource, type);
// type may have changed from non link parseable to link parseable
createRelations(cms, securityManager, resource.getRootPath());
}
/**
* @see org.opencms.file.types.I_CmsResourceType#copyResource(org.opencms.file.CmsObject, CmsSecurityManager, CmsResource, java.lang.String, CmsResource.CmsResourceCopyMode)
*/
public void copyResource(
CmsObject cms,
CmsSecurityManager securityManager,
CmsResource source,
String destination,
CmsResource.CmsResourceCopyMode siblingMode) throws CmsException {
securityManager.copyResource(
cms.getRequestContext(),
source,
cms.getRequestContext().addSiteRoot(destination),
siblingMode);
// create the relations for the new resource, this could be improved by an sql query for copying relations
createRelations(cms, securityManager, cms.getRequestContext().addSiteRoot(destination));
}
/**
* @see org.opencms.file.types.I_CmsResourceType#copyResourceToProject(org.opencms.file.CmsObject, CmsSecurityManager, CmsResource)
*/
public void copyResourceToProject(CmsObject cms, CmsSecurityManager securityManager, CmsResource resource)
throws CmsException {
securityManager.copyResourceToProject(cms.getRequestContext(), resource);
}
/**
* @see org.opencms.file.types.I_CmsResourceType#createResource(org.opencms.file.CmsObject, CmsSecurityManager, java.lang.String, byte[], List)
*/
public CmsResource createResource(
CmsObject cms,
CmsSecurityManager securityManager,
String resourcename,
byte[] content,
List<CmsProperty> properties) throws CmsException {
// initialize a macro resolver with the current user OpenCms context
CmsMacroResolver resolver = getMacroResolver(cms, resourcename);
// add the predefined property values from the XML configuration to the resource
List<CmsProperty> newProperties = processDefaultProperties(properties, resolver);
CmsResource result = securityManager.createResource(
cms.getRequestContext(),
cms.getRequestContext().addSiteRoot(resourcename),
getTypeId(),
content,
newProperties);
if ((m_internal != null) && m_internal.booleanValue()) {
securityManager.chflags(cms.getRequestContext(), result, result.getFlags() ^ CmsResource.FLAG_INTERNAL);
}
// process the (optional) copy resources from the configuration
processCopyResources(cms, resourcename, resolver);
// create the relations for the new resource
createRelations(cms, securityManager, cms.getRequestContext().addSiteRoot(resourcename));
// return the created resource
return result;
}
/**
* @see org.opencms.file.types.I_CmsResourceType#createSibling(org.opencms.file.CmsObject, org.opencms.db.CmsSecurityManager, CmsResource, java.lang.String, java.util.List)
*/
public CmsResource createSibling(
CmsObject cms,
CmsSecurityManager securityManager,
CmsResource source,
String destination,
List<CmsProperty> properties) throws CmsException {
CmsResource sibling = securityManager.createSibling(
cms.getRequestContext(),
source,
cms.getRequestContext().addSiteRoot(destination),
properties);
// create the relations for the new resource, this could be improved by an sql query for copying relations
createRelations(cms, securityManager, sibling.getRootPath());
return sibling;
}
/**
* @see org.opencms.file.types.I_CmsResourceType#deleteResource(org.opencms.file.CmsObject, CmsSecurityManager, CmsResource, CmsResource.CmsResourceDeleteMode)
*/
public void deleteResource(
CmsObject cms,
CmsSecurityManager securityManager,
CmsResource resource,
CmsResource.CmsResourceDeleteMode siblingMode) throws CmsException {
securityManager.deleteResource(cms.getRequestContext(), resource, siblingMode);
}
/**
* Returns <code>true</code>, if this resource type is equal to the given Object.<p>
*
* Please note: A resource type is identified by it's id {@link #getTypeId()} and it's name {@link #getTypeName()}.
* Two resource types are considered equal, if either their id or their name is equal.
* This is to prevent issues in the configuration with multiple occurrences of the same name or id.<p>
*
* @param obj the Object to compare this resource type with
*
* @return <code>true</code>, if this resource type is equal to the given Object
*
* @see #getTypeId()
* @see #getTypeName()
* @see #isIdentical(I_CmsResourceType)
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj instanceof I_CmsResourceType) {
I_CmsResourceType other = (I_CmsResourceType)obj;
if (getTypeId() == other.getTypeId()) {
return true;
}
if ((getTypeName() != null) && (getTypeName().equals(other.getTypeName()))) {
return true;
}
}
return false;
}
/**
* @see org.opencms.file.types.I_CmsResourceType#getAdjustLinksFolder()
*/
public String getAdjustLinksFolder() {
return m_adjustLinksFolder;
}
/**
* @see org.opencms.file.types.I_CmsResourceType#getCachePropertyDefault()
*/
public String getCachePropertyDefault() {
return null;
}
/**
* Returns the configured class name of this resource type.<p>
*
* @see org.opencms.file.types.I_CmsResourceType#getClassName()
*/
public String getClassName() {
return m_className;
}
/**
* @see org.opencms.configuration.I_CmsConfigurationParameterHandler#getConfiguration()
*/
public CmsParameterConfiguration getConfiguration() {
if (LOG.isDebugEnabled()) {
LOG.debug(Messages.get().getBundle().key(Messages.LOG_GET_CONFIGURATION_1, this));
}
return m_configuration;
}
/**
* Returns the (unmodifiable) list of copy resources.<p>
*
* @return the (unmodifiable) list of copy resources
*/
public List<CmsConfigurationCopyResource> getConfiguredCopyResources() {
return m_copyResources;
}
/**
* Returns the default properties for this resource type in an unmodifiable List.<p>
*
* @return the default properties for this resource type in an unmodifiable List
*/
public List<CmsProperty> getConfiguredDefaultProperties() {
return m_defaultProperties;
}
/**
* @see org.opencms.file.types.I_CmsResourceType#getConfiguredMappings()
*/
public List<String> getConfiguredMappings() {
return m_mappings;
}
/**
*
* @see org.opencms.file.types.I_CmsResourceType#getFormattersForResource(org.opencms.file.CmsObject, org.opencms.file.CmsResource)
*/
public CmsFormatterConfiguration getFormattersForResource(CmsObject cms, CmsResource res) {
return CmsFormatterConfiguration.EMPTY_CONFIGURATION;
}
/**
* @see org.opencms.file.types.I_CmsResourceType#getGalleryPreviewProvider()
*/
public String getGalleryPreviewProvider() {
if (m_galleryPreviewProvider == null) {
m_galleryPreviewProvider = getConfiguration().getString(
CONFIGURATION_GALLERY_PREVIEW_PROVIDER,
DEFAULT_GALLERY_PREVIEW_PROVIDER);
}
return m_galleryPreviewProvider;
}
/**
* @see org.opencms.file.types.I_CmsResourceType#getGalleryTypes()
*/
public List<I_CmsResourceType> getGalleryTypes() {
if (m_galleryTypes == null) {
m_galleryTypes = new ArrayList<I_CmsResourceType>();
if (!CmsStringUtil.isEmptyOrWhitespaceOnly(m_galleryTypeNames)) {
CmsResourceManager rm = OpenCms.getResourceManager();
Iterator<String> iTypeNames = CmsStringUtil.splitAsList(
m_galleryTypeNames,
CmsProperty.VALUE_LIST_DELIMITER).iterator();
while (iTypeNames.hasNext()) {
String typeName = iTypeNames.next();
try {
m_galleryTypes.add(rm.getResourceType(typeName));
} catch (CmsLoaderException e) {
if (LOG.isWarnEnabled()) {
LOG.warn(Messages.get().container(Messages.ERR_COULD_NOT_READ_RESOURCE_TYPE_1, typeName));
}
}
}
}
}
return m_galleryTypes;
}
/**
* @see org.opencms.file.types.I_CmsResourceType#getLoaderId()
*/
public abstract int getLoaderId();
/**
* @see org.opencms.file.types.I_CmsResourceType#getModuleName()
*/
public String getModuleName() {
return m_moduleName;
}
/**
* @see org.opencms.file.types.I_CmsResourceType#getTypeId()
*/
public int getTypeId() {
return m_typeId;
}
/**
* @see org.opencms.file.types.I_CmsResourceType#getTypeName()
*/
public String getTypeName() {
return m_typeName;
}
/**
* The hash code implementation simply returns the unique type id of this resource type.
*
* @see #getTypeId()
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
return getTypeId();
}
/**
* @see org.opencms.file.types.I_CmsResourceType#importResource(org.opencms.file.CmsObject, CmsSecurityManager, java.lang.String, org.opencms.file.CmsResource, byte[], List)
*/
public CmsResource importResource(
CmsObject cms,
CmsSecurityManager securityManager,
String resourcename,
CmsResource resource,
byte[] content,
List<CmsProperty> properties) throws CmsException {
// this triggers the internal "is touched" state
// and prevents the security manager from inserting the current time
resource.setDateLastModified(resource.getDateLastModified());
// ensure resource record is updated
resource.setState(CmsResource.STATE_NEW);
return securityManager.importResource(
cms.getRequestContext(),
cms.getRequestContext().addSiteRoot(resourcename),
resource,
content,
properties,
true);
}
/**
* @see org.opencms.configuration.I_CmsConfigurationParameterHandler#initConfiguration()
*/
public final void initConfiguration() {
// final since subclasses should NOT implement this, but rather the version with 3 String parameters (see below)
if (LOG.isDebugEnabled()) {
LOG.debug(Messages.get().getBundle().key(Messages.LOG_INIT_CONFIGURATION_1, this));
}
}
/**
* @see org.opencms.file.types.I_CmsResourceType#initConfiguration(java.lang.String, java.lang.String, java.lang.String)
*/
public void initConfiguration(String name, String id, String className) throws CmsConfigurationException {
if (LOG.isDebugEnabled()) {
LOG.debug(Messages.get().getBundle().key(Messages.LOG_INIT_CONFIGURATION_3, this, name, id));
}
if (m_frozen) {
// configuration already frozen
throw new CmsConfigurationException(org.opencms.configuration.Messages.get().container(
org.opencms.file.types.Messages.ERR_CONFIG_FROZEN_3,
className,
getTypeName(),
new Integer(getTypeId())));
}
// freeze the configuration
m_frozen = true;
// set type name and id (please note that some resource types have a fixed type / id)
if (name != null) {
m_typeName = name;
}
if (id != null) {
m_typeId = Integer.valueOf(id).intValue();
}
if (className != null) {
m_className = className;
}
// check type id, type name and class name
if ((getTypeName() == null)
|| (getClassName() == null)
|| ((getTypeId() < 0) && (!m_typeName.equals(CmsResourceTypeUnknownFile.getStaticTypeName())) && (!m_typeName.equals(CmsResourceTypeUnknownFolder.getStaticTypeName())))) {
throw new CmsConfigurationException(Messages.get().container(
Messages.ERR_INVALID_RESTYPE_CONFIG_3,
className,
m_typeName,
new Integer(m_typeId)));
}
m_defaultProperties = Collections.unmodifiableList(m_defaultProperties);
m_copyResources = Collections.unmodifiableList(m_copyResources);
m_mappings = Collections.unmodifiableList(m_mappings);
m_configuration = CmsParameterConfiguration.unmodifiableVersion(m_configuration);
}
/**
* @see org.opencms.file.types.I_CmsResourceType#initialize(org.opencms.file.CmsObject)
*/
public void initialize(CmsObject cms) {
// most resource type do not require any runtime information
if (LOG.isDebugEnabled()) {
LOG.debug(Messages.get().getBundle().key(Messages.LOG_INITIALIZE_1, this));
}
}
/**
* @see org.opencms.file.types.I_CmsResourceType#isAdditionalModuleResourceType()
*/
public boolean isAdditionalModuleResourceType() {
return m_addititionalModuleResourceType;
}
/**
* @see org.opencms.file.types.I_CmsResourceType#isDirectEditable()
*/
public boolean isDirectEditable() {
return false;
}
/**
* @see org.opencms.file.types.I_CmsResourceType#isFolder()
*/
public boolean isFolder() {
return false;
}
/**
* @see org.opencms.file.types.I_CmsResourceType#isIdentical(org.opencms.file.types.I_CmsResourceType)
*/
public boolean isIdentical(I_CmsResourceType type) {
if (type == null) {
return false;
}
return (getTypeId() == type.getTypeId()) && (getTypeName().equals(type.getTypeName()));
}
/**
* @see org.opencms.file.types.I_CmsResourceType#lockResource(org.opencms.file.CmsObject, org.opencms.db.CmsSecurityManager, org.opencms.file.CmsResource, org.opencms.lock.CmsLockType)
*/
public void lockResource(CmsObject cms, CmsSecurityManager securityManager, CmsResource resource, CmsLockType type)
throws CmsException {
securityManager.lockResource(cms.getRequestContext(), resource, type);
}
/**
* @see org.opencms.file.types.I_CmsResourceType#moveResource(org.opencms.file.CmsObject, org.opencms.db.CmsSecurityManager, org.opencms.file.CmsResource, java.lang.String)
*/
public void moveResource(CmsObject cms, CmsSecurityManager securityManager, CmsResource resource, String destination)
throws CmsException, CmsIllegalArgumentException {
String dest = cms.getRequestContext().addSiteRoot(destination);
if (resource.getRootPath().equals(dest)) {
// move to target with same name is not allowed
throw new CmsVfsException(org.opencms.file.Messages.get().container(
org.opencms.file.Messages.ERR_MOVE_SAME_NAME_1,
destination));
}
// check the destination
try {
securityManager.readResource(cms.getRequestContext(), dest, CmsResourceFilter.ALL);
throw new CmsVfsException(org.opencms.file.Messages.get().container(
org.opencms.file.Messages.ERR_OVERWRITE_RESOURCE_2,
cms.getRequestContext().removeSiteRoot(resource.getRootPath()),
destination));
} catch (CmsVfsResourceNotFoundException e) {
// ok
}
String targetName = CmsResource.getName(destination).replace("/", "");
CmsResource.checkResourceName(targetName);
// move
securityManager.moveResource(cms.getRequestContext(), resource, dest);
}
/**
* @see org.opencms.file.types.I_CmsResourceType#removeResourceFromProject(org.opencms.file.CmsObject, org.opencms.db.CmsSecurityManager, org.opencms.file.CmsResource)
*/
public void removeResourceFromProject(CmsObject cms, CmsSecurityManager securityManager, CmsResource resource)
throws CmsException {
securityManager.removeResourceFromProject(cms.getRequestContext(), resource);
}
/**
* @see org.opencms.file.types.I_CmsResourceType#replaceResource(org.opencms.file.CmsObject, CmsSecurityManager, CmsResource, int, byte[], List)
*/
public void replaceResource(
CmsObject cms,
CmsSecurityManager securityManager,
CmsResource resource,
int type,
byte[] content,
List<CmsProperty> properties) throws CmsException {
securityManager.replaceResource(cms.getRequestContext(), resource, type, content, properties);
// type may have changed from non link parseable to link parseable
createRelations(cms, securityManager, resource.getRootPath());
}
/**
* @see org.opencms.file.types.I_CmsResourceType#restoreResource(org.opencms.file.CmsObject, CmsSecurityManager, CmsResource, int)
*/
public void restoreResource(CmsObject cms, CmsSecurityManager securityManager, CmsResource resource, int version)
throws CmsException {
securityManager.restoreResource(cms.getRequestContext(), resource, version);
// type may have changed from non link parseable to link parseable
createRelations(cms, securityManager, resource.getRootPath());
}
/**
* @see org.opencms.file.types.I_CmsResourceType#setAdditionalModuleResourceType(boolean)
*/
public void setAdditionalModuleResourceType(boolean additionalType) {
m_addititionalModuleResourceType = additionalType;
}
/**
* @see org.opencms.file.types.I_CmsResourceType#setAdjustLinksFolder(String)
*/
public void setAdjustLinksFolder(String adjustLinksFolder) {
m_adjustLinksFolder = adjustLinksFolder;
}
/**
* @see org.opencms.file.types.I_CmsResourceType#setDateExpired(org.opencms.file.CmsObject, CmsSecurityManager, CmsResource, long, boolean)
*/
public void setDateExpired(
CmsObject cms,
CmsSecurityManager securityManager,
CmsResource resource,
long dateExpired,
boolean recursive) throws CmsException {
securityManager.setDateExpired(cms.getRequestContext(), resource, dateExpired);
}
/**
* @see org.opencms.file.types.I_CmsResourceType#setDateLastModified(org.opencms.file.CmsObject, CmsSecurityManager, CmsResource, long, boolean)
*/
public void setDateLastModified(
CmsObject cms,
CmsSecurityManager securityManager,
CmsResource resource,
long dateLastModified,
boolean recursive) throws CmsException {
securityManager.setDateLastModified(cms.getRequestContext(), resource, dateLastModified);
}
/**
* @see org.opencms.file.types.I_CmsResourceType#setDateReleased(org.opencms.file.CmsObject, CmsSecurityManager, CmsResource, long, boolean)
*/
public void setDateReleased(
CmsObject cms,
CmsSecurityManager securityManager,
CmsResource resource,
long dateReleased,
boolean recursive) throws CmsException {
securityManager.setDateReleased(cms.getRequestContext(), resource, dateReleased);
}
/**
* @see org.opencms.file.types.I_CmsResourceType#setModuleName(java.lang.String)
*/
public void setModuleName(String moduleName) {
m_moduleName = moduleName;
}
/**
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
StringBuffer output = new StringBuffer();
output.append("[ResourceType] class=");
output.append(getClass().getName());
output.append(" name=");
output.append(getTypeName());
output.append(" id=");
output.append(getTypeId());
output.append(" loaderId=");
output.append(getLoaderId());
return output.toString();
}
/**
* @see org.opencms.file.types.I_CmsResourceType#undelete(org.opencms.file.CmsObject, CmsSecurityManager, CmsResource, boolean)
*/
public void undelete(CmsObject cms, CmsSecurityManager securityManager, CmsResource resource, boolean recursive)
throws CmsException {
securityManager.undelete(cms.getRequestContext(), resource);
}
/**
* @see org.opencms.file.types.I_CmsResourceType#undoChanges(org.opencms.file.CmsObject, CmsSecurityManager, CmsResource, CmsResource.CmsResourceUndoMode)
*/
public void undoChanges(
CmsObject cms,
CmsSecurityManager securityManager,
CmsResource resource,
CmsResource.CmsResourceUndoMode mode) throws CmsException {
securityManager.undoChanges(cms.getRequestContext(), resource, mode);
updateRelationForUndo(cms, securityManager, resource);
}
/**
* @see org.opencms.file.types.I_CmsResourceType#unlockResource(org.opencms.file.CmsObject, CmsSecurityManager, CmsResource)
*/
public void unlockResource(CmsObject cms, CmsSecurityManager securityManager, CmsResource resource)
throws CmsException {
securityManager.unlockResource(cms.getRequestContext(), resource);
}
/**
* @see org.opencms.file.types.I_CmsResourceType#writeFile(org.opencms.file.CmsObject, CmsSecurityManager, CmsFile)
*/
public CmsFile writeFile(CmsObject cms, CmsSecurityManager securityManager, CmsFile resource) throws CmsException {
if (resource.isFile()) {
CmsFile file = securityManager.writeFile(cms.getRequestContext(), resource);
I_CmsResourceType type = getResourceType(file);
// update the relations after writing!!
List<CmsLink> links = null;
if (type instanceof I_CmsLinkParseable) { // this check is needed because of type change
// if the new type is link parseable
links = ((I_CmsLinkParseable)type).parseLinks(cms, file);
}
// this has to be always executed, even if not link parseable to remove old links
securityManager.updateRelationsForResource(cms.getRequestContext(), file, links);
return file;
}
// folders can never be written like a file
throw new CmsVfsException(Messages.get().container(
Messages.ERR_WRITE_FILE_IS_FOLDER_1,
cms.getSitePath(resource)));
}
/**
* @see org.opencms.file.types.I_CmsResourceType#writePropertyObject(org.opencms.file.CmsObject, org.opencms.db.CmsSecurityManager, CmsResource, org.opencms.file.CmsProperty)
*/
public void writePropertyObject(
CmsObject cms,
CmsSecurityManager securityManager,
CmsResource resource,
CmsProperty property) throws CmsException {
securityManager.writePropertyObject(cms.getRequestContext(), resource, property);
}
/**
* @see org.opencms.file.types.I_CmsResourceType#writePropertyObjects(org.opencms.file.CmsObject, org.opencms.db.CmsSecurityManager, CmsResource, java.util.List)
*/
public void writePropertyObjects(
CmsObject cms,
CmsSecurityManager securityManager,
CmsResource resource,
List<CmsProperty> properties) throws CmsException {
securityManager.writePropertyObjects(cms.getRequestContext(), resource, properties);
}
/**
* Creates the relation information for the resource with the given resource name.<p>
*
* @param cms the cms context
* @param securityManager the security manager
* @param resourceName the resource name of the resource to update the relations for
*
* @return the fresh read resource
*
* @throws CmsException if something goes wrong
*/
protected CmsResource createRelations(CmsObject cms, CmsSecurityManager securityManager, String resourceName)
throws CmsException {
CmsResource resource = securityManager.readResource(
cms.getRequestContext(),
resourceName,
CmsResourceFilter.ALL);
I_CmsResourceType resourceType = getResourceType(resource);
List<CmsLink> links = null;
if (resourceType instanceof I_CmsLinkParseable) {
I_CmsLinkParseable linkParseable = (I_CmsLinkParseable)resourceType;
links = linkParseable.parseLinks(cms, cms.readFile(resource));
}
securityManager.updateRelationsForResource(cms.getRequestContext(), resource, links);
return resource;
}
/**
* Creates a macro resolver based on the current users OpenCms context and the provided resource name.<p>
*
* @param cms the current OpenCms user context
* @param resourcename the resource name for macros like {@link A_CmsResourceType#MACRO_RESOURCE_FOLDER_PATH}
*
* @return a macro resolver based on the current users OpenCms context and the provided resource name
*/
protected CmsMacroResolver getMacroResolver(CmsObject cms, String resourcename) {
CmsMacroResolver result = CmsMacroResolver.newInstance().setCmsObject(cms);
if (isFolder() && (!CmsResource.isFolder(resourcename))) {
// ensure folder ends with "/" so
resourcename = resourcename.concat("/");
}
// add special mappings for macros in default properties
result.addMacro(MACRO_RESOURCE_ROOT_PATH, cms.getRequestContext().addSiteRoot(resourcename));
result.addMacro(MACRO_RESOURCE_SITE_PATH, resourcename);
result.addMacro(MACRO_RESOURCE_FOLDER_PATH, CmsResource.getFolderPath(resourcename));
result.addMacro(MACRO_RESOURCE_FOLDER_PATH_TOUCH, CmsResource.getFolderPath(resourcename));
result.addMacro(MACRO_RESOURCE_PARENT_PATH, CmsResource.getParentFolder(resourcename));
result.addMacro(MACRO_RESOURCE_NAME, CmsResource.getName(resourcename));
return result;
}
/**
* Convenience method to get the initialized resource type instance for the given resource,
* with a fall back to special "unknown" resource types in case the resource type is not configured.<p>
*
* @param resource the resource to get the type for
*
* @return the initialized resource type instance for the given resource
*
* @see org.opencms.loader.CmsResourceManager#getResourceType(int)
*/
protected I_CmsResourceType getResourceType(CmsResource resource) {
return OpenCms.getResourceManager().getResourceType(resource);
}
/**
* Processes the copy resources of this resource type.<p>
*
* @param cms the current OpenCms user context
* @param resourcename the name of the base resource
* @param resolver the resolver used for resolving target macro names
*/
protected void processCopyResources(CmsObject cms, String resourcename, CmsMacroResolver resolver) {
Map<String, String> copiedResources = new HashMap<String, String>();
for (CmsConfigurationCopyResource oriCopyResource : m_copyResources) {
// store original copy target
String oriTarget = oriCopyResource.getTarget();
String target = oriTarget;
List<CmsConfigurationCopyResource> copyResources = new ArrayList<CmsConfigurationCopyResource>();
try {
// determine if source definition has a wild card character at the end
if (oriCopyResource.getSource().endsWith("*")) {
// add all sub resources of the specified source folder to the set of resources to copy
String source = oriCopyResource.getSource().substring(0, oriCopyResource.getSource().length() - 1);
List<CmsResource> sources = cms.readResources(source, CmsResourceFilter.IGNORE_EXPIRATION, false);
for (CmsResource sourceRes : sources) {
copyResources.add(new CmsConfigurationCopyResource(
cms.getSitePath(sourceRes),
oriCopyResource.getTarget(),
oriCopyResource.getTypeString()));
}
copiedResources.put(source, resolver.resolveMacros(target));
} else {
// just add the single specified source
copyResources.add(oriCopyResource);
}
// loop the calculated resources to copy
for (CmsConfigurationCopyResource copyResource : copyResources) {
target = copyResource.getTarget();
if (copyResource.isTargetWasNull()
|| CmsMacroResolver.isMacro(target, MACRO_RESOURCE_FOLDER_PATH)
|| CmsMacroResolver.isMacro(target, MACRO_RESOURCE_FOLDER_PATH_TOUCH)) {
// target is just the resource folder, must add source file name to target
target = target.concat(CmsResource.getName(copyResource.getSource()));
}
// now resolve the macros in the target name
target = resolver.resolveMacros(target);
// now resolve possible relative paths in the target
target = CmsFileUtil.normalizePath(CmsLinkManager.getAbsoluteUri(target, resourcename), '/');
// copy the resource
cms.copyResource(copyResource.getSource(), target, copyResource.getType());
copiedResources.put(copyResource.getSource(), target);
if (CmsMacroResolver.isMacro(oriTarget, MACRO_RESOURCE_FOLDER_PATH_TOUCH)) {
// copied resources should be touched in order to be able to do additional stuff
CmsResource res = cms.readResource(target);
if (res.isFile()) {
// single file, just rewrite it
CmsFile file = cms.readFile(res);
cms.writeFile(file);
} else {
// folder, get all sub resources that are files
Iterator<CmsResource> it = cms.readResources(target, CmsResourceFilter.DEFAULT_FILES, true).iterator();
while (it.hasNext()) {
// rewrite the sub resource
CmsResource subRes = it.next();
CmsFile file = cms.readFile(subRes);
cms.writeFile(file);
}
}
}
}
} catch (Exception e) {
// CmsIllegalArgumentException as well as CmsException
// log the error and continue with the other copy resources
if (LOG.isDebugEnabled()) {
// log stack trace in debug level only
LOG.debug(
Messages.get().getBundle().key(
Messages.LOG_PROCESS_COPY_RESOURCES_3,
resourcename,
oriCopyResource,
target),
e);
} else {
LOG.error(Messages.get().getBundle().key(
Messages.LOG_PROCESS_COPY_RESOURCES_3,
resourcename,
oriCopyResource,
target));
}
}
}
// only adjust links for successfully copied resources and if the feature is enabled
try {
if (!CmsStringUtil.isEmptyOrWhitespaceOnly(m_adjustLinksFolder) && !copiedResources.isEmpty()) {
String realAdjustFolderPath = resolver.resolveMacros(m_adjustLinksFolder);
cms.adjustLinks(copiedResources, realAdjustFolderPath);
}
} catch (CmsException e) {
LOG.error(e.getLocalizedMessage(), e);
} catch (CmsIllegalArgumentException e) {
LOG.error(e.getLocalizedMessage(), e);
}
}
/**
* Returns a list of property objects that are attached to the resource on creation.<p>
*
* It's possible to use OpenCms macros for the property values.
* Please see {@link CmsMacroResolver} for allowed macro values.<p>
*
* @param properties the (optional) properties provided by the user
* @param resolver the resolver used to resolve the macro values
*
* @return a list of property objects that are attached to the resource on creation
*/
protected List<CmsProperty> processDefaultProperties(List<CmsProperty> properties, CmsMacroResolver resolver) {
if ((m_defaultProperties == null) || (m_defaultProperties.size() == 0)) {
// no default properties are defined
return properties;
}
// the properties must be copied since the macros could contain macros that are
// resolved differently for every user / context
ArrayList<CmsProperty> result = new ArrayList<CmsProperty>();
Iterator<CmsProperty> i = m_defaultProperties.iterator();
while (i.hasNext()) {
// create a clone of the next property
CmsProperty property = (i.next()).clone();
// resolve possible macros in the property values
if (property.getResourceValue() != null) {
property.setResourceValue(resolver.resolveMacros(property.getResourceValue()));
}
if (property.getStructureValue() != null) {
property.setStructureValue(resolver.resolveMacros(property.getStructureValue()));
}
// save the new property in the result list
result.add(property);
}
// add the original properties
if (properties != null) {
result.addAll(properties);
}
// return the result
return result;
}
/**
* Update the relations after an undo changes operation.<p>
*
* @param cms the cms context
* @param securityManager the security manager
* @param resource the resource that has been undone
*
* @throws CmsException if something goes wrong
*/
protected void updateRelationForUndo(CmsObject cms, CmsSecurityManager securityManager, CmsResource resource)
throws CmsException {
// type may have changed from non link parseable to link parseable
CmsResource undoneResource1 = null;
try {
// first try to locate the resource by path
undoneResource1 = createRelations(cms, securityManager, resource.getRootPath());
} catch (CmsVfsResourceNotFoundException e) {
// ignore, undone move operation
}
// now, in case a move operation has been undone, locate the resource by id
CmsResource undoneResource2 = securityManager.readResource(
cms.getRequestContext(),
resource.getStructureId(),
CmsResourceFilter.ALL);
if (!undoneResource2.equals(undoneResource1)) {
I_CmsResourceType resourceType = getResourceType(resource);
List<CmsLink> links = null;
if (resourceType instanceof I_CmsLinkParseable) {
I_CmsLinkParseable linkParseable = (I_CmsLinkParseable)resourceType;
if ((undoneResource1 == null) || !undoneResource2.getRootPath().equals(undoneResource1.getRootPath())) {
try {
links = linkParseable.parseLinks(cms, cms.readFile(undoneResource2));
} catch (CmsException e) {
if (LOG.isWarnEnabled()) {
LOG.warn(e);
}
} catch (CmsRuntimeException e) {
if (LOG.isWarnEnabled()) {
LOG.warn(e);
}
}
}
}
securityManager.updateRelationsForResource(cms.getRequestContext(), undoneResource2, links);
}
}
}