/*
* 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.CmsConfigurationException;
import org.opencms.db.CmsSecurityManager;
import org.opencms.file.CmsFile;
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.CmsVfsException;
import org.opencms.loader.CmsDumpLoader;
import org.opencms.loader.CmsImageLoader;
import org.opencms.loader.CmsImageScaler;
import org.opencms.main.CmsException;
import org.opencms.main.CmsLog;
import org.opencms.main.OpenCms;
import org.opencms.security.CmsPermissionSet;
import org.opencms.security.CmsSecurityException;
import org.opencms.util.CmsStringUtil;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.logging.Log;
/**
* Resource type descriptor for the type "image".<p>
*
* @since 6.0.0
*/
public class CmsResourceTypeImage extends A_CmsResourceType {
/**
* A data container for image size and scale operations.<p>
*/
protected static class CmsImageAdjuster {
/** The image byte content. */
private byte[] m_content;
/** The (optional) image scaler that contains the image downscale settings. */
private CmsImageScaler m_imageDownScaler;
/** The image properties. */
private List<CmsProperty> m_properties;
/** The image root path. */
private String m_rootPath;
/**
* Creates a new image data container.<p>
*
* @param content the image byte content
* @param rootPath the image root path
* @param properties the image properties
* @param downScaler the (optional) image scaler that contains the image downscale settings
*/
public CmsImageAdjuster(byte[] content, String rootPath, List<CmsProperty> properties, CmsImageScaler downScaler) {
m_content = content;
m_rootPath = rootPath;
m_properties = properties;
m_imageDownScaler = downScaler;
}
/**
* Calculates the image size and adjusts the image dimensions (if required) accoring to the configured
* image downscale settings.<p>
*
* The image dimensions are always calculated from the given image. The internal list of properties is updated
* with a value for <code>{@link CmsPropertyDefinition#PROPERTY_IMAGE_SIZE}</code> that
* contains the calculated image dimensions.<p>
*/
public void adjust() {
CmsImageScaler scaler = new CmsImageScaler(getContent(), getRootPath());
if (!scaler.isValid()) {
// error calculating image dimensions - this image can't be scaled or resized
return;
}
// check if the image is to big and needs to be rescaled
if (scaler.isDownScaleRequired(m_imageDownScaler)) {
// image is to big, perform rescale operation
CmsImageScaler downScaler = scaler.getDownScaler(m_imageDownScaler);
// perform the rescale using the adjusted size
m_content = downScaler.scaleImage(m_content, m_rootPath);
// image size has been changed, adjust the scaler for later setting of properties
scaler.setHeight(downScaler.getHeight());
scaler.setWidth(downScaler.getWidth());
}
CmsProperty p = new CmsProperty(CmsPropertyDefinition.PROPERTY_IMAGE_SIZE, null, scaler.toString());
// create the new property list if required (don't modify the original List)
List<CmsProperty> result = new ArrayList<CmsProperty>();
if ((m_properties != null) && (m_properties.size() > 0)) {
result.addAll(m_properties);
result.remove(p);
}
// add the updated property
result.add(p);
// store the changed properties
m_properties = result;
}
/**
* Returns the image content.<p>
*
* @return the image content
*/
public byte[] getContent() {
return m_content;
}
/**
* Returns the image properties.<p>
*
* @return the image properties
*/
public List<CmsProperty> getProperties() {
return m_properties;
}
/**
* Returns the image VFS root path.<p>
*
* @return the image VFS root path
*/
public String getRootPath() {
return m_rootPath;
}
}
/** The gallery preview provider. */
private String m_galleryPreviewProvider;
/** The default image preview provider. */
private static final String GALLERY_PREVIEW_PROVIDER = "org.opencms.ade.galleries.preview.CmsImagePreviewProvider";
/** The log object for this class. */
public static final Log LOG = CmsLog.getLog(CmsResourceTypeImage.class);
/**
* The value for the {@link CmsPropertyDefinition#PROPERTY_IMAGE_SIZE} property if resources in
* a folder should never be downscaled.<p>
*/
public static final String PROPERTY_VALUE_UNLIMITED = "unlimited";
/** The image scaler for the image downscale operation (if configured). */
private static CmsImageScaler m_downScaler;
/** Indicates that the static configuration of the resource type has been frozen. */
private static boolean m_staticFrozen;
/** The static resource loader id of this resource type. */
private static int m_staticLoaderId;
/** The static type id of this resource type. */
private static int m_staticTypeId;
/** The type id of this resource type. */
private static final int RESOURCE_TYPE_ID = 3;
/** The name of this resource type. */
private static final String RESOURCE_TYPE_NAME = "image";
/**
* Default constructor, used to initialize member variables.<p>
*/
public CmsResourceTypeImage() {
super();
m_typeId = RESOURCE_TYPE_ID;
m_typeName = RESOURCE_TYPE_NAME;
}
/**
* Returns the image downscaler to use when writing an image resource to the given root path.<p>
*
* If <code>null</code> is returned, image downscaling must not be used for the resource with the given path.
* This may be the case if image downscaling is not configured at all, or if image downscaling has been disabled
* for the parent folder by setting the folders property {@link CmsPropertyDefinition#PROPERTY_IMAGE_SIZE}
* to the value {@link #PROPERTY_VALUE_UNLIMITED}.<p>
*
* @param cms the current OpenCms user context
* @param rootPath the root path of the resource to write
*
* @return the downscaler to use, or <code>null</code> if no downscaling is required for the resource
*/
public static CmsImageScaler getDownScaler(CmsObject cms, String rootPath) {
if (m_downScaler == null) {
// downscaling is not configured at all
return null;
}
// try to read the image.size property from the parent folder
String parentFolder = CmsResource.getParentFolder(rootPath);
parentFolder = cms.getRequestContext().removeSiteRoot(parentFolder);
try {
CmsProperty fileSizeProperty = cms.readPropertyObject(
parentFolder,
CmsPropertyDefinition.PROPERTY_IMAGE_SIZE,
false);
if (!fileSizeProperty.isNullProperty()) {
// image.size property has been set
String value = fileSizeProperty.getValue().trim();
if (CmsStringUtil.isNotEmpty(value)) {
if (PROPERTY_VALUE_UNLIMITED.equals(value)) {
// in this case no downscaling must be done
return null;
} else {
CmsImageScaler scaler = new CmsImageScaler(value);
if (scaler.isValid()) {
// special folder based scaler settings have been set
return scaler;
}
}
}
}
} catch (CmsException e) {
// ignore, continue with given downScaler
}
return (CmsImageScaler)m_downScaler.clone();
}
/**
* Returns the static type id of this (default) resource type.<p>
*
* @return the static type id of this (default) resource type
*/
public static int getStaticTypeId() {
return m_staticTypeId;
}
/**
* Returns the static type name of this (default) resource type.<p>
*
* @return the static type name of this (default) resource type
*/
public static String getStaticTypeName() {
return RESOURCE_TYPE_NAME;
}
/**
* @see org.opencms.file.types.I_CmsResourceType#createResource(org.opencms.file.CmsObject, org.opencms.db.CmsSecurityManager, java.lang.String, byte[], java.util.List)
*/
@Override
public CmsResource createResource(
CmsObject cms,
CmsSecurityManager securityManager,
String resourcename,
byte[] content,
List<CmsProperty> properties) throws CmsException {
if (CmsImageLoader.isEnabled()) {
String rootPath = cms.getRequestContext().addSiteRoot(resourcename);
// get the downscaler to use
CmsImageScaler downScaler = getDownScaler(cms, rootPath);
// create a new image scale adjuster
CmsImageAdjuster adjuster = new CmsImageAdjuster(content, rootPath, properties, downScaler);
// update the image scale adjuster - this will calculate the image dimensions and (optionally) downscale the size
adjuster.adjust();
// continue with the updated content and properties
content = adjuster.getContent();
properties = adjuster.getProperties();
}
return super.createResource(cms, securityManager, resourcename, content, properties);
}
/**
* @see org.opencms.file.types.I_CmsResourceType#getGalleryPreviewProvider()
*/
@Override
public String getGalleryPreviewProvider() {
if (m_galleryPreviewProvider == null) {
m_galleryPreviewProvider = getConfiguration().getString(
CONFIGURATION_GALLERY_PREVIEW_PROVIDER,
GALLERY_PREVIEW_PROVIDER);
}
return m_galleryPreviewProvider;
}
/**
* @see org.opencms.file.types.I_CmsResourceType#getLoaderId()
*/
@Override
public int getLoaderId() {
return m_staticLoaderId;
}
/**
* @see org.opencms.file.types.I_CmsResourceType#importResource(org.opencms.file.CmsObject, org.opencms.db.CmsSecurityManager, java.lang.String, org.opencms.file.CmsResource, byte[], java.util.List)
*/
@Override
public CmsResource importResource(
CmsObject cms,
CmsSecurityManager securityManager,
String resourcename,
CmsResource resource,
byte[] content,
List<CmsProperty> properties) throws CmsException {
if (CmsImageLoader.isEnabled()) {
// siblings have null content in import
if (content != null) {
// get the downscaler to use
CmsImageScaler downScaler = getDownScaler(cms, resource.getRootPath());
// create a new image scale adjuster
CmsImageAdjuster adjuster = new CmsImageAdjuster(
content,
resource.getRootPath(),
properties,
downScaler);
// update the image scale adjuster - this will calculate the image dimensions and (optionally) adjust the size
adjuster.adjust();
// continue with the updated content and properties
content = adjuster.getContent();
properties = adjuster.getProperties();
}
}
return super.importResource(cms, securityManager, resourcename, resource, content, properties);
}
/**
* @see org.opencms.file.types.A_CmsResourceType#initConfiguration(java.lang.String, java.lang.String, String)
*/
@Override
public void initConfiguration(String name, String id, String className) throws CmsConfigurationException {
if ((OpenCms.getRunLevel() > OpenCms.RUNLEVEL_2_INITIALIZING) && m_staticFrozen) {
// configuration already frozen
throw new CmsConfigurationException(Messages.get().container(
Messages.ERR_CONFIG_FROZEN_3,
this.getClass().getName(),
getStaticTypeName(),
new Integer(getStaticTypeId())));
}
if (!RESOURCE_TYPE_NAME.equals(name)) {
// default resource type MUST have default name
throw new CmsConfigurationException(Messages.get().container(
Messages.ERR_INVALID_RESTYPE_CONFIG_NAME_3,
this.getClass().getName(),
RESOURCE_TYPE_NAME,
name));
}
// freeze the configuration
m_staticFrozen = true;
super.initConfiguration(RESOURCE_TYPE_NAME, id, className);
// set static members with values from the configuration
m_staticTypeId = m_typeId;
if (CmsImageLoader.isEnabled()) {
// the image loader is enabled, image operations are supported
m_staticLoaderId = CmsImageLoader.RESOURCE_LOADER_ID_IMAGE_LOADER;
// set the maximum size scaler
String downScaleParams = CmsImageLoader.getDownScaleParams();
if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(downScaleParams)) {
m_downScaler = new CmsImageScaler(downScaleParams);
if (!m_downScaler.isValid()) {
// ignore invalid parameters
m_downScaler = null;
}
}
} else {
// no image operations are supported, use dump loader
m_staticLoaderId = CmsDumpLoader.RESOURCE_LOADER_ID;
// disable maximum image size operation
m_downScaler = null;
}
}
/**
* @see org.opencms.file.types.I_CmsResourceType#replaceResource(org.opencms.file.CmsObject, org.opencms.db.CmsSecurityManager, org.opencms.file.CmsResource, int, byte[], java.util.List)
*/
@Override
public void replaceResource(
CmsObject cms,
CmsSecurityManager securityManager,
CmsResource resource,
int type,
byte[] content,
List<CmsProperty> properties) throws CmsException {
if (CmsImageLoader.isEnabled()) {
// check if the user has write access and if resource is locked
// done here so that no image operations are performed in case no write access is granted
securityManager.checkPermissions(
cms.getRequestContext(),
resource,
CmsPermissionSet.ACCESS_WRITE,
true,
CmsResourceFilter.ALL);
// get the downscaler to use
CmsImageScaler downScaler = getDownScaler(cms, resource.getRootPath());
// create a new image scale adjuster
CmsImageAdjuster adjuster = new CmsImageAdjuster(content, resource.getRootPath(), properties, downScaler);
// update the image scale adjuster - this will calculate the image dimensions and (optionally) adjust the size
adjuster.adjust();
// continue with the updated content
content = adjuster.getContent();
if (adjuster.getProperties() != null) {
// write properties
writePropertyObjects(cms, securityManager, resource, adjuster.getProperties());
}
}
super.replaceResource(cms, securityManager, resource, type, content, properties);
}
/**
* @see org.opencms.file.types.I_CmsResourceType#writeFile(org.opencms.file.CmsObject, org.opencms.db.CmsSecurityManager, org.opencms.file.CmsFile)
*/
@Override
public CmsFile writeFile(CmsObject cms, CmsSecurityManager securityManager, CmsFile resource)
throws CmsException, CmsVfsException, CmsSecurityException {
if (CmsImageLoader.isEnabled()) {
// check if the user has write access and if resource is locked
// done here so that no image operations are performed in case no write access is granted
securityManager.checkPermissions(
cms.getRequestContext(),
resource,
CmsPermissionSet.ACCESS_WRITE,
true,
CmsResourceFilter.ALL);
// get the downscaler to use
CmsImageScaler downScaler = getDownScaler(cms, resource.getRootPath());
// create a new image scale adjuster
CmsImageAdjuster adjuster = new CmsImageAdjuster(
resource.getContents(),
resource.getRootPath(),
null,
downScaler);
// update the image scale adjuster - this will calculate the image dimensions and (optionally) adjust the size
adjuster.adjust();
// continue with the updated content
resource.setContents(adjuster.getContent());
if (adjuster.getProperties() != null) {
// write properties
writePropertyObjects(cms, securityManager, resource, adjuster.getProperties());
}
}
return super.writeFile(cms, securityManager, resource);
}
}