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);
+
}