diff --git a/config/alfresco/model/contentModel.xml b/config/alfresco/model/contentModel.xml index 3671ca43cd..a70e5ef798 100644 --- a/config/alfresco/model/contentModel.xml +++ b/config/alfresco/model/contentModel.xml @@ -316,11 +316,16 @@ cm:content true - - Thumbnail Options - d:any - false + + Thumbnailed Content Property Name + d:qname + true + + Transformation Options Class + d:text + false + @@ -849,6 +854,50 @@ + + + Image Transformation Options + + + Command Options + d:text + false + -1 + + + Resize The Image + d:boolean + false + + + Resize Width + d:int + false + -1 + + + Resize Height + d:int + false + + + Resize Maintain Aspect Ratio + d:boolean + true + + + Resize Percent + d:boolean + false + + + Resize To Thumbnail + d:boolean + false + + + + diff --git a/config/alfresco/thumbnail-service-context.xml b/config/alfresco/thumbnail-service-context.xml index c347cab330..fdd54d7661 100644 --- a/config/alfresco/thumbnail-service-context.xml +++ b/config/alfresco/thumbnail-service-context.xml @@ -40,6 +40,7 @@ + diff --git a/source/java/org/alfresco/model/ContentModel.java b/source/java/org/alfresco/model/ContentModel.java index 93c1be001c..2b4288db4c 100644 --- a/source/java/org/alfresco/model/ContentModel.java +++ b/source/java/org/alfresco/model/ContentModel.java @@ -240,6 +240,8 @@ public interface ContentModel // Thumbnail Type static final QName TYPE_THUMBNAIL = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "thumbnail"); + static final QName PROP_CONTENT_PROPERTY_NAME = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "contentPropertyName"); + static final QName PROP_TRANSFORMATION_OPTIONS_CLASS = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "cm:transformationOptionsClass"); // Thumbnailed Aspect static final QName ASPECT_THUMBNAILED = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "thumbnailed"); diff --git a/source/java/org/alfresco/repo/content/transform/BinaryPassThroughContentTransformer.java b/source/java/org/alfresco/repo/content/transform/BinaryPassThroughContentTransformer.java index bb7031bb7e..d9a8be968d 100644 --- a/source/java/org/alfresco/repo/content/transform/BinaryPassThroughContentTransformer.java +++ b/source/java/org/alfresco/repo/content/transform/BinaryPassThroughContentTransformer.java @@ -71,8 +71,17 @@ public class BinaryPassThroughContentTransformer extends AbstractContentTransfor } else { - // formats are the same and are not text - return true; + if (BinaryPassThroughContentTransformer.class == options.getClass()) + { + // formats are the same and are not text + return true; + } + else + { + // If it has meaningful options then we assume there is another transformer better equiped + // to deal with it + return false; + } } } } diff --git a/source/java/org/alfresco/repo/content/transform/TransformTestSuite.java b/source/java/org/alfresco/repo/content/transform/TransformTestSuite.java index dfcc741093..0fd185dadc 100644 --- a/source/java/org/alfresco/repo/content/transform/TransformTestSuite.java +++ b/source/java/org/alfresco/repo/content/transform/TransformTestSuite.java @@ -24,12 +24,11 @@ */ package org.alfresco.repo.content.transform; -import org.alfresco.repo.content.transform.magick.ImageMagickContentTransformerTest; -import org.alfresco.repo.content.transform.magick.JMagickContentTransformerTest; - import junit.framework.Test; import junit.framework.TestSuite; +import org.alfresco.repo.content.transform.magick.ImageMagickContentTransformerTest; + /** * Version test suite @@ -60,7 +59,6 @@ public class TransformTestSuite extends TestSuite suite.addTestSuite(TextMiningContentTransformerTest.class); suite.addTestSuite(TextToPdfContentTransformerTest.class); suite.addTestSuite(ImageMagickContentTransformerTest.class); - suite.addTestSuite(JMagickContentTransformerTest.class); return suite; } } diff --git a/source/java/org/alfresco/repo/content/transform/magick/ImageMagickContentTransformer.java b/source/java/org/alfresco/repo/content/transform/magick/ImageMagickContentTransformer.java index 6a60a36ef6..f7bf4da7b4 100644 --- a/source/java/org/alfresco/repo/content/transform/magick/ImageMagickContentTransformer.java +++ b/source/java/org/alfresco/repo/content/transform/magick/ImageMagickContentTransformer.java @@ -54,6 +54,9 @@ public class ImageMagickContentTransformer extends AbstractImageMagickContentTra /** the system command executer */ private RuntimeExec executer; + /** + * Default constructor + */ public ImageMagickContentTransformer() { } @@ -100,7 +103,14 @@ public class ImageMagickContentTransformer extends AbstractImageMagickContentTra // set properties if (options instanceof ImageTransformationOptions) { - properties.put(KEY_OPTIONS, (String) ((ImageTransformationOptions)options).getCommandOptions()); + ImageTransformationOptions imageOptions = (ImageTransformationOptions)options; + ImageResizeOptions resizeOptions = imageOptions.getResizeOptions(); + String commandOptions = imageOptions.getCommandOptions(); + if (resizeOptions != null) + { + commandOptions = commandOptions + " " + getImageResizeCommandOptions(resizeOptions); + } + properties.put(KEY_OPTIONS, commandOptions); } properties.put(VAR_SOURCE, sourceFile.getAbsolutePath()); properties.put(VAR_TARGET, targetFile.getAbsolutePath()); @@ -117,4 +127,47 @@ public class ImageMagickContentTransformer extends AbstractImageMagickContentTra logger.debug("ImageMagic executed successfully: \n" + executer); } } + + /** + * Gets the imagemagick command string for the image resize options provided + * + * @param imageResizeOptions image resize options + * @return String the imagemagick command options + */ + private String getImageResizeCommandOptions(ImageResizeOptions imageResizeOptions) + { + StringBuilder builder = new StringBuilder(32); + + if (imageResizeOptions.isResizeToThumbnail() == true) + { + builder.append("-thumbnail "); + } + else + { + builder.append("-resize "); + } + + if (imageResizeOptions.getWidth() > -1) + { + builder.append(imageResizeOptions.getWidth()); + } + + if (imageResizeOptions.getHeight() > -1) + { + builder.append("x"); + builder.append(imageResizeOptions.getHeight()); + } + + if (imageResizeOptions.isPercentResize() == true) + { + builder.append("%"); + } + + if (imageResizeOptions.isMaintainAspectRatio() == false) + { + builder.append("!"); + } + + return builder.toString(); + } } diff --git a/source/java/org/alfresco/repo/content/transform/magick/ImageResizeOptions.java b/source/java/org/alfresco/repo/content/transform/magick/ImageResizeOptions.java new file mode 100644 index 0000000000..589333b160 --- /dev/null +++ b/source/java/org/alfresco/repo/content/transform/magick/ImageResizeOptions.java @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2005-2007 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.content.transform.magick; + +/** + * Image resize options + * + * @author Roy Wetherall + */ +public class ImageResizeOptions +{ + /** The width */ + private int width = -1; + + /** The height */ + private int height = -1; + + /** Indicates whether the aspect ratio of the image should be maintained */ + private boolean maintainAspectRatio = true; + + /** Indicates whether this is a percentage resize */ + private boolean percentResize = false; + + /** Indicates whether the resized image is a thumbnail */ + private boolean resizeToThumbnail = false; + + /** + * Defatult constructor + */ + public ImageResizeOptions() + { + } + + public void setWidth(int width) + { + this.width = width; + } + + public int getWidth() + { + return width; + } + + public void setHeight(int height) + { + this.height = height; + } + + public int getHeight() + { + return height; + } + + public void setMaintainAspectRatio(boolean maintainAspectRatio) + { + this.maintainAspectRatio = maintainAspectRatio; + } + + public boolean isMaintainAspectRatio() + { + return maintainAspectRatio; + } + + public void setPercentResize(boolean percentResize) + { + this.percentResize = percentResize; + } + + public boolean isPercentResize() + { + return percentResize; + } + + public void setResizeToThumbnail(boolean resizeToThumbnail) + { + this.resizeToThumbnail = resizeToThumbnail; + } + + public boolean isResizeToThumbnail() + { + return resizeToThumbnail; + } +} diff --git a/source/java/org/alfresco/repo/content/transform/magick/ImageTransformationOptions.java b/source/java/org/alfresco/repo/content/transform/magick/ImageTransformationOptions.java index 156f93bc76..f7fd9db599 100644 --- a/source/java/org/alfresco/repo/content/transform/magick/ImageTransformationOptions.java +++ b/source/java/org/alfresco/repo/content/transform/magick/ImageTransformationOptions.java @@ -24,22 +24,146 @@ */ package org.alfresco.repo.content.transform.magick; +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; + +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.TransformationOptions; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.namespace.QName; /** + * Image transformation options + * * @author Roy Wetherall */ public class ImageTransformationOptions extends TransformationOptions { + /** imageTransformOptions aspect details */ + public static final QName ASPECT_IMAGE_TRANSFORATION_OPTIONS = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "imageTransformationOptions"); + public static final QName PROP_COMMAND_OPTIONS = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "commandOptions"); + public static final QName PROP_RESIZE = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "resize"); + public static final QName PROP_RESIZE_WIDTH = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "resizeWidth"); + public static final QName PROP_RESIZE_HEIGHT = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "resizeHeight"); + public static final QName PROP_RESIZE_MAINTAIN_ASPECT_RATIO = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "resizeMaintainAspectRatio"); + public static final QName PROP_RESIZE_PERCENT = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "resizePercent"); + public static final QName PROP_RESIZE_TO_THUMBNAIL = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "resizeToThumbnail"); + + /** Command string options, provided for backward compatibility */ private String commandOptions = ""; + /** Image resize options */ + private ImageResizeOptions resizeOptions; + + /** + * Set the command string options + * + * @param commandOptions the command string options + */ public void setCommandOptions(String commandOptions) { this.commandOptions = commandOptions; } + /** + * Get the command string options + * + * @return String the command string options + */ public String getCommandOptions() { return commandOptions; } + + /** + * Set the image resize options + * + * @param resizeOptions image resize options + */ + public void setResizeOptions(ImageResizeOptions resizeOptions) + { + this.resizeOptions = resizeOptions; + } + + /** + * Get the image resize options + * + * @return ImageResizeOptions image resize options + */ + public ImageResizeOptions getResizeOptions() + { + return resizeOptions; + } + + /** + * Save the transformation options to the ImageTransformationOptions aspect. + * + * @see org.alfresco.service.cmr.repository.TransformationOptions#saveToNode(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.cmr.repository.NodeService) + */ + @Override + public void saveToNode(NodeRef nodeRef, NodeService nodeService) + { + super.saveToNode(nodeRef, nodeService); + + // Create a list of the properties + Map properties = new HashMap(7); + properties.put(PROP_COMMAND_OPTIONS, this.commandOptions); + if (this.resizeOptions != null) + { + properties.put(PROP_RESIZE, true); + properties.put(PROP_RESIZE_HEIGHT, this.resizeOptions.getHeight()); + properties.put(PROP_RESIZE_WIDTH, this.resizeOptions.getWidth()); + properties.put(PROP_RESIZE_MAINTAIN_ASPECT_RATIO, this.resizeOptions.isMaintainAspectRatio()); + properties.put(PROP_RESIZE_PERCENT, this.resizeOptions.isPercentResize()); + properties.put(PROP_RESIZE_TO_THUMBNAIL, this.resizeOptions.isResizeToThumbnail()); + } + else + { + properties.put(PROP_RESIZE, false); + } + + // Add the aspect + nodeService.addAspect(nodeRef, ASPECT_IMAGE_TRANSFORATION_OPTIONS, properties); + } + + /** + * Populate the image transformation options from the node provided. + * + * @see org.alfresco.service.cmr.repository.TransformationOptions#populateFromNode(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.cmr.repository.NodeService) + */ + @Override + public void populateFromNode(NodeRef nodeRef, NodeService nodeService) + { + super.populateFromNode(nodeRef, nodeService); + + // Check whether the node has the image transformation options aspect + if (nodeService.hasAspect(nodeRef, ASPECT_IMAGE_TRANSFORATION_OPTIONS) == true) + { + // Get the node's properties + Map properties = nodeService.getProperties(nodeRef); + + // Set the properties + this.commandOptions = (String)properties.get(PROP_COMMAND_OPTIONS); + + // Set the resize properties + Boolean isResize = (Boolean)properties.get(PROP_RESIZE); + if (isResize.booleanValue() == true) + { + int height = ((Long)properties.get(PROP_RESIZE_HEIGHT)).intValue(); + int width = ((Long)properties.get(PROP_RESIZE_WIDTH)).intValue(); + boolean maintainAspectRatio = ((Boolean)properties.get(PROP_RESIZE_MAINTAIN_ASPECT_RATIO)).booleanValue(); + boolean percentResize = ((Boolean)properties.get(PROP_RESIZE_PERCENT)).booleanValue(); + boolean resizeToThumbnail = ((Boolean)properties.get(PROP_RESIZE_TO_THUMBNAIL)).booleanValue(); + + this.resizeOptions = new ImageResizeOptions(); + this.resizeOptions.setHeight(height); + this.resizeOptions.setWidth(width); + this.resizeOptions.setMaintainAspectRatio(maintainAspectRatio); + this.resizeOptions.setPercentResize(percentResize); + this.resizeOptions.setResizeToThumbnail(resizeToThumbnail); + } + } + } } diff --git a/source/java/org/alfresco/repo/content/transform/magick/JMagickContentTransformer.java b/source/java/org/alfresco/repo/content/transform/magick/JMagickContentTransformer.java deleted file mode 100644 index 1954e5fe15..0000000000 --- a/source/java/org/alfresco/repo/content/transform/magick/JMagickContentTransformer.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2005-2007 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.content.transform.magick; - -import java.io.File; - -import magick.ImageInfo; -import magick.MagickImage; - -import org.alfresco.service.cmr.repository.TransformationOptions; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * Makes use of the {@link http://www.textmining.org/ TextMining} library to - * perform conversions from MSWord documents to text. - * - * @author Derek Hulley - */ -public class JMagickContentTransformer extends AbstractImageMagickContentTransformer -{ - @SuppressWarnings("unused") - private static final Log logger = LogFactory.getLog(JMagickContentTransformer.class); - - public JMagickContentTransformer() - { - } - - /** - * Uses the JMagick library to perform the transformation - * - * @param sourceFile - * @param targetFile - * @throws Exception - */ - @Override - protected void transformInternal(File sourceFile, File targetFile, TransformationOptions options) throws Exception - { - ImageInfo imageInfo = new ImageInfo(sourceFile.getAbsolutePath()); - MagickImage image = new MagickImage(imageInfo); - image.setFileName(targetFile.getAbsolutePath()); - image.writeImage(imageInfo); - } -} diff --git a/source/java/org/alfresco/repo/content/transform/magick/JMagickContentTransformerTest.java b/source/java/org/alfresco/repo/content/transform/magick/JMagickContentTransformerTest.java deleted file mode 100644 index bfcfcf36d7..0000000000 --- a/source/java/org/alfresco/repo/content/transform/magick/JMagickContentTransformerTest.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2005-2007 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.content.transform.magick; - -import org.alfresco.repo.content.MimetypeMap; -import org.alfresco.repo.content.transform.AbstractContentTransformerTest; -import org.alfresco.repo.content.transform.ContentTransformer; -import org.alfresco.service.cmr.repository.TransformationOptions; - -/** - * @see org.alfresco.repo.content.transform.magick.JMagickContentTransformer - * - * @author Derek Hulley - */ -public class JMagickContentTransformerTest extends AbstractContentTransformerTest -{ - private JMagickContentTransformer transformer; - - @Override - public void setUp() throws Exception - { - super.setUp(); - - transformer = new JMagickContentTransformer(); - transformer.setMimetypeService(mimetypeService); - transformer.init(); - } - - /** - * @return Returns the same transformer regardless - it is allowed - */ - protected ContentTransformer getTransformer(String sourceMimetype, String targetMimetype) - { - return transformer; - } - - public void testReliability() throws Exception - { - if (!transformer.isAvailable()) - { - return; - } - boolean reliability = transformer.isTransformable(MimetypeMap.MIMETYPE_IMAGE_GIF, MimetypeMap.MIMETYPE_TEXT_PLAIN, new TransformationOptions()); - assertEquals("Mimetype should not be supported", false, reliability); - reliability = transformer.isTransformable(MimetypeMap.MIMETYPE_IMAGE_GIF, MimetypeMap.MIMETYPE_IMAGE_JPEG, new TransformationOptions()); - assertEquals("Mimetype should be supported", true, reliability); - } -} diff --git a/source/java/org/alfresco/repo/thumbnail/ThumbnailServiceImpl.java b/source/java/org/alfresco/repo/thumbnail/ThumbnailServiceImpl.java index 852f284795..5eb7838594 100644 --- a/source/java/org/alfresco/repo/thumbnail/ThumbnailServiceImpl.java +++ b/source/java/org/alfresco/repo/thumbnail/ThumbnailServiceImpl.java @@ -25,33 +25,52 @@ package org.alfresco.repo.thumbnail; import java.io.Serializable; +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.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.thumbnail.AcceptOptions; -import org.alfresco.service.cmr.thumbnail.GenerateOptions; +import org.alfresco.service.cmr.repository.TransformationOptions; +import org.alfresco.service.cmr.thumbnail.CreateOptions; +import org.alfresco.service.cmr.thumbnail.ThumbnailException; import org.alfresco.service.cmr.thumbnail.ThumbnailService; -import org.alfresco.service.cmr.thumbnail.GenerateOptions.ParentAssociationDetails; +import org.alfresco.service.cmr.thumbnail.CreateOptions.ParentAssociationDetails; 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.alfresco.util.ParameterCheck; /** * @author Roy Wetherall */ public class ThumbnailServiceImpl implements ThumbnailService { + /** Error messages */ + private static final String ERR_NO_CREATE = "Thumbnail could not be created as required transformation is not supported."; + private static final String ERR_DUPLICATE_NAME = "Thumbnail could not be created because of a duplicate name"; + private static final String ERR_NO_PARENT = "Thumbnail has no parent so update cannot take place."; + private static final String ERR_TOO_PARENT = "Thumbnail has more than one source content node. This is invalid so update cannot take place."; + private static final String ERR_TRANS_CLASS = "Unable to create transformation options from saved class. Update of thumbnail cannnot take place."; + /** Node service */ private NodeService nodeService; /** Content service */ private ContentService contentService; + /** Mimetype map */ + private MimetypeMap mimetypeMap; + /** * Set the node service * @@ -72,13 +91,34 @@ public class ThumbnailServiceImpl implements ThumbnailService this.contentService = contentService; } + /** + * Sets the mimetype map + * + * @param mimetypeMap the mimetype map + */ + public void setMimetypeMap(MimetypeMap mimetypeMap) + { + this.mimetypeMap = mimetypeMap; + } + /** * @see org.alfresco.service.cmr.thumbnail.ThumbnailService#createThumbnail(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.namespace.QName, org.alfresco.service.cmr.thumbnail.GenerateOptions) */ - public NodeRef createThumbnail(NodeRef node, QName contentProperty, GenerateOptions createOptions) + public NodeRef createThumbnail(NodeRef node, QName contentProperty, CreateOptions createOptions) { + // Parameter check + ParameterCheck.mandatory("node", node); + ParameterCheck.mandatory("contentProperty", contentProperty); + NodeRef thumbnail = null; + // Check for duplicate names + if (createOptions.getThumbnailName() != null && getThumbnailByName(node, contentProperty, createOptions.getThumbnailName()) != null) + { + // We can't continue because there is already an thumnail with the given name for that content property + throw new ThumbnailException(ERR_DUPLICATE_NAME); + } + // Apply the thumbnailed aspect to the node if it doesn't already have it if (this.nodeService.hasAspect(node, ContentModel.ASPECT_THUMBNAILED) == false) { @@ -87,13 +127,25 @@ public class ThumbnailServiceImpl implements ThumbnailService // Get the name of the thumbnail and add to properties map String thumbnailName = createOptions.getThumbnailName(); + Map properties = new HashMap(2); if (thumbnailName == null) { thumbnailName = GUID.generate(); } - Map properties = new HashMap(1); - properties.put(ContentModel.PROP_NAME, thumbnailName); - // TODO .. somehow we need to store the details of the thumbnail on the node so we can regen the thumbnail later .. + else + { + String thumbnailFileName = generateThumbnailFileName(thumbnailName, createOptions.getDestinationMimetype()); + properties.put(ContentModel.PROP_NAME, thumbnailFileName); + } + + // Add the name of the content property + properties.put(ContentModel.PROP_CONTENT_PROPERTY_NAME, contentProperty); + + // Add the class name of the transformation options + if (createOptions.getTransformationOptions() != null) + { + properties.put(ContentModel.PROP_TRANSFORMATION_OPTIONS_CLASS, createOptions.getTransformationOptions().getClass().getName()); + } // See if parent association details have been specified for the thumbnail ParentAssociationDetails assocDetails = createOptions.getParentAssociationDetails(); @@ -125,18 +177,41 @@ public class ThumbnailServiceImpl implements ThumbnailService QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, thumbnailName)); } - // TODO .. do the work of actually creating the thumbnail content ... + // Get the content reader and writer for content nodes + ContentReader reader = this.contentService.getReader(node, contentProperty); + ContentWriter writer = this.contentService.getWriter(thumbnail, ContentModel.PROP_CONTENT, true); + writer.setMimetype(createOptions.getDestinationMimetype()); + writer.setEncoding(reader.getEncoding()); + + // Catch the failure to create the thumbnail + if (this.contentService.isTransformable(reader, writer, createOptions.getTransformationOptions()) == false) + { + // Throw exception indicating that the thumbnail could not be created + throw new ThumbnailException(ERR_NO_CREATE); + } + else + { + // Do the thumnail transformation + this.contentService.transform(reader, writer, createOptions.getTransformationOptions()); + + // Store the transformation options on the thumbnail + createOptions.getTransformationOptions().saveToNode(thumbnail, this.nodeService); + } // Return the created thumbnail return thumbnail; } /** - * @see org.alfresco.service.cmr.thumbnail.ThumbnailService#getThumbnails(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.namespace.QName, org.alfresco.service.cmr.thumbnail.AcceptOptions) + * Generates the thumbnail name from the name and destination mimertype + * + * @param thumbnailName the thumbnail name + * @param destinationMimetype the destination name + * @return String the thumbnail file name */ - public List getThumbnails(NodeRef node, QName contentProperty, AcceptOptions acceptOptions) + private String generateThumbnailFileName(String thumbnailName, String destinationMimetype) { - return null; + return thumbnailName + "." + this.mimetypeMap.getExtension(destinationMimetype); } /** @@ -144,6 +219,179 @@ public class ThumbnailServiceImpl implements ThumbnailService */ public void updateThumbnail(NodeRef thumbnail) { + // First check that we are dealing with a thumbnail + if (ContentModel.TYPE_THUMBNAIL.equals(this.nodeService.getType(thumbnail)) == true) + { + // Get the transformation options + TransformationOptions options = null; + String transformationOptionsClassName = (String)this.nodeService.getProperty(thumbnail, ContentModel.PROP_TRANSFORMATION_OPTIONS_CLASS); + if (transformationOptionsClassName == null) + { + options = new TransformationOptions(); + } + else + { + // Create an options object of the type specified on the thumbnail + try + { + Class transformationClass = Class.forName(transformationOptionsClassName); + options = (TransformationOptions)transformationClass.newInstance(); + } + catch (Exception exception) + { + throw new ThumbnailException(ERR_TRANS_CLASS); + } + + // Populate the options from the node + options.populateFromNode(thumbnail, this.nodeService); + } + + // Get the node that is the source of the thumbnail + NodeRef node = null; + List parents = this.nodeService.getParentAssocs(thumbnail, ContentModel.ASSOC_THUMBNAILS, RegexQNamePattern.MATCH_ALL); + if (parents.size() == 0) + { + throw new ThumbnailException(ERR_NO_PARENT); + } + else if (parents.size() != 1) + { + throw new ThumbnailException(ERR_TOO_PARENT); + } + else + { + node = parents.get(0).getParentRef(); + } + + // Get the content property + QName contentProperty = (QName)this.nodeService.getProperty(thumbnail, ContentModel.PROP_CONTENT_PROPERTY_NAME); + + // Get the reader and writer + ContentReader reader = this.contentService.getReader(node, contentProperty); + ContentWriter writer = this.contentService.getWriter(node, ContentModel.PROP_CONTENT, true); + + // Set the basic detail of the transformation options + options.setSourceNodeRef(node); + options.setSourceContentProperty(contentProperty); + options.setTargetNodeRef(thumbnail); + options.setTargetContentProperty(ContentModel.PROP_CONTENT); + + // Catch the failure to create the thumbnail + if (this.contentService.isTransformable(reader, writer, options) == false) + { + // Throw exception indicating that the thumbnail could not be created + throw new ThumbnailException(ERR_NO_CREATE); + } + else + { + // Do the thumnail transformation + this.contentService.transform(reader, writer, options); + } + } + // TODO else should we throw an exception? + } + + /** + * @see org.alfresco.service.cmr.thumbnail.ThumbnailService#getThumbnailByName(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.namespace.QName, java.lang.String) + */ + public NodeRef getThumbnailByName(NodeRef node, QName contentProperty, String thumbnailName) + { + NodeRef thumbnail = null; + + // + // NOTE: + // + // Since there is not an easy alternative and for clarity the node service is being used to retrieve the thumbnails. + // If retrieval performance becomes an issue then this code can be replaced + // + + // Check that the node has the thumbnailed aspect applied + if (nodeService.hasAspect(node, ContentModel.ASPECT_THUMBNAILED) == true) + { + // Get all the thumnails that match the thumbnail name + List assocs = this.nodeService.getChildAssocs(node, ContentModel.ASSOC_THUMBNAILS, QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, thumbnailName)); + 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) + { + thumbnail = child; + break; + } + } + } + + return thumbnail; + } + + /** + * @see org.alfresco.service.cmr.thumbnail.ThumbnailService#getThumbnails(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.namespace.QName, java.lang.String, org.alfresco.service.cmr.repository.TransformationOptions) + */ + public List getThumbnails(NodeRef node, QName contentProperty, String mimetype, TransformationOptions options) + { + List thumbnails = new ArrayList(5); + + // + // NOTE: + // + // Since there is not an easy alternative and for clarity the node service is being used to retrieve the thumbnails. + // If retrieval performance becomes an issue then this code can be replaced + // + + // Check that the node has the thumbnailed aspect applied + if (nodeService.hasAspect(node, ContentModel.ASPECT_THUMBNAILED) == true) + { + // Get all the thumnails that match the thumbnail name + List 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) + { + thumbnails.add(child); + } + } + } + + return thumbnails; + } + + /** + * Determine whether the thumbnail meta-data matches the given mimetype and options + * + * @param thumbnail thumbnail node reference + * @param mimetype mimetype + * @param options transformation options + * @return boolean true if the mimetype and options match the thumbnail metadata, false otherwise + */ + private boolean matchMimetypeOptions(NodeRef thumbnail, String mimetype, TransformationOptions options) + { + boolean result = true; + + // Check the mimetype + String thumbnailMimetype = ((ContentData)this.nodeService.getProperty(thumbnail, ContentModel.PROP_CONTENT)).getMimetype(); + if (mimetype.equals(thumbnailMimetype) == true) + { + // TODO continue to check options ... + } + else + { + result = false; + } + + return result; + } + + /** + * @see org.alfresco.service.cmr.thumbnail.ThumbnailService#getThumbnails(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.namespace.QName, java.lang.String) + */ + public List getThumbnails(NodeRef node, QName contentProperty, String mimetype) + { + return getThumbnails(node, contentProperty, mimetype, null); } } diff --git a/source/java/org/alfresco/repo/thumbnail/ThumbnailServiceImplTest.java b/source/java/org/alfresco/repo/thumbnail/ThumbnailServiceImplTest.java index dd9d5e71c4..b74bba0b0c 100644 --- a/source/java/org/alfresco/repo/thumbnail/ThumbnailServiceImplTest.java +++ b/source/java/org/alfresco/repo/thumbnail/ThumbnailServiceImplTest.java @@ -24,37 +24,309 @@ */ package org.alfresco.repo.thumbnail; -import org.alfresco.service.cmr.repository.ContentService; -import org.alfresco.service.cmr.repository.NodeService; +import java.io.File; +import java.io.IOException; +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.content.MimetypeMap; +import org.alfresco.repo.content.transform.AbstractContentTransformerTest; +import org.alfresco.repo.content.transform.magick.ImageResizeOptions; +import org.alfresco.repo.content.transform.magick.ImageTransformationOptions; +import org.alfresco.service.cmr.repository.ChildAssociationRef; +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.TransformationOptions; +import org.alfresco.service.cmr.thumbnail.CreateOptions; +import org.alfresco.service.cmr.thumbnail.ThumbnailException; import org.alfresco.service.cmr.thumbnail.ThumbnailService; -import org.alfresco.util.BaseSpringTest; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.namespace.QName; +import org.alfresco.service.namespace.RegexQNamePattern; +import org.alfresco.util.BaseAlfrescoSpringTest; /** * Thumbnail service implementation unit test * * @author Roy Wetherall */ -public class ThumbnailServiceImplTest extends BaseSpringTest +public class ThumbnailServiceImplTest extends BaseAlfrescoSpringTest { - private NodeService nodeService; - private ContentService contentService; - private ThumbnailService thumbnailService; + private ThumbnailService thumbnailService; + private MimetypeMap mimetypeMap; + private NodeRef folder; /** * Called during the transaction setup */ protected void onSetUpInTransaction() throws Exception { - // Get required service implementations - this.nodeService = (NodeService)this.applicationContext.getBean("NodeService"); - this.contentService = (ContentService)this.applicationContext.getBean("ContentService"); - this.thumbnailService = (ThumbnailService)this.applicationContext.getBean("ThumbnailService"); + super.onSetUpInTransaction(); + // Get the required services + this.thumbnailService = (ThumbnailService)this.applicationContext.getBean("ThumbnailService"); + this.mimetypeMap = (MimetypeMap)this.applicationContext.getBean("mimetypeService"); + + // Create a folder and some content + Map folderProps = new HashMap(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(); } - public void testCreateThumbnail() throws Exception + public void testCreateThumbnailFromImage() throws Exception { + NodeRef jpgOrig = createOrigionalContent(this.folder, MimetypeMap.MIMETYPE_IMAGE_JPEG); + NodeRef gifOrig = createOrigionalContent(this.folder, MimetypeMap.MIMETYPE_IMAGE_GIF); + // ===== small: 64x64, marked as thumbnail ==== + + ImageResizeOptions imageResizeOptions = new ImageResizeOptions(); + imageResizeOptions.setWidth(64); + imageResizeOptions.setHeight(64); + imageResizeOptions.setResizeToThumbnail(true); + ImageTransformationOptions imageTransformationOptions = new ImageTransformationOptions(); + imageTransformationOptions.setResizeOptions(imageResizeOptions); + CreateOptions createOptions = new CreateOptions( + MimetypeMap.MIMETYPE_IMAGE_JPEG, + imageTransformationOptions, + "small"); + NodeRef thumbnail1 = this.thumbnailService.createThumbnail(jpgOrig, ContentModel.PROP_CONTENT, createOptions); + assertNotNull(thumbnail1); + checkThumbnailed(jpgOrig, "small"); + checkThumbnail(thumbnail1, imageTransformationOptions); + outputThumbnailTempContentLocation(thumbnail1, "jpg", "small - 64x64, marked as thumbnail"); + + // ===== small2: 64x64, aspect not maintained ==== + + ImageResizeOptions imageResizeOptions2 = new ImageResizeOptions(); + imageResizeOptions2.setWidth(64); + imageResizeOptions2.setHeight(64); + imageResizeOptions2.setMaintainAspectRatio(false); + ImageTransformationOptions imageTransformationOptions2 = new ImageTransformationOptions(); + imageTransformationOptions2.setResizeOptions(imageResizeOptions2); + CreateOptions createOptions2 = new CreateOptions( + MimetypeMap.MIMETYPE_IMAGE_JPEG, + imageTransformationOptions2, + "small2"); + NodeRef thumbnail2 = this.thumbnailService.createThumbnail(jpgOrig, ContentModel.PROP_CONTENT, createOptions2); + checkThumbnailed(jpgOrig, "small2"); + checkThumbnail(thumbnail2, imageTransformationOptions2); + outputThumbnailTempContentLocation(thumbnail2, "jpg", "small2 - 64x64, aspect not maintained"); + + // ===== half: 50%x50 ===== + + ImageResizeOptions imageResizeOptions3 = new ImageResizeOptions(); + imageResizeOptions3.setWidth(50); + imageResizeOptions3.setHeight(50); + imageResizeOptions3.setPercentResize(true); + ImageTransformationOptions imageTransformationOptions3 = new ImageTransformationOptions(); + imageTransformationOptions3.setResizeOptions(imageResizeOptions3); + CreateOptions createOptions3 = new CreateOptions( + MimetypeMap.MIMETYPE_IMAGE_JPEG, + imageTransformationOptions3, + "half"); + NodeRef thumbnail3 = this.thumbnailService.createThumbnail(jpgOrig, ContentModel.PROP_CONTENT, createOptions3); + checkThumbnailed(jpgOrig, "half"); + checkThumbnail(thumbnail3, imageTransformationOptions3); + outputThumbnailTempContentLocation(thumbnail3, "jpg", "half - 50%x50%"); + + + // ===== half2: 50%x50 from gif ===== + + ImageResizeOptions imageResizeOptions4 = new ImageResizeOptions(); + imageResizeOptions4.setWidth(50); + imageResizeOptions4.setHeight(50); + imageResizeOptions4.setPercentResize(true); + ImageTransformationOptions imageTransformationOptions4 = new ImageTransformationOptions(); + imageTransformationOptions4.setResizeOptions(imageResizeOptions4); + CreateOptions createOptions4 = new CreateOptions( + MimetypeMap.MIMETYPE_IMAGE_JPEG, + imageTransformationOptions4, + "half2"); + NodeRef thumbnail4 = this.thumbnailService.createThumbnail(gifOrig, ContentModel.PROP_CONTENT, createOptions4); + checkThumbnailed(gifOrig, "half2"); + checkThumbnail(thumbnail4, imageTransformationOptions4); + outputThumbnailTempContentLocation(thumbnail4, "jpg", "half2 - 50%x50%, from gif"); + + } + + public void testDuplicationNames() + throws Exception + { + NodeRef jpgOrig = createOrigionalContent(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); + CreateOptions createOptions = new CreateOptions( + MimetypeMap.MIMETYPE_IMAGE_JPEG, + imageTransformationOptions, + "small"); + NodeRef thumbnail1 = this.thumbnailService.createThumbnail(jpgOrig, ContentModel.PROP_CONTENT, createOptions); + assertNotNull(thumbnail1); + checkThumbnailed(jpgOrig, "small"); + checkThumbnail(thumbnail1, imageTransformationOptions); + + try + { + this.thumbnailService.createThumbnail(jpgOrig, ContentModel.PROP_CONTENT, createOptions); + fail("A duplicate exception should have been raised"); + } + catch (ThumbnailException exception) + { + // OK since this should have been thrown + } + } + + public void testThumbnailUpdate() + throws Exception + { + // First create a thumbnail + NodeRef jpgOrig = createOrigionalContent(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); + CreateOptions createOptions = new CreateOptions( + MimetypeMap.MIMETYPE_IMAGE_JPEG, + imageTransformationOptions, + "small"); + NodeRef thumbnail1 = this.thumbnailService.createThumbnail(jpgOrig, ContentModel.PROP_CONTENT, createOptions); + + // Update the thumbnail + this.thumbnailService.updateThumbnail(thumbnail1); + + + } + + public void testGetThumbnailByName() + throws Exception + { + NodeRef jpgOrig = createOrigionalContent(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.setResizeToThumbnail(true); + ImageTransformationOptions imageTransformationOptions = new ImageTransformationOptions(); + imageTransformationOptions.setResizeOptions(imageResizeOptions); + CreateOptions createOptions = new CreateOptions( + MimetypeMap.MIMETYPE_IMAGE_JPEG, + imageTransformationOptions, + "small"); + this.thumbnailService.createThumbnail(jpgOrig, ContentModel.PROP_CONTENT, createOptions); + + // Try and retrieve the thumbnail + NodeRef result2 = this.thumbnailService.getThumbnailByName(jpgOrig, ContentModel.PROP_CONTENT, "small"); + assertNotNull(result2); + checkThumbnail(result2, imageTransformationOptions); + + // 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) + { + assertTrue("Thumbnailed aspect should have been applied", this.nodeService.hasAspect(thumbnailed, ContentModel.ASPECT_THUMBNAILED)); + List 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(NodeRef thumbnail, TransformationOptions transformationOptions) + { + // Check the thumbnail is of the correct type + assertEquals(ContentModel.TYPE_THUMBNAIL, this.nodeService.getType(thumbnail)); + + // Check the meta data on the thumnail + assertEquals(ContentModel.PROP_CONTENT, this.nodeService.getProperty(thumbnail, ContentModel.PROP_CONTENT_PROPERTY_NAME)); + assertEquals(transformationOptions.getClass().getName(), this.nodeService.getProperty(thumbnail, ContentModel.PROP_TRANSFORMATION_OPTIONS_CLASS)); + + if (transformationOptions instanceof ImageTransformationOptions) + { + ImageTransformationOptions imageTransformationOptions = (ImageTransformationOptions)transformationOptions; + assertTrue(this.nodeService.hasAspect(thumbnail, ImageTransformationOptions.ASPECT_IMAGE_TRANSFORATION_OPTIONS)); + assertEquals( + imageTransformationOptions.getCommandOptions(), + this.nodeService.getProperty(thumbnail, ImageTransformationOptions.PROP_COMMAND_OPTIONS)); + ImageResizeOptions resizeOptions = imageTransformationOptions.getResizeOptions(); + if (resizeOptions != null) + { + assertTrue((Boolean)this.nodeService.getProperty(thumbnail, ImageTransformationOptions.PROP_RESIZE)); + assertEquals( + imageTransformationOptions.getResizeOptions().getHeight(), + this.nodeService.getProperty(thumbnail, ImageTransformationOptions.PROP_RESIZE_HEIGHT)); + assertEquals( + imageTransformationOptions.getResizeOptions().getWidth(), + this.nodeService.getProperty(thumbnail, ImageTransformationOptions.PROP_RESIZE_WIDTH)); + assertEquals( + imageTransformationOptions.getResizeOptions().isMaintainAspectRatio(), + this.nodeService.getProperty(thumbnail, ImageTransformationOptions.PROP_RESIZE_MAINTAIN_ASPECT_RATIO)); + assertEquals( + imageTransformationOptions.getResizeOptions().isPercentResize(), + this.nodeService.getProperty(thumbnail, ImageTransformationOptions.PROP_RESIZE_PERCENT)); + assertEquals( + imageTransformationOptions.getResizeOptions().isResizeToThumbnail(), + this.nodeService.getProperty(thumbnail, ImageTransformationOptions.PROP_RESIZE_TO_THUMBNAIL)); + } + else + { + assertFalse((Boolean)this.nodeService.getProperty(thumbnail, ImageTransformationOptions.PROP_RESIZE)); + } + + } + } + + 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()); + } + + private NodeRef createOrigionalContent(NodeRef folder, String mimetype) + throws IOException + { + String ext = this.mimetypeMap.getExtension(mimetype); + File origFile = AbstractContentTransformerTest.loadQuickTestFile(ext); + + Map props = new HashMap(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(); + + ContentWriter writer = this.contentService.getWriter(node, ContentModel.PROP_CONTENT, true); + writer.setMimetype(mimetype); + writer.setEncoding("UTF-8"); + writer.putContent(origFile); + + return node; } } diff --git a/source/java/org/alfresco/service/cmr/repository/TransformationOptions.java b/source/java/org/alfresco/service/cmr/repository/TransformationOptions.java index 6435ccf168..206929d912 100644 --- a/source/java/org/alfresco/service/cmr/repository/TransformationOptions.java +++ b/source/java/org/alfresco/service/cmr/repository/TransformationOptions.java @@ -206,5 +206,29 @@ public class TransformationOptions this.sourceContentProperty = (QName)optionsMap.get(OPT_SOURCE_CONTENT_PROPERTY); this.targetNodeRef = (NodeRef)optionsMap.get(OPT_TARGET_NODEREF); this.targetContentProperty = (QName)optionsMap.get(OPT_TARGET_CONTENT_PROPERTY); - } + } + + /** + * Save the transformation options to the given node by applying the appropriate aspect + * and setting the meta data from the transformation options + * + * @param nodeRef the node reference + * @param nodeService the node service + */ + public void saveToNode(NodeRef nodeRef, NodeService nodeService) + { + // Do nothing for default transformation options + } + + /** + * Populate the transformation options from the meta data present on the appropraite + * aspect on the passed node. + * + * @param nodeRef the node reference + * @param nodeService the node service + */ + public void populateFromNode(NodeRef nodeRef, NodeService nodeService) + { + // Do nothing for the detauls transformation options + } } diff --git a/source/java/org/alfresco/service/cmr/thumbnail/GenerateOptions.java b/source/java/org/alfresco/service/cmr/thumbnail/CreateOptions.java similarity index 64% rename from source/java/org/alfresco/service/cmr/thumbnail/GenerateOptions.java rename to source/java/org/alfresco/service/cmr/thumbnail/CreateOptions.java index 3b522b9561..35b7fd2486 100644 --- a/source/java/org/alfresco/service/cmr/thumbnail/GenerateOptions.java +++ b/source/java/org/alfresco/service/cmr/thumbnail/CreateOptions.java @@ -25,15 +25,16 @@ package org.alfresco.service.cmr.thumbnail; import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.TransformationOptions; import org.alfresco.service.namespace.QName; import org.alfresco.util.ParameterCheck; /** - * This class provides the thumbnail generate options to the thumbnail service. + * This class provides the thumbnail create options to the thumbnail service. * * @author Roy Wetherall */ -public class GenerateOptions +public class CreateOptions { /** Parent association details */ private ParentAssociationDetails assocDetails; @@ -41,11 +42,19 @@ public class GenerateOptions /** Name of the thumbnail */ private String thumbnailName; + /** The destination mimetype */ + private String destinationMimetype; + + /** Transformation options */ + private TransformationOptions options; + /** * Default constructor. */ - public GenerateOptions() + public CreateOptions(String destinationMimetype, TransformationOptions options) { + this.destinationMimetype = destinationMimetype; + this.options = options; } /** @@ -53,8 +62,9 @@ public class GenerateOptions * * @param thumbnailName the name of the thumbnail, can be null */ - public GenerateOptions(String thumbnailName) + public CreateOptions(String destinationMimetype, TransformationOptions options, String thumbnailName) { + this(destinationMimetype, options); this.thumbnailName= thumbnailName; } @@ -66,9 +76,60 @@ public class GenerateOptions * @param assocType the child association type * @param asscoName the child association name */ - public GenerateOptions(String thumbnailName, NodeRef parent, QName assocType, QName assocName) + public CreateOptions(String destinationMimetype, TransformationOptions options, String thumbnailName, + NodeRef parent, QName assocType, QName assocName) + { + this(destinationMimetype, options, thumbnailName); + this.assocDetails = new ParentAssociationDetails(parent, assocType, assocName); + } + + /** + * Set the destination mimetype + * + * @param destinationMimetype the destination minetype + */ + public void setDestinationMimetype(String destinationMimetype) + { + this.destinationMimetype = destinationMimetype; + } + + /** + * Get the destination mimetype + * + * @return the destination mimetype + */ + public String getDestinationMimetype() + { + return destinationMimetype; + } + + /** + * Set the transformation options + * + * @param options the transformation options + */ + public void setTransformationOptions(TransformationOptions options) + { + this.options = options; + } + + /** + * Get the transformation options + * + * @return the transformation options + */ + public TransformationOptions getTransformationOptions() + { + return options; + } + + /** + * Sets the name of the thumbnail + * + * @param thumbnailName the thumbnail name + */ + public void setThumbnailName(String thumbnailName) { - this.assocDetails = new ParentAssociationDetails(parent, assocType, assocName); this.thumbnailName = thumbnailName; } @@ -80,6 +141,16 @@ public class GenerateOptions public String getThumbnailName() { return thumbnailName; + } + + /** + * Sets the details of the thumnails parent association + * + * @param assocDetails the parent association details + */ + public void setParentAssociationDetails(ParentAssociationDetails assocDetails) + { + this.assocDetails = assocDetails; } /** diff --git a/source/java/org/alfresco/service/cmr/thumbnail/AcceptOptions.java b/source/java/org/alfresco/service/cmr/thumbnail/ThumbnailException.java similarity index 60% rename from source/java/org/alfresco/service/cmr/thumbnail/AcceptOptions.java rename to source/java/org/alfresco/service/cmr/thumbnail/ThumbnailException.java index 5e8e1fd8c6..5ec2c442b5 100644 --- a/source/java/org/alfresco/service/cmr/thumbnail/AcceptOptions.java +++ b/source/java/org/alfresco/service/cmr/thumbnail/ThumbnailException.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2008 Alfresco Software Limited. + * Copyright (C) 2005-2007 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 @@ -24,11 +24,37 @@ */ package org.alfresco.service.cmr.thumbnail; +import org.alfresco.error.AlfrescoRuntimeException; /** + * Thumbnail service exception class + * * @author Roy Wetherall */ -public class AcceptOptions +public class ThumbnailException extends AlfrescoRuntimeException { + /** + * Serial version UID + */ + private static final long serialVersionUID = 3257571685241467958L; + public ThumbnailException(String msgId) + { + super(msgId); + } + + public ThumbnailException(String msgId, Object[] msgParams) + { + super(msgId, msgParams); + } + + public ThumbnailException(String msgId, Object[] msgParams, Throwable cause) + { + super(msgId, msgParams, cause); + } + + public ThumbnailException(String msgId, Throwable cause) + { + super(msgId, cause); + } } diff --git a/source/java/org/alfresco/service/cmr/thumbnail/ThumbnailService.java b/source/java/org/alfresco/service/cmr/thumbnail/ThumbnailService.java index 54d38d694a..c3f18dc6ca 100644 --- a/source/java/org/alfresco/service/cmr/thumbnail/ThumbnailService.java +++ b/source/java/org/alfresco/service/cmr/thumbnail/ThumbnailService.java @@ -28,6 +28,7 @@ import java.util.List; import org.alfresco.service.Auditable; import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.TransformationOptions; import org.alfresco.service.namespace.QName; /** @@ -57,7 +58,7 @@ public interface ThumbnailService * @return NodeRef node reference to the newly created thumbnail */ @Auditable(key = Auditable.Key.ARG_0, parameters = {"node", "contentProperty", "createOptions"}) - NodeRef createThumbnail(NodeRef node, QName contentProperty, GenerateOptions createOptions); + NodeRef createThumbnail(NodeRef node, QName contentProperty, CreateOptions createOptions); /** * Updates the content of a thumbnail. @@ -73,25 +74,37 @@ public interface ThumbnailService void updateThumbnail(NodeRef thumbnail); /** - * Gets a list of the thumbnails that are available for the node's content property, given a - * the accept options. * - * The accept options contain details about the desired mimetypes, size and other parameters of - * a potential thumbnail. If any of the nodes thumbnails match these accept options they are - * added to the return list. - * - * The list of returned thumbnails is ordered, with the most appropriate thumbnail first. If no - * appropriate thumbnails are found then the list is returned empty. - * - * When no accept options are provided all available thumbnails are returned. - * - * @see org.alfresco.service.cmr.thumbnail.AcceptOptions - * - * @param node the content node - * @param contentProperty the content property - * @param acceptOptions the accept options - * @return List list of thumbnails that match the accept options + * @param node + * @param contentProperty + * @param thumbnailName + * @return */ - @Auditable(key = Auditable.Key.ARG_0, parameters = {"node", "contentProperty", "acceptOptions"}) - List getThumbnails(NodeRef node, QName contentProperty, AcceptOptions acceptOptions); + @Auditable(key = Auditable.Key.ARG_0, parameters = {"node", "contentProperty", "thumbnailName"}) + NodeRef getThumbnailByName(NodeRef node, QName contentProperty, String thumbnailName); + + /** + * + * @param node + * @param contentProperty + * @param mimetype + * @param options + * @return + */ + @Auditable(key = Auditable.Key.ARG_0, parameters = {"node", "contentProperty", "mimetype", "options"}) + List getThumbnails(NodeRef node, QName contentProperty, String mimetype, TransformationOptions options); + + /** + * @see ThumbnailService#getThumbnails(NodeRef, QName, String, TransformationOptions) + * + * Transformation options defaulted to null. + * + * @param node + * @param contentProperty + * @param mimetype + * @return + */ + @Auditable(key = Auditable.Key.ARG_0, parameters = {"node", "contentProperty", "mimetype"}) + List getThumbnails(NodeRef node, QName contentProperty, String mimetype); + }