</filterset>\r
</copy>\r
<ant antfile="nuxeo-platform-collectionspace/build.xml" target="deploy" inheritall="false"/>\r
+ <ant antfile="nuxeo-platform-thumbnail/build.xml" target="deploy" inheritall="false"/>\r
</target>\r
\r
<target name="undeploy"\r
<ant antfile="nuxeo-platform-collectionspace/build.xml" target="undeploy" inheritall="false"/>\r
<ant antfile="nuxeo-platform-quote/build.xml" target="undeploy" inheritall="false"/>\r
<ant antfile="nuxeo-platform-quote-api/build.xml" target="undeploy" inheritall="false"/>\r
+ <ant antfile="nuxeo-platform-thumbnail/build.xml" target="undeploy" inheritall="false"/>\r
</target>\r
\r
<target name="dist"\r
<schema name="subitem" />
</doctype>
</extension>
-
- <!-- Support for creation of document/blob thumbnails. All of this code was take from the following two
- blog posts:
- http://dev.blogs.nuxeo.com/2012/06/qa-friday-thumbnails-pdf-psd-documents.html
- http://dev.blogs.nuxeo.com/2012/06/monday-dev-heaven-adding-thumbnail-preview-document-content-nuxeo.html
- -->
- <extension target="org.nuxeo.ecm.core.schema.TypeService"
- point="schema">
- <schema name="thumbnail" src="schemas/thumbnail.xsd" prefix="thumb" />
- </extension>
- <extension target="org.nuxeo.ecm.core.schema.TypeService"
- point="doctype">
- <facet name="Thumbnail">
- <schema name="thumbnail" />
- </facet>
- </extension>
- <extension target="org.nuxeo.ecm.platform.commandline.executor.service.CommandLineExecutorComponent" point="command">
- <command name="toThumbnail" enabled="true">
- <commandLine>convert</commandLine>
- <parameterString>-strip -thumbnail 100x100 -background transparent -gravity center -extent 100x100 -format png -quality 75 #{inputFilePath}[0] #{outputFilePath}</parameterString>
- <winParameterString>-strip -thumbnail 100x100 -background transparent -gravity center -extent 100x100 -format png -quality 75 #{inputFilePath}[0] #{outputFilePath}</winParameterString>
- <installationDirective>You need to install ImageMagick.</installationDirective>
- </command>
- </extension>
- <extension target="org.nuxeo.ecm.core.convert.service.ConversionServiceImpl" point="converter">
- <converter name="toThumbnail" class="org.collectionspace.services.common.imaging.nuxeo.ThumbnailConverter">
- </converter>
- </extension>
</component>
--- /dev/null
+package org.collectionspace.services.nuxeo.extension.thumbnail;
+
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.security.NoSuchAlgorithmException;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.nuxeo.ecm.core.api.Blob;
+import org.nuxeo.ecm.core.api.ClientException;
+import org.nuxeo.ecm.core.api.CoreSession;
+import org.nuxeo.ecm.core.api.DocumentModel;
+import org.nuxeo.ecm.core.api.UnrestrictedSessionRunner;
+import org.nuxeo.ecm.core.api.blobholder.BlobHolder;
+import org.nuxeo.ecm.core.convert.api.ConversionService;
+import org.nuxeo.ecm.platform.filemanager.api.FileManager;
+import org.nuxeo.runtime.api.Framework;
+
+public class AddThumbnailUnrestricted extends UnrestrictedSessionRunner {
+
+ private static final Log logger = LogFactory
+ .getLog(AddThumbnailUnrestricted.class);
+
+ protected ConversionService cs;
+
+ protected DocumentModel doc;
+
+ protected BlobHolder blobHolder;
+
+ protected Thumbnail thumbnail = null;
+
+ public AddThumbnailUnrestricted(CoreSession coreSession, DocumentModel doc,
+ BlobHolder blobHolder) {
+ super(coreSession);
+ this.doc = doc;
+ this.blobHolder = blobHolder;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.nuxeo.ecm.core.api.UnrestrictedSessionRunner#run()
+ *
+ * Creates a new thumbnail image and associates it with the document blob by adding a "Thumnail" facet
+ * to the document blob.
+ */
+ @Override
+ public void run() throws ClientException {
+ String errMsg = "Error while adding preview thumbnail.";
+ String documentId = doc.getId();
+
+ try {
+ Blob blob = blobHolder.getBlob();
+ if (blob != null) {
+ if (doc.hasFacet(ThumbnailConstants.THUMBNAIL_FACET) == false) { // Make sure we don't already have a "Thumbnail" facet
+ cs = Framework.getService(ConversionService.class);
+ ensureModificationDateExists(doc); // For some reason, the ConversionService service requires the modification date of the blob is not null so we need to ensure it is not null.
+ BlobHolder thumbnailBlobHolder = cs.convert(ThumbnailConstants.THUMBNAIL_CONVERTER_NAME,
+ blobHolder, null /*no params*/);
+ if (thumbnailBlobHolder != null && thumbnailBlobHolder.getBlob() != null) {
+ Blob thumbnailBlob = thumbnailBlobHolder.getBlob();
+ doc.addFacet(ThumbnailConstants.THUMBNAIL_FACET); // Add the "Thumbnail" facet since we were able to create a thumnail image
+ // Give the thumbnail blob a name.
+ String thumbnailName = documentId + ThumbnailConstants.THUMBNAIL_PROPERTY_NAME;
+ thumbnailBlobHolder.getBlob().setFilename(thumbnailName); // Give it a name so we can manually search for it in the "nuxeo" database
+
+ doc.setProperty(ThumbnailConstants.THUMBNAIL_SCHEMA_NAME,
+ ThumbnailConstants.THUMBNAIL_FILENAME_PROPERTY_NAME,
+ (Serializable) thumbnailName);
+ doc.setProperty(ThumbnailConstants.THUMBNAIL_SCHEMA_NAME,
+ ThumbnailConstants.THUMBNAIL_PROPERTY_NAME,
+ (Serializable) thumbnailBlob);
+ //
+ // Save the new Thumnail facet data (including the new thumbnail image). The save triggers a new create event and recurses us back to
+ // this method, but the next time we'll have a Thumbnail facet and bypass this save -sparing us from an infinite event loop.
+ //
+ doc = session.saveDocument(doc);
+ } else {
+ logger.warn("Could not create a preview thumbnail image for Nuxeo blob document: " + doc.getId());
+ }
+ }
+ } else {
+ logger.warn(errMsg + " " + "The Nuxeo blob holder had an empty blob object. Document ID:" + doc.getId());
+ }
+ } catch (Exception e) {
+ logger.warn(errMsg, e);
+ }
+ }
+
+ private String computeDigest(FileManager fileManager, Blob blob) throws Exception {
+ String result = null;
+
+ // Compute the digest
+ result = fileManager.computeDigest(blob); // REM - Warning: Why is this operation so slow?
+
+ return result;
+ }
+
+ private String ensureModificationDateExists(DocumentModel docModel) throws Exception {
+ Calendar modificationDate = (Calendar)doc.getProperty("dublincore", "modified");
+ if (modificationDate == null) {
+ // If the 'modified' field is null then try the 'created' field
+ Calendar creationDate = (Calendar)doc.getProperty("dublincore", "created");
+ if (creationDate != null) {
+ modificationDate = creationDate;
+ } else {
+ // We *need* a 'modified' date, so let's use the current date
+ modificationDate = new GregorianCalendar();
+ }
+ doc.setProperty("dublincore", "modified", modificationDate);
+ }
+
+ return modificationDate.toString();
+ }
+
+ public Thumbnail getAdapter() {
+ return thumbnail;
+ }
+
+}
--- /dev/null
+package org.collectionspace.services.nuxeo.extension.thumbnail;
+
+public class ThumbnailConstants {
+ public static final String THUMBNAIL_SIZE_PARAMETER_NAME = "size";
+ public static final String THUMBNAIL_DEFAULT_SIZE = "200";
+ public static final String THUMBNAIL_FACET = "Thumbnail";
+ public static final String THUMBNAIL_SCHEMA_NAME = "thumbnail";
+ public static final String THUMBNAIL_PROPERTY_NAME = "thumbnail";
+ public static final String THUMBNAIL_DIGEST_PROPERTY_NAME = "digest";
+ public static final String THUMBNAIL_FILENAME_PROPERTY_NAME = "fileName";
+ public static final String THUMBNAIL_CONVERTER_NAME = "toThumbnail";
+}
-package org.collectionspace.services.common.imaging.nuxeo;
+package org.collectionspace.services.nuxeo.extension.thumbnail;
import java.io.File;
import java.io.Serializable;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+
import org.nuxeo.ecm.core.api.Blob;
import org.nuxeo.ecm.core.api.blobholder.BlobHolder;
import org.nuxeo.ecm.core.api.impl.blob.FileBlob;
+import org.nuxeo.ecm.core.api.impl.blob.StreamingBlob;
import org.nuxeo.ecm.core.convert.api.ConversionException;
import org.nuxeo.ecm.core.convert.cache.SimpleCachableBlobHolder;
import org.nuxeo.ecm.core.convert.extension.Converter;
import org.nuxeo.ecm.platform.commandline.executor.api.CommandLineExecutorService;
import org.nuxeo.ecm.platform.commandline.executor.api.ExecResult;
import org.nuxeo.ecm.platform.picture.core.im.IMImageUtils;
+
import org.nuxeo.runtime.api.Framework;
import org.nuxeo.runtime.services.streaming.FileSource;
import org.nuxeo.runtime.services.streaming.StreamSource;
public class ThumbnailConverter extends IMImageUtils implements Converter {
- private static final Log log = LogFactory.getLog(ThumbnailConverter.class);
+ private static final Log logger = LogFactory.getLog(ThumbnailConverter.class);
@Override
public BlobHolder convert(BlobHolder blobHolder,
StreamSource source = ((SQLBlob) blob).getBinary()
.getStreamSource();
inputFile = ((FileSource) source).getFile();
+ } else if (blob instanceof StreamingBlob) {
+ StreamingBlob streamingBlob = ((StreamingBlob) blob);
+ if (!streamingBlob.isPersistent()) {
+ streamingBlob.persist();
+ }
+ StreamSource source = streamingBlob.getStreamSource();
+ inputFile = ((FileSource) source).getFile();
}
if (inputFile == null) {
- return null;
+ return null; // Add a log message here
}
CmdParameters params = new CmdParameters();
File outputFile = File.createTempFile("nuxeoImageTarget", "."
+ "png");
+ String size = ThumbnailConstants.THUMBNAIL_DEFAULT_SIZE;
+ if (parameters != null) {
+ if (parameters.containsKey(ThumbnailConstants.THUMBNAIL_SIZE_PARAMETER_NAME)) {
+ size = (String) parameters.get(ThumbnailConstants.THUMBNAIL_SIZE_PARAMETER_NAME);
+ }
+ }
+ params.addNamedParameter(ThumbnailConstants.THUMBNAIL_SIZE_PARAMETER_NAME, size);
params.addNamedParameter("inputFilePath", inputFile);
params.addNamedParameter("outputFilePath", outputFile);
Framework.trackFile(outputFile, targetBlob);
return new SimpleCachableBlobHolder(targetBlob);
} catch (Exception e) {
+ logger.trace("Could not create a thumbnail image using the Nuxeo conversion service", e);
throw new ConversionException("Thumbnail conversion has failed", e);
}
}
--- /dev/null
+package org.collectionspace.services.nuxeo.extension.thumbnail;
+
+import org.nuxeo.ecm.core.api.Blob;
+import org.nuxeo.ecm.core.api.ClientException;
+import org.nuxeo.ecm.core.api.DocumentModel;
+import org.nuxeo.ecm.core.api.blobholder.BlobHolder;
+import org.nuxeo.ecm.core.api.event.DocumentEventTypes;
+import org.nuxeo.ecm.core.event.Event;
+import org.nuxeo.ecm.core.event.EventContext;
+import org.nuxeo.ecm.core.event.EventListener;
+import org.nuxeo.ecm.core.event.impl.DocumentEventContext;
+
+public class UpdateThumbListener implements EventListener {
+
+ public void handleEvent(Event event) throws ClientException {
+ EventContext ec = event.getContext();
+ if (ec instanceof DocumentEventContext) {
+ DocumentEventContext context = (DocumentEventContext) ec;
+ DocumentModel doc = context.getSourceDocument();
+ if (doc.isDirty() || DocumentEventTypes.DOCUMENT_CREATED.equals(event.getName())) {
+ BlobHolder blobHolder = doc.getAdapter(BlobHolder.class);
+ if (blobHolder != null) {
+ Blob blob = blobHolder.getBlob();
+ if (blob != null) {
+ try {
+ AddThumbnailUnrestricted runner = new AddThumbnailUnrestricted(
+ context.getCoreSession(), doc, blobHolder);
+ runner.runUnrestricted();
+ return; // Exit
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+ // No Blob anymore, remove the facet
+ if (doc.hasFacet(ThumbnailConstants.THUMBNAIL_FACET)) {
+ doc.removeFacet(ThumbnailConstants.THUMBNAIL_FACET);
+ context.getCoreSession().saveDocument(doc);
+ }
+ }
+ }
+ }
+}
-<?xml version="1.0" encoding="UTF-8"?>\r
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">\r
-\r
- <parent>\r
- <groupId>org.collectionspace.services</groupId>\r
- <artifactId>org.collectionspace.services.3rdparty</artifactId>\r
- <version>2.6-SNAPSHOT</version>\r
- </parent>\r
-\r
- <modelVersion>4.0.0</modelVersion>\r
- <groupId>org.collectionspace.services</groupId>\r
- <artifactId>org.collectionspace.services.3rdparty.nuxeo</artifactId>\r
- <packaging>pom</packaging>\r
- <name>services.3rdparty.nuxeo</name>\r
-\r
- <modules>\r
- <module>nuxeo-platform-collectionspace</module>\r
- <module>nuxeo-platform-quote-api</module>\r
- <module>nuxeo-platform-quote</module>\r
- </modules>\r
-\r
- <dependencies>\r
- <dependency>\r
- <groupId>org.osgi</groupId>\r
- <artifactId>org.osgi.core</artifactId>\r
- <version>4.1.0</version>\r
- </dependency>\r
- <!-- jboss -->\r
- <dependency>\r
- <groupId>org.jboss.remoting</groupId>\r
- <artifactId>jboss-remoting</artifactId>\r
- <scope>provided</scope>\r
- </dependency>\r
- </dependencies>\r
-\r
-</project>\r
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+ <parent>
+ <groupId>org.collectionspace.services</groupId>
+ <artifactId>org.collectionspace.services.3rdparty</artifactId>
+ <version>2.6-SNAPSHOT</version>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.collectionspace.services</groupId>
+ <artifactId>org.collectionspace.services.3rdparty.nuxeo</artifactId>
+ <packaging>pom</packaging>
+ <name>services.3rdparty.nuxeo</name>
+
+ <modules>
+ <module>nuxeo-platform-collectionspace</module>
+ <module>nuxeo-platform-quote-api</module>
+ <module>nuxeo-platform-quote</module>
+ <module>nuxeo-platform-thumbnail</module>
+ </modules>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ <version>4.1.0</version>
+ </dependency>
+ <!-- jboss -->
+ <dependency>
+ <groupId>org.jboss.remoting</groupId>
+ <artifactId>jboss-remoting</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+
+</project>
\ No newline at end of file
<artifactId>org.collectionspace.services.config</artifactId>\r
<version>${project.version}</version>\r
</dependency> \r
+ <dependency>\r
+ <groupId>org.collectionspace.services</groupId>\r
+ <artifactId>org.collectionspace.services.3rdparty.nuxeo.thumbnail</artifactId>\r
+ <version>${project.version}</version>\r
+ </dependency> \r
<dependency>\r
<groupId>org.collectionspace.services</groupId>\r
<artifactId>org.collectionspace.services.common-api</artifactId>\r
//import org.collectionspace.services.blob.BlobsCommonList.BlobListItem;\r
import org.collectionspace.services.jaxb.BlobJAXBSchema;\r
import org.collectionspace.services.nuxeo.client.java.CommonList;\r
+import org.collectionspace.services.nuxeo.extension.thumbnail.ThumbnailConstants;\r
import org.collectionspace.services.common.blob.BlobOutput;\r
\r
import org.collectionspace.services.config.service.ListResultField;\r
if (measuredPartGroupList != null) {\r
result.setMeasuredPartGroupList(measuredPartGroupList);\r
}\r
+ \r
+ // Check to see if a thumbnail preview was created by Nuxeo\r
+ if (documentModel.hasFacet(ThumbnailConstants.THUMBNAIL_FACET)) {\r
+ String errorMsg = null;\r
+ String thumbnailName = null;\r
+ try {\r
+ thumbnailName = (String)documentModel.getProperty(ThumbnailConstants.THUMBNAIL_SCHEMA_NAME,\r
+ ThumbnailConstants.THUMBNAIL_FILENAME_PROPERTY_NAME);\r
+ Blob thumbnailBlob = (Blob)documentModel.getProperty(ThumbnailConstants.THUMBNAIL_SCHEMA_NAME,\r
+ ThumbnailConstants.THUMBNAIL_PROPERTY_NAME);\r
+ } catch (ClientException e) {\r
+ errorMsg = "Could not extract the name of the thumbnail preview image file.";\r
+ if (logger.isTraceEnabled()) {\r
+ logger.trace(errorMsg, e);\r
+ }\r
+ }\r
+ \r
+ if (errorMsg == null) {\r
+ logger.info("A thumbnail preview was created for this document blob: " + thumbnailName);\r
+ } else {\r
+ logger.warn(errorMsg);\r
+ }\r
+ }\r
}\r
\r
return result;\r