Merging DEV_TEMPORARY to HEAD (RenditionService)

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@19103 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Neil McErlean
2010-03-05 20:02:52 +00:00
parent ad84497735
commit bce28a5599
80 changed files with 10611 additions and 1815 deletions

View File

@@ -19,30 +19,43 @@
package org.alfresco.repo.thumbnail;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.alfresco.repo.rendition.executer.AbstractRenderingEngine;
import org.alfresco.service.cmr.rendition.RenditionDefinition;
import org.alfresco.service.cmr.rendition.RenditionService;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.thumbnail.ThumbnailException;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
/**
* Registry of all the thumbnail details available
*
* @author Roy Wetherall
* @author Neil McErlean
*/
public class ThumbnailRegistry
{
/** Content service */
private ContentService contentService;
/** Map of thumbnail defintion */
private Map<String, ThumbnailDefinition> thumbnailDefinitions = new HashMap<String, ThumbnailDefinition>(7);
/** Rendition service */
private RenditionService renditionService;
private List<String> thumbnails;
/** This flag indicates whether the thumbnail definitions have been lazily loaded or not. */
private boolean thumbnailDefinitionsInited = false;
/** Map of thumbnail definition */
private Map<String, ThumbnailDefinition> thumbnailDefinitions = new HashMap<String, ThumbnailDefinition>();
/** Cache to store mimetype to thumbnailDefinition mapping */
private Map<String, List<ThumbnailDefinition>> mimetypeMap = new HashMap<String, List<ThumbnailDefinition>>(17);
/**
* Content service
*
@@ -54,36 +67,63 @@ public class ThumbnailRegistry
}
/**
* Add a number of thumbnail defintions
* Rendition service
*
* @param thumbnailDefinitions list of thumbnail details
* @param renditionService rendition service
*/
public void setThumbnailDefinitions(List<ThumbnailDefinition> thumbnailDefinitions)
public void setRenditionService(RenditionService renditionService)
{
for (ThumbnailDefinition value : thumbnailDefinitions)
{
addThumbnailDefinition(value);
}
this.renditionService = renditionService;
}
public void setThumbnails(final List<String> thumbnails)
{
this.thumbnails = thumbnails;
// We'll not populate the data fields in the ThumbnailRegistry here, instead preferring
// to do it lazily later.
}
/**
* Get a list of all the thumbnail defintions
* Get a list of all the thumbnail definitions
*
* @return Collection<ThumbnailDefinition> colleciton of thumbnail defintions
* @return Collection<ThumbnailDefinition> collection of thumbnail definitions
*/
public List<ThumbnailDefinition> getThumbnailDefinitions()
{
if (thumbnailDefinitionsInited == false)
{
this.initThumbnailDefinitions();
thumbnailDefinitionsInited = true;
}
return new ArrayList<ThumbnailDefinition>(this.thumbnailDefinitions.values());
}
/**
*
* @param mimetype
* @return
*/
public List<ThumbnailDefinition> getThumnailDefintions(String mimetype)
private void initThumbnailDefinitions()
{
List<ThumbnailDefinition> result = this.mimetypeMap.get(mimetype);;
ThumbnailRenditionConvertor thumbnailRenditionConvertor = new ThumbnailRenditionConvertor();
for (String thumbnailDefinitionName : this.thumbnails)
{
QName qName = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, thumbnailDefinitionName);
RenditionDefinition rAction = renditionService
.loadRenditionDefinition(qName);
ThumbnailDefinition thDefn = thumbnailRenditionConvertor.convert(rAction);
thumbnailDefinitions.put(thumbnailDefinitionName, thDefn);
}
}
public List<ThumbnailDefinition> getThumbnailDefinitions(String mimetype)
{
if (thumbnailDefinitionsInited == false)
{
this.initThumbnailDefinitions();
thumbnailDefinitionsInited = true;
}
List<ThumbnailDefinition> result = this.mimetypeMap.get(mimetype);
if (result == null)
{
@@ -107,12 +147,28 @@ public class ThumbnailRegistry
}
/**
* Add a thumnail details
*
* @param mimetype
* @return
* @deprecated Use {@link #getThumbnailDefinitions(String)} instead.
*/
public List<ThumbnailDefinition> getThumnailDefintions(String mimetype)
{
return this.getThumbnailDefinitions(mimetype);
}
/**
* Add a thumbnail details
*
* @param thumbnailDetails thumbnail details
*/
public void addThumbnailDefinition(ThumbnailDefinition thumbnailDetails)
{
if (thumbnailDefinitionsInited == false)
{
this.initThumbnailDefinitions();
thumbnailDefinitionsInited = true;
}
String thumbnailName = thumbnailDetails.getName();
if (thumbnailName == null)
{
@@ -130,6 +186,11 @@ public class ThumbnailRegistry
*/
public ThumbnailDefinition getThumbnailDefinition(String thumbnailName)
{
if (thumbnailDefinitionsInited == false)
{
this.initThumbnailDefinitions();
thumbnailDefinitionsInited = true;
}
return this.thumbnailDefinitions.get(thumbnailName);
}
}

View File

@@ -0,0 +1,164 @@
/*
* Copyright (C) 2005-2010 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.thumbnail;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import org.alfresco.repo.content.transform.magick.ImageResizeOptions;
import org.alfresco.repo.content.transform.magick.ImageTransformationOptions;
import org.alfresco.repo.content.transform.swf.SWFTransformationOptions;
import org.alfresco.repo.rendition.executer.AbstractRenderingEngine;
import org.alfresco.repo.rendition.executer.ImageRenderingEngine;
import org.alfresco.repo.rendition.executer.ReformatRenderingEngine;
import org.alfresco.service.cmr.rendition.RenditionDefinition;
import org.alfresco.service.cmr.rendition.RenditionService;
import org.alfresco.service.cmr.repository.TransformationOptions;
import org.alfresco.service.cmr.thumbnail.ThumbnailParentAssociationDetails;
/**
* A helper class to convert {@link TransformationOptions transformationOptions} (a thumbnail-specific
* class) to rendition-specific parameters and vice versa.
*
* @author Neil McErlean
*/
public class ThumbnailRenditionConvertor
{
public Map<String, Serializable> convert(TransformationOptions transformationOptions, ThumbnailParentAssociationDetails assocDetails)
{
Map<String, Serializable> parameters = new HashMap<String, Serializable>();
// parameters common to all transformations
putParameterIfNotNull(AbstractRenderingEngine.PARAM_SOURCE_CONTENT_PROPERTY, transformationOptions.getSourceContentProperty(), parameters);
putParameterIfNotNull(AbstractRenderingEngine.PARAM_TARGET_CONTENT_PROPERTY, transformationOptions.getTargetContentProperty(), parameters);
putParameterIfNotNull(RenditionService.PARAM_DESTINATION_NODE, transformationOptions.getTargetNodeRef(), parameters);
// putParameterIfNotNull(ImageRenderingEngine.PARAM_ASSOC_NAME, assocDetails.getAssociationName(), parameters);
// putParameterIfNotNull(ImageRenderingEngine.PARAM_ASSOC_TYPE, assocDetails.getAssociationType(), parameters);
if (transformationOptions instanceof SWFTransformationOptions)
{
SWFTransformationOptions swfTransformationOptions = (SWFTransformationOptions)transformationOptions;
putParameterIfNotNull(ReformatRenderingEngine.PARAM_FLASH_VERSION, swfTransformationOptions.getFlashVersion(), parameters);
}
else if (transformationOptions instanceof ImageTransformationOptions)
{
ImageTransformationOptions imTransformationOptions = (ImageTransformationOptions)transformationOptions;
putParameterIfNotNull(ImageRenderingEngine.PARAM_COMMAND_OPTIONS, imTransformationOptions.getCommandOptions(), parameters);
ImageResizeOptions imgResizeOptions = imTransformationOptions.getResizeOptions();
if (imgResizeOptions != null)
{
int width = imgResizeOptions.getWidth();
parameters.put(ImageRenderingEngine.PARAM_RESIZE_WIDTH, width);
int height = imgResizeOptions.getHeight();
parameters.put(ImageRenderingEngine.PARAM_RESIZE_HEIGHT, height);
boolean maintainAspectRatio = imgResizeOptions.isMaintainAspectRatio();
parameters.put(ImageRenderingEngine.PARAM_MAINTAIN_ASPECT_RATIO, maintainAspectRatio);
boolean percentResize = imgResizeOptions.isPercentResize();
parameters.put(ImageRenderingEngine.PARAM_IS_PERCENT_RESIZE, percentResize);
boolean resizeToThumbnail = imgResizeOptions.isResizeToThumbnail();
parameters.put(ImageRenderingEngine.PARAM_RESIZE_TO_THUMBNAIL, resizeToThumbnail);
}
}
return parameters;
}
private void putParameterIfNotNull(String paramName, Serializable paramValue, Map<String, Serializable> params)
{
if (paramValue != null)
{
params.put(paramName, paramValue);
}
}
public ThumbnailDefinition convert(RenditionDefinition renditionDefinition)
{
ThumbnailDefinition thDefn = new ThumbnailDefinition();
Map<String, Serializable> params = renditionDefinition.getParameterValues();
//parameters common to all the built-in thumbnail definitions
Serializable mimeTypeParam = params.get(AbstractRenderingEngine.PARAM_MIME_TYPE);
thDefn.setMimetype((String) mimeTypeParam);
thDefn.setName(renditionDefinition.getRenditionName().getLocalName());
Serializable placeHolderResourcePathParam = params.get(AbstractRenderingEngine.PARAM_PLACEHOLDER_RESOURCE_PATH);
if (placeHolderResourcePathParam != null)
{
thDefn.setPlaceHolderResourcePath((String)placeHolderResourcePathParam);
}
//TODO src/target contentProp & nodeRef
TransformationOptions transformationOptions = null;
Serializable flashVersion = renditionDefinition.getParameterValue(ReformatRenderingEngine.PARAM_FLASH_VERSION);
if (flashVersion != null)
{
// Thumbnails based on SWFTransformationOptions
transformationOptions = new SWFTransformationOptions();
SWFTransformationOptions swfTranOpts = (SWFTransformationOptions)transformationOptions;
swfTranOpts.setFlashVersion((String)flashVersion);
}
else
{
// Thumbnails based on ImageTransformationOptions
transformationOptions = new ImageTransformationOptions();
ImageTransformationOptions imgTrOpts = (ImageTransformationOptions)transformationOptions;
ImageResizeOptions resizeOptions = new ImageResizeOptions();
Serializable xsize = renditionDefinition.getParameterValue(ImageRenderingEngine.PARAM_RESIZE_WIDTH);
if (xsize != null)
{
// Saved actions with int parameters seem to be coming back as Longs. TODO Investigate
resizeOptions.setWidth(((Long) xsize).intValue());
}
Serializable ysize = renditionDefinition.getParameterValue(ImageRenderingEngine.PARAM_RESIZE_HEIGHT);
if (ysize != null)
{
resizeOptions.setHeight(((Long) ysize).intValue());
}
Serializable maintainAspectRatio = renditionDefinition.getParameterValue(ImageRenderingEngine.PARAM_MAINTAIN_ASPECT_RATIO);
if (maintainAspectRatio != null)
{
resizeOptions.setMaintainAspectRatio((Boolean) maintainAspectRatio);
}
Serializable resizeToThumbnail = renditionDefinition.getParameterValue(ImageRenderingEngine.PARAM_RESIZE_TO_THUMBNAIL);
if (resizeToThumbnail != null)
{
resizeOptions.setResizeToThumbnail((Boolean) resizeToThumbnail);
}
imgTrOpts.setResizeOptions(resizeOptions);
}
thDefn.setTransformationOptions(transformationOptions);
return thDefn;
}
}

View File

@@ -19,21 +19,24 @@
package org.alfresco.repo.thumbnail;
import java.io.Serializable;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.content.transform.magick.ImageTransformationOptions;
import org.alfresco.repo.content.transform.swf.SWFTransformationOptions;
import org.alfresco.repo.policy.BehaviourFilter;
import org.alfresco.repo.rendition.executer.ImageRenderingEngine;
import org.alfresco.repo.rendition.executer.ReformatRenderingEngine;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.service.cmr.rendition.RenditionDefinition;
import org.alfresco.service.cmr.rendition.RenditionService;
import org.alfresco.service.cmr.rendition.RenditionServiceException;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.TransformationOptions;
@@ -42,14 +45,14 @@ import org.alfresco.service.cmr.thumbnail.ThumbnailParentAssociationDetails;
import org.alfresco.service.cmr.thumbnail.ThumbnailService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern;
import org.alfresco.util.GUID;
import org.springframework.extensions.surf.util.ParameterCheck;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.extensions.surf.util.ParameterCheck;
/**
* @author Roy Wetherall
* @author Neil McErlean
*/
public class ThumbnailServiceImpl implements ThumbnailService
{
@@ -79,6 +82,19 @@ public class ThumbnailServiceImpl implements ThumbnailService
/** Thumbnail registry */
private ThumbnailRegistry thumbnailRegistry;
/** Rendition service */
private RenditionService renditionService;
/**
* Set the rendition service.
*
* @param renditionService
*/
public void setRenditionService(RenditionService renditionService)
{
this.renditionService = renditionService;
}
/**
* Set the node service
*
@@ -168,118 +184,89 @@ public class ThumbnailServiceImpl implements ThumbnailService
logger.debug("Creating thumbnail: There is already a thumbnail with the name '" + thumbnailName + "' (node=" + node.toString() + "; contentProperty=" + contentProperty.toString() + "; mimetype=" + mimetype);
}
// We can't continue because there is already an thumbnail with the given name for that content property
// We can't continue because there is already a thumbnail with the given name for that content property
throw new ThumbnailException(ERR_DUPLICATE_NAME);
}
NodeRef thumbnail = AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<NodeRef>()
ChildAssociationRef thumbnailRef = AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<ChildAssociationRef>()
{
public NodeRef doWork() throws Exception
public ChildAssociationRef doWork() throws Exception
{
NodeRef thumbnail;
// Apply the thumbnailed aspect to the node if it doesn't already have it
if (nodeService.hasAspect(node, ContentModel.ASPECT_THUMBNAILED) == false)
{
// Ensure we do not update the 'modifier' due to thumbnail addition
behaviourFilter.disableBehaviour(node, ContentModel.ASPECT_AUDITABLE);
try
{
nodeService.addAspect(node, ContentModel.ASPECT_THUMBNAILED, null);
}
finally
{
behaviourFilter.enableBehaviour(node, ContentModel.ASPECT_AUDITABLE);
}
}
// Need a variable scoped to this inner class in order to assign a new value to it.
String localThumbnailName = thumbnailName;
// Get the name of the thumbnail and add to properties map
String thumbName = thumbnailName;
Map<QName, Serializable> properties = new HashMap<QName, Serializable>(4);
if (thumbName == null || thumbName.length() == 0)
if (localThumbnailName == null || localThumbnailName.length() == 0)
{
thumbName = GUID.generate();
localThumbnailName = GUID.generate();
}
else
{
String thumbnailFileName = generateThumbnailFileName(thumbName, mimetype);
properties.put(ContentModel.PROP_NAME, thumbnailFileName);
}
properties.put(ContentModel.PROP_THUMBNAIL_NAME, thumbName);
// Add the name of the content property
properties.put(ContentModel.PROP_CONTENT_PROPERTY_NAME, contentProperty);
// See if parent association details have been specified for the thumbnail
if (assocDetails == null)
{
// Create the thumbnail using the thumbnails child association
thumbnail = nodeService.createNode(
node,
ContentModel.ASSOC_THUMBNAILS,
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, thumbName),
ContentModel.TYPE_THUMBNAIL,
properties).getChildRef();
}
else
{
// Create the thumbnail using the specified parent assoc details
thumbnail = nodeService.createNode(
assocDetails.getParent(),
assocDetails.getAssociationType(),
assocDetails.getAssociationName(),
ContentModel.TYPE_THUMBNAIL,
properties).getChildRef();
// We're prepending the cm namespace here.
QName thumbnailQName = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, localThumbnailName);
// Associate the new thumbnail to the source
nodeService.addChild(
node,
thumbnail,
ContentModel.ASSOC_THUMBNAILS,
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, thumbName));
}
// Get the content reader and writer for content nodes
ContentReader reader = contentService.getReader(node, contentProperty);
ContentWriter writer = contentService.getWriter(thumbnail, ContentModel.PROP_CONTENT, true);
writer.setMimetype(mimetype);
writer.setEncoding(reader.getEncoding());
// Catch the failure to create the thumbnail
if (contentService.isTransformable(reader, writer, transformationOptions) == false)
RenditionDefinition renderingAction = renditionService.loadRenditionDefinition(thumbnailQName);
if (renderingAction == null)
{
if (logger.isDebugEnabled() == true)
{
logger.debug("Creating thumbnail: There is no transformer to generate the thumbnail required (node=" + node.toString() + "; contentProperty=" + contentProperty.toString() + "; mimetype=" + mimetype + ")");
}
// If the provided thumbnailName does not map to a built-in rendition definition
// then we must create a dynamic rendition definition for this thumbnail.
// To do this we must have a renderingEngineName.
//
// The transformation will either be a imageRenderingEngine or a reformat (pdf2swf)
String renderingEngineName = getRenderingEngineNameFor(transformationOptions);
// Throw exception indicating that the thumbnail could not be created
throw new ThumbnailException(MessageFormat.format(ERR_NO_CREATE, reader.getMimetype(), writer.getMimetype()));
renderingAction = renditionService.createRenditionDefinition(thumbnailQName, renderingEngineName);
}
else
Map<String, Serializable> params = new ThumbnailRenditionConvertor().convert(transformationOptions, assocDetails);
for (String key : params.keySet())
{
// Do the thumbnail transformation
contentService.transform(reader, writer, transformationOptions);
renderingAction.setParameterValue(key, params.get(key));
}
return thumbnail;
ChildAssociationRef chAssRef = null;
try
{
chAssRef = renditionService.render(node, renderingAction);
} catch (RenditionServiceException rsx)
{
throw new ThumbnailException(rsx.getMessage(), rsx);
}
return chAssRef;
}
}, AuthenticationUtil.getSystemUserName());
// Return the created thumbnail
return thumbnail;
return getThumbnailNode(thumbnailRef);
}
private String getRenderingEngineNameFor(TransformationOptions options)
{
if (options instanceof ImageTransformationOptions)
{
return ImageRenderingEngine.NAME;
}
else if (options instanceof SWFTransformationOptions)
{
return ReformatRenderingEngine.NAME;
}
else
{
// TODO What can we do here? Can we treat this as an error?
// Isn't this a 'standard' TransformationOptions?
return "";
}
}
/**
* Generates the thumbnail name from the name and destination mimertype
* This method returns the NodeRef for the thumbnail, using the ChildAssociationRef
* that links the sourceNode to its associated Thumbnail node.
*
* @param thumbnailName the thumbnail name
* @param destinationMimetype the destination name
* @return String the thumbnail file name
* @param thumbnailRef the ChildAssociationRef containing the child NodeRef.
* @return the NodeRef of the thumbnail itself.
*/
private String generateThumbnailFileName(String thumbnailName, String destinationMimetype)
public NodeRef getThumbnailNode(ChildAssociationRef thumbnailRef)
{
return thumbnailName + "." + this.mimetypeMap.getExtension(destinationMimetype);
return thumbnailRef.getChildRef();
}
/**
@@ -287,75 +274,61 @@ public class ThumbnailServiceImpl implements ThumbnailService
*/
public void updateThumbnail(final NodeRef thumbnail, final TransformationOptions transformationOptions)
{
// Seeing as how this always gives its own options, maybe this should be a delete and recreate?
if (logger.isDebugEnabled() == true)
{
logger.debug("Updating thumbnail (thumbnail=" + thumbnail.toString() + ")");
}
AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<Object>()
// First check that we are dealing with a rendition object
if (renditionService.isRendition(thumbnail))
{
public Object doWork() throws Exception
// Get the node that is the source of the thumbnail
ChildAssociationRef parentAssoc = renditionService.getSourceNode(thumbnail);
if (parentAssoc == null)
{
// First check that we are dealing with a thumbnail
if (ContentModel.TYPE_THUMBNAIL.equals(nodeService.getType(thumbnail)) == true)
if (logger.isDebugEnabled() == true)
{
// Get the node that is the source of the thumbnail
NodeRef node = null;
List<ChildAssociationRef> parents = nodeService.getParentAssocs(thumbnail, ContentModel.ASSOC_THUMBNAILS, RegexQNamePattern.MATCH_ALL);
if (parents.size() == 0)
{
if (logger.isDebugEnabled() == true)
{
logger.debug("Updating thumbnail: The thumbnails parent cannot be found (thumbnail=" + thumbnail.toString() + ")");
}
throw new ThumbnailException(ERR_NO_PARENT);
}
else
{
node = parents.get(0).getParentRef();
}
// Get the content property
QName contentProperty = (QName)nodeService.getProperty(thumbnail, ContentModel.PROP_CONTENT_PROPERTY_NAME);
// Get the reader and writer
ContentReader reader = contentService.getReader(node, contentProperty);
ContentWriter writer = contentService.getWriter(thumbnail, ContentModel.PROP_CONTENT, true);
// Set the basic detail of the transformation options
transformationOptions.setSourceNodeRef(node);
transformationOptions.setSourceContentProperty(contentProperty);
transformationOptions.setTargetNodeRef(thumbnail);
transformationOptions.setTargetContentProperty(ContentModel.PROP_CONTENT);
// Catch the failure to create the thumbnail
if (contentService.isTransformable(reader, writer, transformationOptions) == false)
{
if (logger.isDebugEnabled() == true)
{
logger.debug("Updating thumbnail: there is not transformer to update the thumbnail with (thumbnail=" + thumbnail.toString() + ")");
}
// Throw exception indicating that the thumbnail could not be created
throw new ThumbnailException(MessageFormat.format(ERR_NO_CREATE, reader.getMimetype(), writer.getMimetype()));
}
else
{
// Do the thumbnail transformation
contentService.transform(reader, writer, transformationOptions);
}
logger.debug("Updating thumbnail: The thumbnails parent cannot be found (thumbnail=" + thumbnail.toString() + ")");
}
else
{
if (logger.isDebugEnabled() == true)
{
logger.debug("Updating thumbnail: cannot update a thumbnail node that isn't the correct thumbnail type (thumbnail=" + thumbnail.toString() + ")");
}
}
return null;
throw new ThumbnailException(ERR_NO_PARENT);
}
}, AuthenticationUtil.getSystemUserName());
final QName renditionAssociationName = parentAssoc.getQName();
NodeRef sourceNode = parentAssoc.getParentRef();
// Get the content property
QName contentProperty = (QName)nodeService.getProperty(thumbnail, ContentModel.PROP_CONTENT_PROPERTY_NAME);
// Set the basic detail of the transformation options
transformationOptions.setSourceNodeRef(sourceNode);
transformationOptions.setSourceContentProperty(contentProperty);
transformationOptions.setTargetContentProperty(ContentModel.PROP_CONTENT);
// Do the thumbnail transformation
RenditionDefinition rendDefn = renditionService.loadRenditionDefinition(renditionAssociationName);
if (rendDefn == null)
{
String renderingEngineName = getRenderingEngineNameFor(transformationOptions);
rendDefn = renditionService.createRenditionDefinition(parentAssoc.getQName(), renderingEngineName);
}
Map<String, Serializable> params = new ThumbnailRenditionConvertor().convert(transformationOptions, null);
for (String key : params.keySet())
{
rendDefn.setParameterValue(key, params.get(key));
}
renditionService.render(sourceNode, rendDefn);
}
else
{
if (logger.isDebugEnabled() == true)
{
logger.debug("Updating thumbnail: cannot update a thumbnail node that isn't the correct thumbnail type (thumbnail=" + thumbnail.toString() + ")");
}
}
}
/**
@@ -363,8 +336,6 @@ public class ThumbnailServiceImpl implements ThumbnailService
*/
public NodeRef getThumbnailByName(NodeRef node, QName contentProperty, String thumbnailName)
{
NodeRef thumbnail = null;
//
// NOTE:
//
@@ -377,21 +348,21 @@ public class ThumbnailServiceImpl implements ThumbnailService
logger.debug("Getting thumbnail by name (nodeRef=" + node.toString() + "; contentProperty=" + contentProperty.toString() + "; thumbnailName=" + thumbnailName + ")");
}
// Check that the node has the thumbnailed aspect applied
if (nodeService.hasAspect(node, ContentModel.ASPECT_THUMBNAILED) == true)
// Thumbnails have a cm: prefix.
QName namespacedThumbnailName = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, thumbnailName);
ChildAssociationRef existingRendition = renditionService.getRenditionByName(node, namespacedThumbnailName);
NodeRef thumbnail = null;
// Check the child to see if it matches the content property we are concerned about.
// We can assume there will only ever be one per content property since createThumbnail enforces this.
if (existingRendition != null)
{
// Get all the thumbnails that match the thumbnail name
List<ChildAssociationRef> assocs = this.nodeService.getChildAssocs(node, ContentModel.ASSOC_THUMBNAILS, QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, thumbnailName));
for (ChildAssociationRef assoc : assocs)
NodeRef child = existingRendition.getChildRef();
Serializable contentPropertyName = this.nodeService.getProperty(child, ContentModel.PROP_CONTENT_PROPERTY_NAME);
if (contentProperty.equals(contentPropertyName) == true)
{
// Check the child to see if it matches the content property we are concerned about.
// We can assume there will only ever be one per content property since createThumbnail enforces this.
NodeRef child = assoc.getChildRef();
if (contentProperty.equals(this.nodeService.getProperty(child, ContentModel.PROP_CONTENT_PROPERTY_NAME)) == true)
{
thumbnail = child;
break;
}
thumbnail = child;
}
}
@@ -417,24 +388,21 @@ public class ThumbnailServiceImpl implements ThumbnailService
logger.debug("Getting thumbnails (nodeRef=" + node.toString() + "; contentProperty=" + contentProperty.toString() + "; mimetype=" + mimetype + ")");
}
// Check that the node has the thumbnailed aspect applied
if (nodeService.hasAspect(node, ContentModel.ASPECT_THUMBNAILED) == true)
List<ChildAssociationRef> renditions = this.renditionService.getRenditions(node);
for (ChildAssociationRef assoc : renditions)
{
// Get all the thumbnails that match the thumbnail name
List<ChildAssociationRef> assocs = this.nodeService.getChildAssocs(node, ContentModel.ASSOC_THUMBNAILS, RegexQNamePattern.MATCH_ALL);
for (ChildAssociationRef assoc : assocs)
// Check the child to see if it matches the content property we are concerned about.
// We can assume there will only ever be one per content property since createThumbnail enforces this.
NodeRef child = assoc.getChildRef();
if (contentProperty.equals(this.nodeService.getProperty(child, ContentModel.PROP_CONTENT_PROPERTY_NAME)) == true &&
matchMimetypeOptions(child, mimetype, options) == true)
{
// Check the child to see if it matches the content property we are concerned about.
// We can assume there will only ever be one per content property since createThumbnail enforces this.
NodeRef child = assoc.getChildRef();
if (contentProperty.equals(this.nodeService.getProperty(child, ContentModel.PROP_CONTENT_PROPERTY_NAME)) == true &&
matchMimetypeOptions(child, mimetype, options) == true)
{
thumbnails.add(child);
}
thumbnails.add(child);
}
}
//TODO Ensure this doesn't return non-thumbnail renditions.
return thumbnails;
}

View File

@@ -0,0 +1,177 @@
/*
* Copyright (C) 2005-2010 Alfresco Software Limited.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program 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 General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.repo.thumbnail;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.action.ActionImpl;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.content.transform.magick.ImageResizeOptions;
import org.alfresco.repo.content.transform.magick.ImageTransformationOptions;
import org.alfresco.repo.rendition.PerformRenditionActionExecuter;
import org.alfresco.repo.rendition.RenditionServiceImpl;
import org.alfresco.repo.rendition.executer.AbstractRenderingEngine;
import org.alfresco.repo.rendition.executer.ImageRenderingEngine;
import org.alfresco.service.cmr.action.Action;
import org.alfresco.service.cmr.action.ActionService;
import org.alfresco.service.cmr.rendition.RenditionDefinition;
import org.alfresco.service.cmr.rendition.RenditionService;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.thumbnail.ThumbnailParentAssociationDetails;
import org.alfresco.service.cmr.thumbnail.ThumbnailService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
/**
* Thumbnail service implementation unit test
*
* @author Neil McErlean
*/
public class ThumbnailServiceImplParameterTest
{
// Mocked services.
private ActionService mockActionService = mock(ActionService.class);
// Real services - backed by mocked services.
private RenditionServiceImpl renditionService;
private ThumbnailService thumbnailService;
private final NodeRef dummyNodeRef1 = new NodeRef("workspace", "dummy", "dummyID_1");
private final NodeRef dummyNodeRef2 = new NodeRef("workspace", "dummy", "dummyID_2");
private final NodeRef dummyNodeRef3 = new NodeRef("workspace", "dummy", "dummyID_3");
@Before
public void initMockObjects()
{
when(mockActionService.createAction(PerformRenditionActionExecuter.NAME))
.thenReturn(new ActionImpl(dummyNodeRef2, "id", PerformRenditionActionExecuter.NAME, new HashMap<String, Serializable>()));
renditionService = new RenditionServiceImpl()
{
@Override
public RenditionDefinition loadRenditionDefinition(QName renderingActionName)
{
// We're intentionally returning null for this test.
return null;
}
};
renditionService.setActionService(mockActionService);
ThumbnailServiceImpl thumbs = new ThumbnailServiceImpl()
{
@Override
public NodeRef getThumbnailByName(NodeRef node,
QName contentProperty, String thumbnailName)
{
return null;
}
/**
* In this test the thumbnailRef will be null, so we need to ensure
* it is not dereferenced here.
*/
@Override
public NodeRef getThumbnailNode(ChildAssociationRef thumbnailRef)
{
return null;
}
};
thumbs.setRenditionService(renditionService);
thumbnailService = thumbs;
}
/**
* This test method ensures that the parameters on thumbnail-create are
* passed through the RenditionService to the ActionService
*/
@Test
public void createThumbnailPassesParametersToActionService()
{
// As most of the services are mocked out, the actual values used here
// don't matter.
final Map<String, Serializable> parametersUnderTest = new HashMap<String, Serializable>();
parametersUnderTest.put(ImageRenderingEngine.PARAM_RESIZE_WIDTH, new Integer(42));
parametersUnderTest.put(ImageRenderingEngine.PARAM_RESIZE_HEIGHT, new Integer(93));
parametersUnderTest.put(ImageRenderingEngine.PARAM_COMMAND_OPTIONS, "foo");
parametersUnderTest.put(ImageRenderingEngine.PARAM_MAINTAIN_ASPECT_RATIO, Boolean.TRUE);
parametersUnderTest.put(ImageRenderingEngine.PARAM_RESIZE_TO_THUMBNAIL, Boolean.FALSE);
parametersUnderTest.put(AbstractRenderingEngine.PARAM_TARGET_CONTENT_PROPERTY, ContentModel.PROP_CONTENT);
parametersUnderTest.put(RenditionService.PARAM_DESTINATION_NODE, dummyNodeRef2);
ImageTransformationOptions imageTransOpts = new ImageTransformationOptions();
imageTransOpts.setTargetNodeRef(dummyNodeRef2);
imageTransOpts.setTargetContentProperty((QName) parametersUnderTest.get(ImageRenderingEngine.PARAM_TARGET_CONTENT_PROPERTY));
imageTransOpts.setCommandOptions((String) parametersUnderTest.get(ImageRenderingEngine.PARAM_COMMAND_OPTIONS));
ImageResizeOptions resizeOptions = new ImageResizeOptions();
resizeOptions.setHeight((Integer) parametersUnderTest.get(ImageRenderingEngine.PARAM_RESIZE_HEIGHT));
resizeOptions.setWidth((Integer) parametersUnderTest.get(ImageRenderingEngine.PARAM_RESIZE_WIDTH));
resizeOptions.setMaintainAspectRatio((Boolean) parametersUnderTest.get(ImageRenderingEngine.PARAM_MAINTAIN_ASPECT_RATIO));
resizeOptions.setResizeToThumbnail((Boolean) parametersUnderTest.get(ImageRenderingEngine.PARAM_RESIZE_TO_THUMBNAIL));
imageTransOpts.setResizeOptions(resizeOptions);
ThumbnailParentAssociationDetails assocDetails = new ThumbnailParentAssociationDetails(dummyNodeRef3,
ContentModel.ASSOC_CONTAINS, QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI,
"homerSimpson"));
// Now request the creation of the the thumbnail.
thumbnailService.createThumbnail(dummyNodeRef1, ContentModel.PROP_CONTENT, MimetypeMap.MIMETYPE_IMAGE_JPEG,
imageTransOpts, "bartSimpson", assocDetails);
ArgumentCaptor<Action> argument = ArgumentCaptor.forClass(Action.class);
verify(mockActionService).executeAction(argument.capture(), any(NodeRef.class), anyBoolean(), anyBoolean());
final Action performRenditionAction = argument.getValue();
final RenditionDefinition renditionDefn = (RenditionDefinition) performRenditionAction.getParameterValue(PerformRenditionActionExecuter.PARAM_RENDITION_DEFINITION);
Map<String, Serializable> parameters = renditionDefn.getParameterValues();
for (String s : parametersUnderTest.keySet())
{
if (parameters.keySet().contains(s) == false || parameters.get(s) == null || parameters.get(s).toString().length() == 0)
{
fail("Missing parameter " + s);
}
assertEquals("Parameter " + s + " had wrong value.",
parametersUnderTest.get(s), parameters.get(s));
}
}
}

View File

@@ -16,6 +16,7 @@
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.thumbnail;
import java.io.File;
@@ -26,6 +27,7 @@ import java.util.List;
import java.util.Map;
import org.alfresco.model.ContentModel;
import org.alfresco.model.RenditionModel;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.content.transform.AbstractContentTransformerTest;
import org.alfresco.repo.content.transform.ContentTransformer;
@@ -33,13 +35,16 @@ import org.alfresco.repo.content.transform.magick.ImageResizeOptions;
import org.alfresco.repo.content.transform.magick.ImageTransformationOptions;
import org.alfresco.repo.jscript.ClasspathScriptLocation;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.service.cmr.rendition.RenditionService;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.ContentIOException;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.ScriptLocation;
import org.alfresco.service.cmr.repository.ScriptService;
import org.alfresco.service.cmr.thumbnail.ThumbnailException;
import org.alfresco.service.cmr.thumbnail.ThumbnailParentAssociationDetails;
import org.alfresco.service.cmr.thumbnail.ThumbnailService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
@@ -50,160 +55,189 @@ import org.alfresco.util.BaseAlfrescoSpringTest;
* Thumbnail service implementation unit test
*
* @author Roy Wetherall
* @author Neil McErlean
*/
public class ThumbnailServiceImplTest extends BaseAlfrescoSpringTest
public class ThumbnailServiceImplTest extends BaseAlfrescoSpringTest
{
private ThumbnailService thumbnailService;
private RenditionService renditionService;
private ThumbnailService thumbnailService;
private ScriptService scriptService;
private MimetypeMap mimetypeMap;
private MimetypeMap mimetypeMap;
private NodeRef folder;
/**
* Called during the transaction setup
*/
@SuppressWarnings("deprecation")
@Override
protected void onSetUpInTransaction() throws Exception
{
super.onSetUpInTransaction();
// Get the required services
this.thumbnailService = (ThumbnailService)this.applicationContext.getBean("ThumbnailService");
this.mimetypeMap = (MimetypeMap)this.applicationContext.getBean("mimetypeService");
this.scriptService = (ScriptService)this.applicationContext.getBean("ScriptService");
this.renditionService = (RenditionService) this.applicationContext.getBean("RenditionService");
this.thumbnailService = (ThumbnailService) this.applicationContext.getBean("ThumbnailService");
this.mimetypeMap = (MimetypeMap) this.applicationContext.getBean("mimetypeService");
this.scriptService = (ScriptService) this.applicationContext.getBean("ScriptService");
// Create a folder and some content
Map<QName, Serializable> folderProps = new HashMap<QName, Serializable>(1);
folderProps.put(ContentModel.PROP_NAME, "testFolder");
this.folder = this.nodeService.createNode(
this.rootNodeRef,
ContentModel.ASSOC_CHILDREN,
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "testFolder"),
ContentModel.TYPE_FOLDER).getChildRef();
this.folder = this.nodeService.createNode(this.rootNodeRef, ContentModel.ASSOC_CHILDREN,
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "testFolder"), ContentModel.TYPE_FOLDER)
.getChildRef();
}
private void checkTransformer()
{
ContentTransformer transformer = this.contentService.getImageTransformer();
if (transformer == null)
{
fail("No transformer returned for 'getImageTransformer'");
}
assertNotNull("No transformer returned for 'getImageTransformer'", transformer);
// Check that it is working
ImageTransformationOptions imageTransformationOptions = new ImageTransformationOptions();
if (!transformer.isTransformable(
MimetypeMap.MIMETYPE_IMAGE_JPEG,
MimetypeMap.MIMETYPE_IMAGE_JPEG,
imageTransformationOptions))
if (!transformer.isTransformable(MimetypeMap.MIMETYPE_IMAGE_JPEG, MimetypeMap.MIMETYPE_IMAGE_JPEG,
imageTransformationOptions))
{
fail("Image transformer is not working. Please check your image conversion command setup.");
}
}
public void testCreateRenditionThumbnailFromImage() throws Exception
{
QName qname = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "doclib");
ThumbnailDefinition details = thumbnailService.getThumbnailRegistry().getThumbnailDefinition(
qname.getLocalName());
assertEquals("doclib", details.getName());
assertEquals("image/png", details.getMimetype());
assertEquals("alfresco/thumbnail/thumbnail_placeholder_doclib.png", details.getPlaceHolderResourcePath());
checkTransformer();
NodeRef jpgOrig = createOriginalContent(this.folder, MimetypeMap.MIMETYPE_IMAGE_JPEG);
NodeRef thumbnail0 = this.thumbnailService.createThumbnail(jpgOrig, ContentModel.PROP_CONTENT,
MimetypeMap.MIMETYPE_IMAGE_JPEG, details.getTransformationOptions(), "doclib");
assertNotNull(thumbnail0);
checkRenditioned(jpgOrig, "doclib");
checkRendition("doclib", thumbnail0);
outputThumbnailTempContentLocation(thumbnail0, "jpg", "doclib test");
}
public void testCreateRenditionThumbnailFromPdf() throws Exception
{
QName qname = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "doclib");
ThumbnailDefinition details = thumbnailService.getThumbnailRegistry().getThumbnailDefinition(
qname.getLocalName());
assertEquals("doclib", details.getName());
assertEquals("image/png", details.getMimetype());
assertEquals("alfresco/thumbnail/thumbnail_placeholder_doclib.png", details.getPlaceHolderResourcePath());
checkTransformer();
NodeRef pdfOrig = createOriginalContent(this.folder, MimetypeMap.MIMETYPE_PDF);
NodeRef thumbnail0 = this.thumbnailService.createThumbnail(pdfOrig, ContentModel.PROP_CONTENT,
MimetypeMap.MIMETYPE_IMAGE_JPEG, details.getTransformationOptions(), "doclib");
assertNotNull(thumbnail0);
checkRenditioned(pdfOrig, "doclib");
checkRendition("doclib", thumbnail0);
outputThumbnailTempContentLocation(thumbnail0, "jpg", "doclib test");
}
public void testCreateThumbnailFromImage() throws Exception
{
checkTransformer();
NodeRef jpgOrig = createOrigionalContent(this.folder, MimetypeMap.MIMETYPE_IMAGE_JPEG);
NodeRef gifOrig = createOrigionalContent(this.folder, MimetypeMap.MIMETYPE_IMAGE_GIF);
NodeRef jpgOrig = createOriginalContent(this.folder, MimetypeMap.MIMETYPE_IMAGE_JPEG);
NodeRef gifOrig = createOriginalContent(this.folder, MimetypeMap.MIMETYPE_IMAGE_GIF);
// ===== small: 64x64, marked as thumbnail ====
ImageResizeOptions imageResizeOptions = new ImageResizeOptions();
imageResizeOptions.setWidth(64);
imageResizeOptions.setHeight(64);
imageResizeOptions.setHeight(64);
imageResizeOptions.setResizeToThumbnail(true);
ImageTransformationOptions imageTransformationOptions = new ImageTransformationOptions();
imageTransformationOptions.setResizeOptions(imageResizeOptions);
//ThumbnailDetails createOptions = new ThumbnailDetails();
NodeRef thumbnail1 = this.thumbnailService.createThumbnail(jpgOrig, ContentModel.PROP_CONTENT,
MimetypeMap.MIMETYPE_IMAGE_JPEG,
imageTransformationOptions,
"small");
imageTransformationOptions.setResizeOptions(imageResizeOptions);
// ThumbnailDetails createOptions = new ThumbnailDetails();
NodeRef thumbnail1 = this.thumbnailService.createThumbnail(jpgOrig, ContentModel.PROP_CONTENT,
MimetypeMap.MIMETYPE_IMAGE_JPEG, imageTransformationOptions, "small");
assertNotNull(thumbnail1);
checkThumbnailed(jpgOrig, "small");
checkThumbnail("small", thumbnail1);
checkRenditioned(jpgOrig, "small");
checkRendition("small", thumbnail1);
outputThumbnailTempContentLocation(thumbnail1, "jpg", "small - 64x64, marked as thumbnail");
// ===== small2: 64x64, aspect not maintained ====
ImageResizeOptions imageResizeOptions2 = new ImageResizeOptions();
imageResizeOptions2.setWidth(64);
imageResizeOptions2.setHeight(64);
imageResizeOptions2.setHeight(64);
imageResizeOptions2.setMaintainAspectRatio(false);
ImageTransformationOptions imageTransformationOptions2 = new ImageTransformationOptions();
imageTransformationOptions2.setResizeOptions(imageResizeOptions2);
//ThumbnailDetails createOptions2 = new ThumbnailDetails();
NodeRef thumbnail2 = this.thumbnailService.createThumbnail(jpgOrig, ContentModel.PROP_CONTENT,
MimetypeMap.MIMETYPE_IMAGE_JPEG,
imageTransformationOptions2,
"small2");
checkThumbnailed(jpgOrig, "small2");
checkThumbnail("small2", thumbnail2);
imageTransformationOptions2.setResizeOptions(imageResizeOptions2);
// ThumbnailDetails createOptions2 = new ThumbnailDetails();
NodeRef thumbnail2 = this.thumbnailService.createThumbnail(jpgOrig, ContentModel.PROP_CONTENT,
MimetypeMap.MIMETYPE_IMAGE_JPEG, imageTransformationOptions2, "small2");
checkRenditioned(jpgOrig, "small2");
checkRendition("small2", thumbnail2);
outputThumbnailTempContentLocation(thumbnail2, "jpg", "small2 - 64x64, aspect not maintained");
// ===== half: 50%x50 =====
// ===== half: 50%x50 =====
ImageResizeOptions imageResizeOptions3 = new ImageResizeOptions();
imageResizeOptions3.setWidth(50);
imageResizeOptions3.setHeight(50);
imageResizeOptions3.setHeight(50);
imageResizeOptions3.setPercentResize(true);
ImageTransformationOptions imageTransformationOptions3 = new ImageTransformationOptions();
imageTransformationOptions3.setResizeOptions(imageResizeOptions3);
// ThumbnailDetails createOptions3 = new ThumbnailDetails();
NodeRef thumbnail3 = this.thumbnailService.createThumbnail(jpgOrig, ContentModel.PROP_CONTENT,
MimetypeMap.MIMETYPE_IMAGE_JPEG,
imageTransformationOptions3,
"half");
checkThumbnailed(jpgOrig, "half");
checkThumbnail("half", thumbnail3);
imageTransformationOptions3.setResizeOptions(imageResizeOptions3);
// ThumbnailDetails createOptions3 = new ThumbnailDetails();
NodeRef thumbnail3 = this.thumbnailService.createThumbnail(jpgOrig, ContentModel.PROP_CONTENT,
MimetypeMap.MIMETYPE_IMAGE_JPEG, imageTransformationOptions3, "half");
checkRenditioned(jpgOrig, "half");
checkRendition("half", thumbnail3);
outputThumbnailTempContentLocation(thumbnail3, "jpg", "half - 50%x50%");
// ===== half2: 50%x50 from gif =====
// ===== half2: 50%x50 from gif =====
ImageResizeOptions imageResizeOptions4 = new ImageResizeOptions();
imageResizeOptions4.setWidth(50);
imageResizeOptions4.setHeight(50);
imageResizeOptions4.setHeight(50);
imageResizeOptions4.setPercentResize(true);
ImageTransformationOptions imageTransformationOptions4 = new ImageTransformationOptions();
imageTransformationOptions4.setResizeOptions(imageResizeOptions4);
// ThumbnailDetails createOptions4 = new ThumbnailDetails();
NodeRef thumbnail4 = this.thumbnailService.createThumbnail(gifOrig, ContentModel.PROP_CONTENT,
MimetypeMap.MIMETYPE_IMAGE_JPEG,
imageTransformationOptions4,
"half2");
checkThumbnailed(gifOrig, "half2");
checkThumbnail("half2", thumbnail4);
imageTransformationOptions4.setResizeOptions(imageResizeOptions4);
// ThumbnailDetails createOptions4 = new ThumbnailDetails();
NodeRef thumbnail4 = this.thumbnailService.createThumbnail(gifOrig, ContentModel.PROP_CONTENT,
MimetypeMap.MIMETYPE_IMAGE_JPEG, imageTransformationOptions4, "half2");
checkRenditioned(gifOrig, "half2");
checkRendition("half2", thumbnail4);
outputThumbnailTempContentLocation(thumbnail4, "jpg", "half2 - 50%x50%, from gif");
}
public void testDuplicationNames()
throws Exception
public void testDuplicationNames() throws Exception
{
checkTransformer();
NodeRef jpgOrig = createOrigionalContent(this.folder, MimetypeMap.MIMETYPE_IMAGE_JPEG);
NodeRef jpgOrig = createOriginalContent(this.folder, MimetypeMap.MIMETYPE_IMAGE_JPEG);
ImageResizeOptions imageResizeOptions = new ImageResizeOptions();
imageResizeOptions.setWidth(64);
imageResizeOptions.setHeight(64);
imageResizeOptions.setHeight(64);
imageResizeOptions.setResizeToThumbnail(true);
ImageTransformationOptions imageTransformationOptions = new ImageTransformationOptions();
imageTransformationOptions.setResizeOptions(imageResizeOptions);
//ThumbnailDetails createOptions = new ThumbnailDetails();
NodeRef thumbnail1 = this.thumbnailService.createThumbnail(jpgOrig, ContentModel.PROP_CONTENT,
MimetypeMap.MIMETYPE_IMAGE_JPEG,
imageTransformationOptions,
"small");
imageTransformationOptions.setResizeOptions(imageResizeOptions);
// ThumbnailDetails createOptions = new ThumbnailDetails();
NodeRef thumbnail1 = this.thumbnailService.createThumbnail(jpgOrig, ContentModel.PROP_CONTENT,
MimetypeMap.MIMETYPE_IMAGE_JPEG, imageTransformationOptions, "small");
assertNotNull(thumbnail1);
checkThumbnailed(jpgOrig, "small");
checkThumbnail("small", thumbnail1);
checkRenditioned(jpgOrig, "small");
checkRendition("small", thumbnail1);
try
{
this.thumbnailService.createThumbnail(jpgOrig, ContentModel.PROP_CONTENT,
MimetypeMap.MIMETYPE_IMAGE_JPEG,
imageTransformationOptions,
"small");
this.thumbnailService.createThumbnail(jpgOrig, ContentModel.PROP_CONTENT, MimetypeMap.MIMETYPE_IMAGE_JPEG,
imageTransformationOptions, "small");
fail("A duplicate exception should have been raised");
}
catch (ThumbnailException exception)
@@ -211,180 +245,182 @@ public class ThumbnailServiceImplTest extends BaseAlfrescoSpringTest
// OK since this should have been thrown
}
}
public void testThumbnailUpdate()
throws Exception
public void testThumbnailUpdate() throws Exception
{
checkTransformer();
// First create a thumbnail
NodeRef jpgOrig = createOrigionalContent(this.folder, MimetypeMap.MIMETYPE_IMAGE_JPEG);
NodeRef jpgOrig = createOriginalContent(this.folder, MimetypeMap.MIMETYPE_IMAGE_JPEG);
ImageResizeOptions imageResizeOptions = new ImageResizeOptions();
imageResizeOptions.setWidth(64);
imageResizeOptions.setHeight(64);
imageResizeOptions.setHeight(64);
imageResizeOptions.setResizeToThumbnail(true);
ImageTransformationOptions imageTransformationOptions = new ImageTransformationOptions();
imageTransformationOptions.setResizeOptions(imageResizeOptions);
NodeRef thumbnail1 = this.thumbnailService.createThumbnail(jpgOrig, ContentModel.PROP_CONTENT,
MimetypeMap.MIMETYPE_IMAGE_JPEG,
imageTransformationOptions,
"small");
imageTransformationOptions.setResizeOptions(imageResizeOptions);
NodeRef thumbnail1 = this.thumbnailService.createThumbnail(jpgOrig, ContentModel.PROP_CONTENT,
MimetypeMap.MIMETYPE_IMAGE_JPEG, imageTransformationOptions, "small");
// Update the thumbnail
this.thumbnailService.updateThumbnail(thumbnail1, imageTransformationOptions);
}
public void testGetThumbnailByName()
throws Exception
public void testGetThumbnailByName() throws Exception
{
checkTransformer();
NodeRef jpgOrig = createOrigionalContent(this.folder, MimetypeMap.MIMETYPE_IMAGE_JPEG);
NodeRef jpgOrig = createOriginalContent(this.folder, MimetypeMap.MIMETYPE_IMAGE_JPEG);
// Check for missing thumbnail
NodeRef result1 = this.thumbnailService.getThumbnailByName(jpgOrig, ContentModel.PROP_CONTENT, "small");
assertNull("The thumbnail 'small' should have been missing", result1);
// Create the thumbnail
ImageResizeOptions imageResizeOptions = new ImageResizeOptions();
imageResizeOptions.setWidth(64);
imageResizeOptions.setHeight(64);
imageResizeOptions.setHeight(64);
imageResizeOptions.setResizeToThumbnail(true);
ImageTransformationOptions imageTransformationOptions = new ImageTransformationOptions();
imageTransformationOptions.setResizeOptions(imageResizeOptions);
this.thumbnailService.createThumbnail(jpgOrig, ContentModel.PROP_CONTENT,
MimetypeMap.MIMETYPE_IMAGE_JPEG,
imageTransformationOptions,
"small");
imageTransformationOptions.setResizeOptions(imageResizeOptions);
this.thumbnailService.createThumbnail(jpgOrig, ContentModel.PROP_CONTENT, MimetypeMap.MIMETYPE_IMAGE_JPEG,
imageTransformationOptions, "small");
// Try and retrieve the thumbnail
NodeRef result2 = this.thumbnailService.getThumbnailByName(jpgOrig, ContentModel.PROP_CONTENT, "small");
assertNotNull(result2);
checkThumbnail("small", result2);
checkRendition("small", result2);
// Check for an other thumbnail that doesn't exist
NodeRef result3 = this.thumbnailService.getThumbnailByName(jpgOrig, ContentModel.PROP_CONTENT, "anotherone");
assertNull("The thumbnail 'anotherone' should have been missing", result3);
}
// TODO test getThumbnails
private void checkThumbnailed(NodeRef thumbnailed, String assocName)
private void checkRenditioned(NodeRef thumbnailed, String assocName)
{
assertTrue("Thumbnailed aspect should have been applied", this.nodeService.hasAspect(thumbnailed, ContentModel.ASPECT_THUMBNAILED));
List<ChildAssociationRef> assocs = this.nodeService.getChildAssocs(thumbnailed, RegexQNamePattern.MATCH_ALL, QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, assocName));
assertNotNull(assocs);
assertEquals(1, assocs.size());
assertTrue("Renditioned aspect should have been applied", this.nodeService.hasAspect(thumbnailed,
RenditionModel.ASPECT_RENDITIONED));
if (assocName != null)
{
List<ChildAssociationRef> assocs = this.nodeService.getChildAssocs(thumbnailed, RegexQNamePattern.MATCH_ALL,
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, assocName));
assertNotNull(assocs);
assertEquals(1, assocs.size());
}
}
private void checkThumbnail(String thumbnailName, NodeRef thumbnail)
private void checkRendition(String thumbnailName, NodeRef thumbnail)
{
// Check the thumbnail is of the correct type
assertEquals(ContentModel.TYPE_THUMBNAIL, this.nodeService.getType(thumbnail));
// Check the name
assertEquals(thumbnailName, this.nodeService.getProperty(thumbnail, ContentModel.PROP_THUMBNAIL_NAME));
// Check the contet property value
assertEquals(ContentModel.PROP_CONTENT, this.nodeService.getProperty(thumbnail, ContentModel.PROP_CONTENT_PROPERTY_NAME));
assertTrue("Thumbnail should have been a rendition",
renditionService.isRendition(thumbnail));
// Check the name
if (thumbnailName != null)
{
assertEquals(thumbnailName, this.nodeService.getProperty(thumbnail, ContentModel.PROP_NAME));
}
// Check the content property value
assertEquals(ContentModel.PROP_CONTENT, this.nodeService.getProperty(thumbnail,
ContentModel.PROP_CONTENT_PROPERTY_NAME));
}
private void outputThumbnailTempContentLocation(NodeRef thumbnail, String ext, String message)
throws IOException
private void outputThumbnailTempContentLocation(NodeRef thumbnail, String ext, String message) throws IOException
{
File tempFile = File.createTempFile("thumbnailServiceImpTest", "." + ext);
ContentReader reader = this.contentService.getReader(thumbnail, ContentModel.PROP_CONTENT);
reader.getContent(tempFile);
System.out.println(message + ": " + tempFile.getPath());
System.out.println(message + ": " + tempFile.getPath());
}
private NodeRef createOrigionalContent(NodeRef folder, String mimetype)
throws IOException
/**
* This method creates a node under the specified folder whose content is
* taken from the quick file corresponding to the specified MIME type.
*
* @param parentFolder
* @param mimetype
* @return
* @throws IOException
*/
private NodeRef createOriginalContent(NodeRef parentFolder, String mimetype) throws IOException
{
String ext = this.mimetypeMap.getExtension(mimetype);
File origFile = AbstractContentTransformerTest.loadQuickTestFile(ext);
Map<QName, Serializable> props = new HashMap<QName, Serializable>(1);
props.put(ContentModel.PROP_NAME, "origional." + ext);
NodeRef node = this.nodeService.createNode(
folder,
ContentModel.ASSOC_CONTAINS,
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "origional." + ext),
ContentModel.TYPE_CONTENT,
props).getChildRef();
props.put(ContentModel.PROP_NAME, "origional." + ext);
NodeRef node = this.nodeService.createNode(parentFolder, ContentModel.ASSOC_CONTAINS,
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "original." + ext),
ContentModel.TYPE_CONTENT, props).getChildRef();
ContentWriter writer = this.contentService.getWriter(node, ContentModel.PROP_CONTENT, true);
writer.setMimetype(mimetype);
writer.setEncoding("UTF-8");
writer.putContent(origFile);
return node;
}
@SuppressWarnings("deprecation")
public void testAutoUpdate() throws Exception
{
checkTransformer();
final NodeRef jpgOrig = createOrigionalContent(this.folder, MimetypeMap.MIMETYPE_IMAGE_JPEG);
final NodeRef jpgOrig = createOriginalContent(this.folder, MimetypeMap.MIMETYPE_IMAGE_JPEG);
ThumbnailDefinition details = this.thumbnailService.getThumbnailRegistry().getThumbnailDefinition("medium");
@SuppressWarnings("unused")
final NodeRef thumbnail = this.thumbnailService.createThumbnail(jpgOrig, ContentModel.PROP_CONTENT, details.getMimetype(), details.getTransformationOptions(), details.getName());
final NodeRef thumbnail = this.thumbnailService.createThumbnail(jpgOrig, ContentModel.PROP_CONTENT, details
.getMimetype(), details.getTransformationOptions(), details.getName());
setComplete();
endTransaction();
transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<Object>()
{
public Object execute() throws Exception
{
{
String ext = ThumbnailServiceImplTest.this.mimetypeMap.getExtension(MimetypeMap.MIMETYPE_IMAGE_JPEG);
File origFile = AbstractContentTransformerTest.loadQuickTestFile(ext);
ContentWriter writer = ThumbnailServiceImplTest.this.contentService.getWriter(jpgOrig, ContentModel.PROP_CONTENT, true);
ContentWriter writer = ThumbnailServiceImplTest.this.contentService.getWriter(jpgOrig,
ContentModel.PROP_CONTENT, true);
writer.putContent(origFile);
return null;
}
});
// TODO
// this test should wait for the async action to run .. will need to commit transaction for that thou!
//Thread.sleep(1000);
// TODO
// this test should wait for the async action to run .. will need to
// commit transaction for that thou!
// Thread.sleep(1000);
}
public void testHTMLToImageAndSWF() throws Exception
{
NodeRef nodeRef = createOrigionalContent(this.folder, MimetypeMap.MIMETYPE_HTML);
NodeRef nodeRef = createOriginalContent(this.folder, MimetypeMap.MIMETYPE_HTML);
ThumbnailDefinition def = this.thumbnailService.getThumbnailRegistry().getThumbnailDefinition("medium");
if (this.contentService.getTransformer(MimetypeMap.MIMETYPE_HTML, def.getMimetype(), def.getTransformationOptions()) != null)
{
NodeRef thumb = this.thumbnailService.createThumbnail(
nodeRef,
ContentModel.PROP_CONTENT,
def.getMimetype(),
def.getTransformationOptions(),
def.getName());
ContentTransformer transformer = this.contentService.getTransformer(MimetypeMap.MIMETYPE_HTML, def
.getMimetype(), def.getTransformationOptions());
if (transformer != null)
{
NodeRef thumb = this.thumbnailService.createThumbnail(nodeRef, ContentModel.PROP_CONTENT,
def.getMimetype(), def.getTransformationOptions(), def.getName());
assertNotNull(thumb);
ContentReader reader = this.contentService.getReader(thumb, ContentModel.PROP_CONTENT);
assertNotNull(reader);
assertEquals(def.getMimetype(), reader.getMimetype());
assertTrue(reader.getSize() != 0);
}
def = this.thumbnailService.getThumbnailRegistry().getThumbnailDefinition("webpreview");
if (this.contentService.getTransformer(MimetypeMap.MIMETYPE_HTML, def.getMimetype(), def.getTransformationOptions()) != null)
{
NodeRef thumb = this.thumbnailService.createThumbnail(
nodeRef,
ContentModel.PROP_CONTENT,
def.getMimetype(),
def.getTransformationOptions(),
def.getName());
if (transformer != null)
{
NodeRef thumb = this.thumbnailService.createThumbnail(nodeRef, ContentModel.PROP_CONTENT,
def.getMimetype(), def.getTransformationOptions(), def.getName());
assertNotNull(thumb);
ContentReader reader = this.contentService.getReader(thumb, ContentModel.PROP_CONTENT);
assertNotNull(reader);
@@ -393,34 +429,111 @@ public class ThumbnailServiceImplTest extends BaseAlfrescoSpringTest
}
}
public void testThumbnailServiceCreateApi() throws Exception
{
// Create a second folder
Map<QName, Serializable> folderProps = new HashMap<QName, Serializable>();
folderProps.put(ContentModel.PROP_NAME, "otherTestFolder");
NodeRef otherFolder = this.nodeService.createNode(this.rootNodeRef, ContentModel.ASSOC_CHILDREN,
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "otherTestFolder"), ContentModel.TYPE_FOLDER)
.getChildRef();
checkTransformer();
NodeRef jpgOrig = createOriginalContent(this.folder, MimetypeMap.MIMETYPE_IMAGE_JPEG);
ImageResizeOptions imageResizeOptions = new ImageResizeOptions();
imageResizeOptions.setWidth(64);
imageResizeOptions.setHeight(64);
imageResizeOptions.setResizeToThumbnail(true);
ImageTransformationOptions imageTransformationOptions = new ImageTransformationOptions();
imageTransformationOptions.setResizeOptions(imageResizeOptions);
// Create thumbnail - same MIME type
NodeRef thumbnail1 = this.thumbnailService.createThumbnail(jpgOrig, ContentModel.PROP_CONTENT,
MimetypeMap.MIMETYPE_IMAGE_JPEG, imageTransformationOptions, "smallJpeg");
assertNotNull(thumbnail1);
checkRenditioned(jpgOrig, "smallJpeg");
checkRendition("smallJpeg", thumbnail1);
outputThumbnailTempContentLocation(thumbnail1, "jpg", "smallJpeg - 64x64, marked as thumbnail");
// Create thumbnail - different MIME type
thumbnail1 = this.thumbnailService.createThumbnail(jpgOrig, ContentModel.PROP_CONTENT,
MimetypeMap.MIMETYPE_IMAGE_PNG, imageTransformationOptions, "smallPng");
assertNotNull(thumbnail1);
checkRenditioned(jpgOrig, "smallPng");
checkRendition("smallPng", thumbnail1);
outputThumbnailTempContentLocation(thumbnail1, "png", "smallPng - 64x64, marked as thumbnail");
// Create thumbnail - different content property
// TODO
// Create thumbnail - different command options
// We'll pass illegal command options to ImageMagick in order to trigger an exception
Exception x = null;
try
{
imageTransformationOptions.setCommandOptions("-noSuchOption");
thumbnail1 = this.thumbnailService.createThumbnail(jpgOrig, ContentModel.PROP_CONTENT,
MimetypeMap.MIMETYPE_IMAGE_PNG, imageTransformationOptions, "smallCO");
} catch (ContentIOException ciox)
{
x = ciox;
ciox.printStackTrace();
}
assertNotNull("Expected exception from ImageMagick due to invalid option", x);
// Reset the command options
imageTransformationOptions.setCommandOptions("");
// Create thumbnail - different target assoc details
ThumbnailParentAssociationDetails tpad
= new ThumbnailParentAssociationDetails(otherFolder,
QName.createQName(NamespaceService.RENDITION_MODEL_1_0_URI, "foo"),
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "bar"));
thumbnail1 = this.thumbnailService.createThumbnail(jpgOrig, ContentModel.PROP_CONTENT,
MimetypeMap.MIMETYPE_IMAGE_PNG, imageTransformationOptions, "targetDetails", tpad);
assertNotNull(thumbnail1);
checkRenditioned(jpgOrig, "targetDetails");
checkRendition("targetDetails", thumbnail1);
outputThumbnailTempContentLocation(thumbnail1, "png", "targetDetails - 64x64, marked as thumbnail");
// Create thumbnail - null thumbnail name
thumbnail1 = this.thumbnailService.createThumbnail(jpgOrig, ContentModel.PROP_CONTENT,
MimetypeMap.MIMETYPE_IMAGE_PNG, imageTransformationOptions, null);
assertNotNull(thumbnail1);
checkRenditioned(jpgOrig, null);
checkRendition(null, thumbnail1);
outputThumbnailTempContentLocation(thumbnail1, "png", "'null' - 64x64, marked as thumbnail");
}
public void testRegistry()
{
ThumbnailRegistry thumbnailRegistry = this.thumbnailService.getThumbnailRegistry();
List<ThumbnailDefinition> defs = thumbnailRegistry.getThumnailDefintions(MimetypeMap.MIMETYPE_HTML);
List<ThumbnailDefinition> defs = thumbnailRegistry.getThumbnailDefinitions(MimetypeMap.MIMETYPE_HTML);
System.out.println("Definitions ...");
for (ThumbnailDefinition def : defs)
{
System.out.println("Thumbnail Available: " + def.getName());
}
}
// == Test the JavaScript API ==
public void testJSAPI() throws Exception
{
NodeRef jpgOrig = createOrigionalContent(this.folder, MimetypeMap.MIMETYPE_IMAGE_JPEG);
NodeRef gifOrig = createOrigionalContent(this.folder, MimetypeMap.MIMETYPE_IMAGE_GIF);
NodeRef pdfOrig = createOrigionalContent(this.folder, MimetypeMap.MIMETYPE_PDF);
NodeRef docOrig = createOrigionalContent(this.folder, MimetypeMap.MIMETYPE_WORD);
NodeRef jpgOrig = createOriginalContent(this.folder, MimetypeMap.MIMETYPE_IMAGE_JPEG);
NodeRef gifOrig = createOriginalContent(this.folder, MimetypeMap.MIMETYPE_IMAGE_GIF);
NodeRef pdfOrig = createOriginalContent(this.folder, MimetypeMap.MIMETYPE_PDF);
NodeRef docOrig = createOriginalContent(this.folder, MimetypeMap.MIMETYPE_WORD);
Map<String, Object> model = new HashMap<String, Object>(2);
model.put("jpgOrig", jpgOrig);
model.put("gifOrig", gifOrig);
model.put("pdfOrig", pdfOrig);
model.put("docOrig", docOrig);
ScriptLocation location = new ClasspathScriptLocation("org/alfresco/repo/thumbnail/script/test_thumbnailAPI.js");
this.scriptService.executeScript(location, model);
}

View File

@@ -1,293 +0,0 @@
/*
* Copyright (C) 2005-2010 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.thumbnail;
import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.copy.CopyBehaviourCallback;
import org.alfresco.repo.copy.CopyDetails;
import org.alfresco.repo.copy.CopyServicePolicies;
import org.alfresco.repo.copy.DefaultCopyBehaviourCallback;
import org.alfresco.repo.node.NodeServicePolicies;
import org.alfresco.repo.policy.Behaviour;
import org.alfresco.repo.policy.JavaBehaviour;
import org.alfresco.repo.policy.PolicyComponent;
import org.alfresco.service.cmr.action.Action;
import org.alfresco.service.cmr.action.ActionService;
import org.alfresco.service.cmr.action.CompositeAction;
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.thumbnail.ThumbnailService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.EqualsHelper;
/**
* Thumbnailed aspect behaviour bean
*
* @author Roy Wetherall
*/
public class ThumbnailedAspect implements NodeServicePolicies.OnUpdatePropertiesPolicy,
CopyServicePolicies.OnCopyNodePolicy
{
/** Services */
private PolicyComponent policyComponent;
private ThumbnailService thumbnailService;
private ActionService actionService;
private NodeService nodeService;
private DictionaryService dictionaryService;
/**
* Set the policy component
*
* @param policyComponent policy component
*/
public void setPolicyComponent(PolicyComponent policyComponent)
{
this.policyComponent = policyComponent;
}
/**
* Set the action service
*
* @param actionService action service
*/
public void setActionService(ActionService actionService)
{
this.actionService = actionService;
}
/**
* Set the node service
*
* @param nodeService node service
*/
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
/**
* Set the thumbnail service
*
* @param thumbnailService thumbnail service
*/
public void setThumbnailService(ThumbnailService thumbnailService)
{
this.thumbnailService = thumbnailService;
}
/**
* Set the dictionary service
*
* @param dictionaryService dictionary service
*/
public void setDictionaryService(DictionaryService dictionaryService)
{
this.dictionaryService = dictionaryService;
}
/**
* Initialise method
*/
public void init()
{
this.policyComponent.bindClassBehaviour(
QName.createQName(NamespaceService.ALFRESCO_URI, "onUpdateProperties"),
ContentModel.ASPECT_THUMBNAILED,
new JavaBehaviour(this, "onUpdateProperties", Behaviour.NotificationFrequency.TRANSACTION_COMMIT));
this.policyComponent.bindClassBehaviour(
QName.createQName(NamespaceService.ALFRESCO_URI, "getCopyCallback"),
ContentModel.ASPECT_THUMBNAILED,
new JavaBehaviour(this, "getCopyCallback"));
}
/**
* @see org.alfresco.repo.node.NodeServicePolicies.OnUpdatePropertiesPolicy#onUpdateProperties(org.alfresco.service.cmr.repository.NodeRef, java.util.Map, java.util.Map)
*/
public void onUpdateProperties(
NodeRef nodeRef,
Map<QName, Serializable> before,
Map<QName, Serializable> after)
{
// Ignore working copies
if (this.nodeService.exists(nodeRef) == true &&
this.nodeService.hasAspect(nodeRef, ContentModel.ASPECT_WORKING_COPY) == false)
{
// check if any of the content properties have changed
for (QName propertyQName : after.keySet())
{
// is this a content property?
PropertyDefinition propertyDef = dictionaryService.getProperty(propertyQName);
if (propertyDef == null)
{
// the property is not recognised
continue;
}
if (!propertyDef.getDataType().getName().equals(DataTypeDefinition.CONTENT))
{
// not a content type
continue;
}
try
{
ContentData beforeValue = (ContentData) before.get(propertyQName);
ContentData afterValue = (ContentData) after.get(propertyQName);
// Figure out if the content is new or not
boolean newContent = false;
String beforeContentUrl = null;
if (beforeValue != null)
{
beforeContentUrl = beforeValue.getContentUrl();
}
String afterContentUrl = null;
if (afterValue != null)
{
afterContentUrl = afterValue.getContentUrl();
}
if (beforeContentUrl == null && afterContentUrl != null)
{
newContent = true;
}
if (afterValue != null && afterValue.getContentUrl() == null)
{
// no URL - ignore
}
else if (newContent == false && EqualsHelper.nullSafeEquals(beforeValue, afterValue) == false)
{
// Queue the update
queueUpdate(nodeRef, propertyQName);
}
}
catch (ClassCastException e)
{
// properties don't conform to model
continue;
}
}
}
}
/**
* Queue the update to happen asynchronously
*
* @param nodeRef node reference
* @param contentProperty content property
*/
private void queueUpdate(NodeRef nodeRef, QName contentProperty)
{
Boolean automaticUpdate = (Boolean)this.nodeService.getProperty(nodeRef, ContentModel.PROP_AUTOMATIC_UPDATE);
if (automaticUpdate != null && automaticUpdate.booleanValue() == true)
{
CompositeAction compositeAction = actionService.createCompositeAction();
List<NodeRef> thumbnails = this.thumbnailService.getThumbnails(nodeRef, contentProperty, null, null);
for (NodeRef thumbnail : thumbnails)
{
// Execute the update thumbnail action async for each thumbnail
Action action = actionService.createAction(UpdateThumbnailActionExecuter.NAME);
action.setParameterValue(UpdateThumbnailActionExecuter.PARAM_CONTENT_PROPERTY, contentProperty);
action.setParameterValue(UpdateThumbnailActionExecuter.PARAM_THUMBNAIL_NODE, thumbnail);
compositeAction.addAction(action);
}
actionService.executeAction(compositeAction, nodeRef, false, true);
}
}
/**
* @return Returns {@link ThumbnailedAspectCopyBehaviourCallback}
*/
public CopyBehaviourCallback getCopyCallback(QName classRef, CopyDetails copyDetails)
{
return ThumbnailedAspectCopyBehaviourCallback.INSTANCE;
}
/**
* Behaviour for the {@link ContentModel#ASPECT_THUMBNAILED <b>cm:thumbnailed</b>} aspect.
*
* @author Derek Hulley
* @since 3.2
*/
private static class ThumbnailedAspectCopyBehaviourCallback extends DefaultCopyBehaviourCallback
{
private static final CopyBehaviourCallback INSTANCE = new ThumbnailedAspectCopyBehaviourCallback();
/**
* @return Returns <tt>true</tt> always
*/
@Override
public boolean getMustCopy(QName classQName, CopyDetails copyDetails)
{
return true;
}
/**
* Copy thumbnail-related associations, {@link ContentModel#ASSOC_THUMBNAILS} regardless of
* cascade options.
*/
@Override
public ChildAssocCopyAction getChildAssociationCopyAction(
QName classQName,
CopyDetails copyDetails,
CopyChildAssociationDetails childAssocCopyDetails)
{
ChildAssociationRef childAssocRef = childAssocCopyDetails.getChildAssocRef();
if (childAssocRef.getTypeQName().equals(ContentModel.ASSOC_THUMBNAILS))
{
return ChildAssocCopyAction.COPY_CHILD;
}
else
{
throw new IllegalStateException(
"Behaviour should have been invoked: \n" +
" Aspect: " + this.getClass().getName() + "\n" +
" " + childAssocCopyDetails + "\n" +
" " + copyDetails);
}
}
/**
* Copy only the {@link ContentModel#PROP_AUTOMATIC_UPDATE}
*/
@Override
public Map<QName, Serializable> getCopyProperties(
QName classQName,
CopyDetails copyDetails,
Map<QName, Serializable> properties)
{
Map<QName, Serializable> newProperties = new HashMap<QName, Serializable>(5);
Serializable value = properties.get(ContentModel.PROP_AUTOMATIC_UPDATE);
newProperties.put(ContentModel.PROP_AUTOMATIC_UPDATE, value);
return newProperties;
}
}
}

View File

@@ -27,20 +27,31 @@ import org.alfresco.repo.action.executer.ActionExecuterAbstractBase;
import org.alfresco.service.cmr.action.Action;
import org.alfresco.service.cmr.action.ParameterDefinition;
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
import org.alfresco.service.cmr.rendition.RenditionService;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.thumbnail.ThumbnailService;
import org.alfresco.service.namespace.QName;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Update thumbnail action executer.
*
* NOTE: This action is used to facilitate the async update of thumbnails. It is not intended for genereral usage.
* NOTE: This action is used to facilitate the async update of thumbnails. It is not intended for general usage.
*
* @author Roy Wetherall
* @author Neil McErlean
*/
public class UpdateThumbnailActionExecuter extends ActionExecuterAbstractBase
{
/** Logger */
private static Log logger = LogFactory.getLog(UpdateThumbnailActionExecuter.class);
/** Rendition Service */
private RenditionService renditionService;
/** Thumbnail Service */
private ThumbnailService thumbnailService;
@@ -52,6 +63,16 @@ public class UpdateThumbnailActionExecuter extends ActionExecuterAbstractBase
public static final String PARAM_CONTENT_PROPERTY = "content-property";
public static final String PARAM_THUMBNAIL_NODE = "thumbnail-node";
/**
* Injects the rendition service.
*
* @param renditionService the rendition service.
*/
public void setRenditionService(RenditionService renditionService)
{
this.renditionService = renditionService;
}
/**
* Set the thumbnail service
*
@@ -86,17 +107,17 @@ public class UpdateThumbnailActionExecuter extends ActionExecuterAbstractBase
}
if (this.nodeService.exists(thumbnailNodeRef) == true &&
ContentModel.TYPE_THUMBNAIL.equals(this.nodeService.getType(thumbnailNodeRef)) == true)
renditionService.isRendition(thumbnailNodeRef))
{
// Get the thumbnail Name
String thumbnailName = (String)this.nodeService.getProperty(thumbnailNodeRef, ContentModel.PROP_THUMBNAIL_NAME);
ChildAssociationRef parent = renditionService.getSourceNode(thumbnailNodeRef);
String thumbnailName = parent.getQName().getLocalName();
// Get the details of the thumbnail
ThumbnailRegistry registry = this.thumbnailService.getThumbnailRegistry();
ThumbnailDefinition details = registry.getThumbnailDefinition(thumbnailName);
if (details == null)
{
// Throw exception
throw new AlfrescoRuntimeException("The thumbnail name '" + thumbnailName + "' is not registered");
}
@@ -121,5 +142,4 @@ public class UpdateThumbnailActionExecuter extends ActionExecuterAbstractBase
paramList.add(new ParameterDefinitionImpl(PARAM_CONTENT_PROPERTY, DataTypeDefinition.QNAME, false, getParamDisplayLabel(PARAM_CONTENT_PROPERTY)));
paramList.add(new ParameterDefinitionImpl(PARAM_THUMBNAIL_NODE, DataTypeDefinition.QNAME, false, getParamDisplayLabel(PARAM_THUMBNAIL_NODE)));
}
}

View File

@@ -18,20 +18,31 @@
*/
package org.alfresco.repo.thumbnail.script;
import org.alfresco.model.ContentModel;
import java.util.List;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.RenditionModel;
import org.alfresco.repo.jscript.ScriptNode;
import org.alfresco.repo.thumbnail.ThumbnailDefinition;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.RegexQNamePattern;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.mozilla.javascript.Scriptable;
/**
* @author Roy Wetherall
* @author Neil McErlean
*/
public class ScriptThumbnail extends ScriptNode
{
private static final long serialVersionUID = 7854749986083635678L;
/** Logger */
private static Log logger = LogFactory.getLog(ScriptThumbnail.class);
/**
* Constructor
*
@@ -49,7 +60,25 @@ public class ScriptThumbnail extends ScriptNode
*/
public void update()
{
String name = (String)services.getNodeService().getProperty(nodeRef, ContentModel.PROP_THUMBNAIL_NAME);
List<ChildAssociationRef> parentRefs = services.getNodeService().getParentAssocs(nodeRef, RenditionModel.ASSOC_RENDITION, RegexQNamePattern.MATCH_ALL);
// There should in fact only ever be one parent association of type rendition on any rendition node.
if (parentRefs.size() != 1)
{
StringBuilder msg = new StringBuilder();
msg.append("Node ")
.append(nodeRef)
.append(" has ")
.append(parentRefs.size())
.append(" rendition parents. Unable to update.");
if (logger.isWarnEnabled())
{
logger.warn(msg.toString());
}
throw new AlfrescoRuntimeException(msg.toString());
}
String name = parentRefs.get(0).getQName().getLocalName();
ThumbnailDefinition def = services.getThumbnailService().getThumbnailRegistry().getThumbnailDefinition(name);
services.getThumbnailService().updateThumbnail(this.nodeRef, def.getTransformationOptions());
}