diff --git a/config/alfresco/application-context.xml b/config/alfresco/application-context.xml index f59f7d08aa..6a9fdf53e8 100644 --- a/config/alfresco/application-context.xml +++ b/config/alfresco/application-context.xml @@ -40,6 +40,7 @@ + diff --git a/config/alfresco/content-services-context.xml b/config/alfresco/content-services-context.xml index f0f88effb5..beb3c1571e 100644 --- a/config/alfresco/content-services-context.xml +++ b/config/alfresco/content-services-context.xml @@ -190,16 +190,16 @@ + parent="baseContentTransformer" /> - - application/pdf - text/plain + + application/pdf + text/plain @@ -210,7 +210,7 @@ parent="baseContentTransformer" > - + text/plain application/pdf @@ -227,9 +227,9 @@ parent="baseContentTransformer" > - - application/msword - text/plain + + application/msword + text/plain diff --git a/config/alfresco/model/contentModel.xml b/config/alfresco/model/contentModel.xml index d74b5ae624..3671ca43cd 100644 --- a/config/alfresco/model/contentModel.xml +++ b/config/alfresco/model/contentModel.xml @@ -309,6 +309,20 @@ sys:localized + + + + Thumbnail + cm:content + true + + + Thumbnail Options + d:any + false + + + @@ -816,6 +830,25 @@ cm:mlDocument + + + + Thumbnailed + + + + false + true + + + cm:thumbnail + false + true + + + + + diff --git a/config/alfresco/thumbnail-service-context.xml b/config/alfresco/thumbnail-service-context.xml new file mode 100644 index 0000000000..c347cab330 --- /dev/null +++ b/config/alfresco/thumbnail-service-context.xml @@ -0,0 +1,45 @@ + + + + + + + + + org.alfresco.service.cmr.thumbnail.ThumbnailService + + + + + + + + + + + + + + + + + + + + + + ${server.transaction.mode.default} + + + + + + + + + + + + + + diff --git a/source/java/org/alfresco/model/ContentModel.java b/source/java/org/alfresco/model/ContentModel.java index 934e4b9688..93c1be001c 100644 --- a/source/java/org/alfresco/model/ContentModel.java +++ b/source/java/org/alfresco/model/ContentModel.java @@ -237,6 +237,13 @@ public interface ContentModel static final QName ASSOC_MULTILINGUAL_CHILD = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "mlChild"); static final QName ASPECT_MULTILINGUAL_DOCUMENT = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "mlDocument"); static final QName ASPECT_MULTILINGUAL_EMPTY_TRANSLATION = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "mlEmptyTranslation"); + + // Thumbnail Type + static final QName TYPE_THUMBNAIL = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "thumbnail"); + + // Thumbnailed Aspect + static final QName ASPECT_THUMBNAILED = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "thumbnailed"); + static final QName ASSOC_THUMBNAILS = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "thumbnails"); // // User Model Definitions diff --git a/source/java/org/alfresco/repo/action/executer/ImageTransformActionExecuter.java b/source/java/org/alfresco/repo/action/executer/ImageTransformActionExecuter.java index 8b3ba4b09f..f85c7a1a26 100644 --- a/source/java/org/alfresco/repo/action/executer/ImageTransformActionExecuter.java +++ b/source/java/org/alfresco/repo/action/executer/ImageTransformActionExecuter.java @@ -24,12 +24,11 @@ */ package org.alfresco.repo.action.executer; -import java.util.HashMap; import java.util.List; -import java.util.Map; import org.alfresco.repo.action.ParameterDefinitionImpl; import org.alfresco.repo.content.transform.magick.ImageMagickContentTransformer; +import org.alfresco.repo.content.transform.magick.ImageTransformationOptions; import org.alfresco.service.cmr.action.Action; import org.alfresco.service.cmr.action.ParameterDefinition; import org.alfresco.service.cmr.dictionary.DataTypeDefinition; @@ -85,9 +84,9 @@ public class ImageTransformActionExecuter extends TransformActionExecuter // Try and transform the content String convertCommand = (String)ruleAction.getParameterValue(PARAM_CONVERT_COMMAND); // create some options for the transform - Map options = new HashMap(5); - options.put(ImageMagickContentTransformer.KEY_OPTIONS, convertCommand); + ImageTransformationOptions imageOptions = new ImageTransformationOptions(); + imageOptions.setCommandOptions(convertCommand); - this.imageMagickContentTransformer.transform(contentReader, contentWriter, options); + this.imageMagickContentTransformer.transform(contentReader, contentWriter, imageOptions); } } diff --git a/source/java/org/alfresco/repo/action/executer/TransformActionExecuter.java b/source/java/org/alfresco/repo/action/executer/TransformActionExecuter.java index a1f2926c57..acb16641cd 100644 --- a/source/java/org/alfresco/repo/action/executer/TransformActionExecuter.java +++ b/source/java/org/alfresco/repo/action/executer/TransformActionExecuter.java @@ -24,9 +24,7 @@ */ package org.alfresco.repo.action.executer; -import java.util.HashMap; import java.util.List; -import java.util.Map; import org.alfresco.model.ContentModel; import org.alfresco.repo.action.ParameterDefinitionImpl; @@ -45,6 +43,7 @@ import org.alfresco.service.cmr.repository.MimetypeService; import org.alfresco.service.cmr.repository.NoTransformerException; 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.cmr.rule.RuleServiceException; import org.alfresco.service.namespace.QName; import org.apache.commons.logging.Log; @@ -186,14 +185,6 @@ public class TransformActionExecuter extends ActionExecuterAbstractBase // Get the mime type String mimeType = (String)ruleAction.getParameterValue(PARAM_MIME_TYPE); - // Check that a transformer is available to the transformation before we go any further - ContentTransformer contentTransformer = this.transformerRegistry.getTransformer(sourceMimeType, mimeType); - if (contentTransformer == null) - { - // Throw an exception since the transformer is not present - throw new NoTransformerException(sourceMimeType, mimeType); - } - // Get the details of the copy destination NodeRef destinationParent = (NodeRef)ruleAction.getParameterValue(PARAM_DESTINATION_FOLDER); QName destinationAssocTypeQName = (QName)ruleAction.getParameterValue(PARAM_ASSOC_TYPE_QNAME); @@ -314,13 +305,9 @@ public class TransformActionExecuter extends ActionExecuterAbstractBase throw new NoTransformerException(contentReader.getMimetype(), contentWriter.getMimetype()); } - // build map of options - Map options = new HashMap(2); - options.put(ContentTransformer.OPT_SOURCE_NODEREF, sourceNodeRef); - options.put(ContentTransformer.OPT_DESTINATION_NODEREF, destinationNodeRef); - // transform - this.contentService.transform(contentReader, contentWriter, options); + TransformationOptions options = new TransformationOptions(sourceNodeRef, ContentModel.PROP_NAME, destinationNodeRef, ContentModel.PROP_NAME); + this.contentService.transform(contentReader, contentWriter, options); } /** diff --git a/source/java/org/alfresco/repo/content/RoutingContentService.java b/source/java/org/alfresco/repo/content/RoutingContentService.java index d0433402be..fdb13d6f85 100644 --- a/source/java/org/alfresco/repo/content/RoutingContentService.java +++ b/source/java/org/alfresco/repo/content/RoutingContentService.java @@ -59,6 +59,7 @@ import org.alfresco.service.cmr.repository.NoTransformerException; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.StoreRef; +import org.alfresco.service.cmr.repository.TransformationOptions; import org.alfresco.service.cmr.usage.ContentQuotaException; import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; @@ -309,6 +310,7 @@ public class RoutingContentService implements ContentService return getReader(nodeRef, propertyQName, true); } + @SuppressWarnings("unchecked") private ContentReader getReader(NodeRef nodeRef, QName propertyQName, boolean fireContentReadPolicy) { ContentData contentData = null; @@ -448,16 +450,29 @@ public class RoutingContentService implements ContentService */ public void transform(ContentReader reader, ContentWriter writer) { - // Call transform with not options - this.transform(reader, writer, null); + // Call transform with no options + TransformationOptions options = null; + this.transform(reader, writer, options); + } + + /** + * @see org.alfresco.repo.content.transform.ContentTransformerRegistry + * @see org.alfresco.repo.content.transform.ContentTransformer + * @deprecated + */ + @SuppressWarnings("deprecation") + public void transform(ContentReader reader, ContentWriter writer, Map options) + throws NoTransformerException, ContentIOException + { + transform(reader, writer, new TransformationOptions(options)); } /** * @see org.alfresco.repo.content.transform.ContentTransformerRegistry * @see org.alfresco.repo.content.transform.ContentTransformer */ - public void transform(ContentReader reader, ContentWriter writer, Map options) - throws NoTransformerException, ContentIOException + public void transform(ContentReader reader, ContentWriter writer, TransformationOptions options) + throws NoTransformerException, ContentIOException { // check that source and target mimetypes are available String sourceMimetype = reader.getMimetype(); @@ -471,7 +486,7 @@ public class RoutingContentService implements ContentService throw new AlfrescoRuntimeException("The content writer mimetype must be set: " + writer); } // look for a transformer - ContentTransformer transformer = transformerRegistry.getTransformer(sourceMimetype, targetMimetype); + ContentTransformer transformer = transformerRegistry.getTransformer(sourceMimetype, targetMimetype, options); if (transformer == null) { throw new NoTransformerException(sourceMimetype, targetMimetype); @@ -487,10 +502,15 @@ public class RoutingContentService implements ContentService */ public ContentTransformer getTransformer(String sourceMimetype, String targetMimetype) { - // look for a transformer - ContentTransformer transformer = transformerRegistry.getTransformer(sourceMimetype, targetMimetype); - // done - return transformer; + return getTransformer(sourceMimetype, targetMimetype, new TransformationOptions()); + } + + /** + * @see org.alfresco.service.cmr.repository.ContentService#getTransformer(java.lang.String, java.lang.String, org.alfresco.service.cmr.repository.TransformationOptions) + */ + public ContentTransformer getTransformer(String sourceMimetype, String targetMimetype, TransformationOptions options) + { + return transformerRegistry.getTransformer(sourceMimetype, targetMimetype, options); } /** @@ -507,7 +527,15 @@ public class RoutingContentService implements ContentService */ public boolean isTransformable(ContentReader reader, ContentWriter writer) { - // check that source and target mimetypes are available + return isTransformable(reader, writer, new TransformationOptions()); + } + + /** + * @see org.alfresco.service.cmr.repository.ContentService#isTransformable(org.alfresco.service.cmr.repository.ContentReader, org.alfresco.service.cmr.repository.ContentWriter, org.alfresco.service.cmr.repository.TransformationOptions) + */ + public boolean isTransformable(ContentReader reader, ContentWriter writer, TransformationOptions options) + { + // check that source and target mimetypes are available String sourceMimetype = reader.getMimetype(); if (sourceMimetype == null) { @@ -520,7 +548,7 @@ public class RoutingContentService implements ContentService } // look for a transformer - ContentTransformer transformer = transformerRegistry.getTransformer(sourceMimetype, targetMimetype); + ContentTransformer transformer = transformerRegistry.getTransformer(sourceMimetype, targetMimetype, options); return (transformer != null); } diff --git a/source/java/org/alfresco/repo/content/transform/AbstractContentTransformer.java b/source/java/org/alfresco/repo/content/transform/AbstractContentTransformer.java index e74869919b..c41ee4c543 100644 --- a/source/java/org/alfresco/repo/content/transform/AbstractContentTransformer.java +++ b/source/java/org/alfresco/repo/content/transform/AbstractContentTransformer.java @@ -35,6 +35,8 @@ import org.alfresco.service.cmr.repository.ContentIOException; import org.alfresco.service.cmr.repository.ContentReader; import org.alfresco.service.cmr.repository.ContentWriter; import org.alfresco.service.cmr.repository.MimetypeService; +import org.alfresco.service.cmr.repository.TransformationOptions; +import org.alfresco.util.ParameterCheck; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -45,14 +47,19 @@ import org.apache.commons.logging.LogFactory; * This class maintains the performance measures for the transformers as well, making sure that * there is an extra penalty for transformers that fail regularly. * + * @deprecated + * Deprecated since 3.0. The abstract base class org.alfresco.repo.content.transform.AbstractContentTransformer2 should now be used instead. + * * @author Derek Hulley */ +@Deprecated public abstract class AbstractContentTransformer implements ContentTransformer { private static final Log logger = LogFactory.getLog(AbstractContentTransformer.class); private MimetypeService mimetypeService; private ContentTransformerRegistry registry; + @SuppressWarnings("deprecation") private List explicitTransformations; private double averageTime = 0.0; private long count = 0L; @@ -60,6 +67,7 @@ public abstract class AbstractContentTransformer implements ContentTransformer /** * All transformers start with an average transformation time of 0.0ms. */ + @SuppressWarnings("deprecation") protected AbstractContentTransformer() { averageTime = 0.0; @@ -97,6 +105,7 @@ public abstract class AbstractContentTransformer implements ContentTransformer /** * @return Returns the explicit transformations that were enabled for this transformer */ + @SuppressWarnings("deprecation") protected List getExplicitTransformations() { return explicitTransformations; @@ -108,6 +117,7 @@ public abstract class AbstractContentTransformer implements ContentTransformer * * @param explicitTransformations explicit key mappings */ + @SuppressWarnings("deprecation") public void setExplicitTransformations(List explicitTransformations) { this.explicitTransformations = explicitTransformations; @@ -136,13 +146,13 @@ public abstract class AbstractContentTransformer implements ContentTransformer return; } // first register any explicit transformations - if (explicitTransformations != null) - { - for (ContentTransformerRegistry.TransformationKey key : explicitTransformations) - { - registry.addExplicitTransformer(key, this); - } - } + //if (explicitTransformations != null) + //{ + // for (ContentTransformerRegistry.TransformationKey key : explicitTransformations) + // / { + // registry.addExplicitTransformer(key, this); + // } + //} // register this instance for the fallback case registry.addTransformer(this); } @@ -165,6 +175,15 @@ public abstract class AbstractContentTransformer implements ContentTransformer return mimetype; } + /** + * Added for backward compatibility of existing content transformers + * + * @param sourceMimetype the source mimetype + * @param targetMimetype the target mimetype + * @return double the reliability value of the content transformer ranging from 0 to 1 + */ + protected abstract double getReliability(String sourceMimetype, String targetMimetype); + /** * Convenience method to check the reliability of a transformation * @@ -185,7 +204,48 @@ public abstract class AbstractContentTransformer implements ContentTransformer } // it all checks out OK } + + /** + * @see org.alfresco.repo.content.transform.ContentTransformer#isTransformable(java.lang.String, java.lang.String, org.alfresco.service.cmr.repository.TransformationOptions) + */ + public boolean isTransformable(String sourceMimetype, String targetMimetype, TransformationOptions options) + { + ParameterCheck.mandatoryString("sourceMimetype", sourceMimetype); + ParameterCheck.mandatoryString("targetMimetype", targetMimetype); + + double reliability = getReliability(sourceMimetype, targetMimetype); + boolean result = true; + if (reliability <= 0.0) + { + result = false; + } + return result; + } + /** + * @see org.alfresco.repo.content.transform.ContentTransformer#isTransformable(java.lang.String, java.lang.String, org.alfresco.service.cmr.repository.TransformationOptions) + */ + @SuppressWarnings("deprecation") + public boolean isExplicitTransformation(String sourceMimetype, String targetMimetype, TransformationOptions options) + { + boolean result = false; + + if (this.explicitTransformations != null) + { + for (ContentTransformerRegistry.TransformationKey transformationKey : this.explicitTransformations) + { + if (transformationKey.getSourceMimetype().equals(sourceMimetype) == true && + transformationKey.getTargetMimetype().equals(targetMimetype) == true) + { + result = true; + break; + } + } + } + + return result; + } + /** * Method to be implemented by subclasses wishing to make use of the common infrastructural code * provided by this class. @@ -207,7 +267,18 @@ public abstract class AbstractContentTransformer implements ContentTransformer */ public final void transform(ContentReader reader, ContentWriter writer) throws ContentIOException { - transform(reader, writer, null); + Map optionsMap = null; + transform(reader, writer, optionsMap); + } + + /** + * @see org.alfresco.repo.content.transform.ContentTransformer#transform(org.alfresco.service.cmr.repository.ContentReader, org.alfresco.service.cmr.repository.ContentWriter, org.alfresco.service.cmr.repository.TransformationOptions) + */ + public final void transform(ContentReader reader, ContentWriter writer, TransformationOptions options) + throws ContentIOException + { + Map optionsMap = options.toMap(); + transform(reader, writer, optionsMap); } /** @@ -223,6 +294,7 @@ public abstract class AbstractContentTransformer implements ContentTransformer *

* If the options provided are null, then an empty map will be created. */ + @SuppressWarnings("deprecation") public final void transform( ContentReader reader, ContentWriter writer, diff --git a/source/java/org/alfresco/repo/content/transform/AbstractContentTransformer2.java b/source/java/org/alfresco/repo/content/transform/AbstractContentTransformer2.java new file mode 100644 index 0000000000..36a45b24b1 --- /dev/null +++ b/source/java/org/alfresco/repo/content/transform/AbstractContentTransformer2.java @@ -0,0 +1,326 @@ +/* + * 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; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.service.cmr.repository.ContentAccessor; +import org.alfresco.service.cmr.repository.ContentIOException; +import org.alfresco.service.cmr.repository.ContentReader; +import org.alfresco.service.cmr.repository.ContentWriter; +import org.alfresco.service.cmr.repository.MimetypeService; +import org.alfresco.service.cmr.repository.TransformationOptions; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Provides basic services for {@link org.alfresco.repo.content.transform.ContentTransformer} + * implementations. + *

+ * This class maintains the performance measures for the transformers as well, making sure that + * there is an extra penalty for transformers that fail regularly. + * + * @author Derek Hulley + * @author Roy Wetherall + */ +public abstract class AbstractContentTransformer2 implements ContentTransformer +{ + private static final Log logger = LogFactory.getLog(AbstractContentTransformer2.class); + + private MimetypeService mimetypeService; + private ContentTransformerRegistry registry; + private List explicitTransformations; + private double averageTime = 0.0; + private long count = 0L; + + /** + * All transformers start with an average transformation time of 0.0ms. + */ + protected AbstractContentTransformer2() + { + averageTime = 0.0; + explicitTransformations = new ArrayList(0); + } + + /** + * The registry to auto-register with + * + * @param registry the transformer registry + */ + public void setRegistry(ContentTransformerRegistry registry) + { + this.registry = registry; + } + + /** + * Helper setter of the mimetype service. This is not always required. + * + * @param mimetypeService + */ + public void setMimetypeService(MimetypeService mimetypeService) + { + this.mimetypeService = mimetypeService; + } + + /** + * @return Returns the mimetype helper + */ + protected MimetypeService getMimetypeService() + { + return mimetypeService; + } + + public void setExplicitTransformations(List explicitTransformations) + { + this.explicitTransformations = explicitTransformations; + } + + + @Override + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(this.getClass().getSimpleName()) + .append("[ average=").append((long)averageTime).append("ms") + .append("]"); + return sb.toString(); + } + + /** + * Registers this instance with the {@link #setRegistry(ContentTransformerRegistry) registry} + * if it is present. + */ + public void register() + { + if (registry == null) + { + logger.warn("Property 'registry' has not been set. Ignoring auto-registration: \n" + + " transformer: " + this); + return; + } + + // register this instance for the fallback case + registry.addTransformer(this); + } + + /** + * Convenience to fetch and check the mimetype for the given content + * + * @param content the reader/writer for the content + * @return Returns the mimetype for the content + * @throws AlfrescoRuntimeException if the content doesn't have a mimetype + */ + protected String getMimetype(ContentAccessor content) + { + String mimetype = content.getMimetype(); + if (mimetype == null) + { + throw new AlfrescoRuntimeException("Mimetype is mandatory for transformation: " + content); + } + // done + return mimetype; + } + + /** + * Convenience method to check the transformability of a transformation + * + * @param reader content reader + * @param writer content writer + * @param options transformation options + * @throws AlfrescoRuntimeException if the the transformation isn't supported + */ + protected void checkTransformable(ContentReader reader, ContentWriter writer, TransformationOptions options) + { + String sourceMimetype = getMimetype(reader); + String targetMimetype = getMimetype(writer); + boolean transformable = isTransformable(sourceMimetype, targetMimetype, options); + if (transformable == false) + { + throw new AlfrescoRuntimeException("Unsuported transformation attempted: \n" + + " reader: " + reader + "\n" + + " writer: " + writer); + } + // it all checks out OK + } + + /** + * Method to be implemented by subclasses wishing to make use of the common infrastructural code + * provided by this class. + * + * @param reader the source of the content to transform + * @param writer the target to which to write the transformed content + * @param options a map of options to use when performing the transformation. The map + * will never be null. + * @throws Exception exceptions will be handled by this class - subclasses can throw anything + */ + protected abstract void transformInternal( + ContentReader reader, + ContentWriter writer, + TransformationOptions options) throws Exception; + + /** + * @see #transform(ContentReader, ContentWriter, Map) + * @see #transformInternal(ContentReader, ContentWriter, Map) + */ + public final void transform(ContentReader reader, ContentWriter writer) throws ContentIOException + { + transform(reader, writer, new TransformationOptions()); + } + + /** + * @see org.alfresco.repo.content.transform.ContentTransformer#transform(org.alfresco.service.cmr.repository.ContentReader, org.alfresco.service.cmr.repository.ContentWriter, org.alfresco.service.cmr.repository.TransformationOptions) + */ + public final void transform(ContentReader reader, ContentWriter writer, TransformationOptions options) + throws ContentIOException + { + // begin timing + long before = System.currentTimeMillis(); + + // check options map + if (options == null) + { + options = new TransformationOptions(); + } + + try + { + // Check the transformability + checkTransformable(reader, writer, options); + + // Transform + transformInternal(reader, writer, options); + } + catch (Throwable e) + { + // Make sure that this transformation gets set back i.t.o. time taken. + // This will ensure that transformers that compete for the same transformation + // will be prejudiced against transformers that tend to fail + recordTime(10000); // 10 seconds, i.e. rubbish + + throw new ContentIOException("Content conversion failed: \n" + + " reader: " + reader + "\n" + + " writer: " + writer + "\n" + + " options: " + options, + e); + } + finally + { + // check that the reader and writer are both closed + if (reader.isChannelOpen()) + { + logger.error("Content reader not closed by transformer: \n" + + " reader: " + reader + "\n" + + " transformer: " + this); + } + if (writer.isChannelOpen()) + { + logger.error("Content writer not closed by transformer: \n" + + " writer: " + writer + "\n" + + " transformer: " + this); + } + } + + // record time + long after = System.currentTimeMillis(); + recordTime(after - before); + + // done + if (logger.isDebugEnabled()) + { + logger.debug("Completed transformation: \n" + + " reader: " + reader + "\n" + + " writer: " + writer + "\n" + + " options: " + options + "\n" + + " transformer: " + this); + } + } + + + @SuppressWarnings("deprecation") + public final void transform( + ContentReader reader, + ContentWriter writer, + Map options) throws ContentIOException + { + this.transform(reader, writer, new TransformationOptions(options)); + } + + /** + * Default implementation, override if need to extend logic + * + * @see org.alfresco.repo.content.transform.ContentTransformer#isExplicitTransformation(java.lang.String, java.lang.String, org.alfresco.service.cmr.repository.TransformationOptions) + */ + public boolean isExplicitTransformation(String sourceMimetype, String targetMimetype, TransformationOptions options) + { + boolean result = false; + for (ExplictTransformationDetails explicitTransformation : this.explicitTransformations) + { + if (sourceMimetype.equals(explicitTransformation.getSourceMimetype()) == true && + targetMimetype.equals(explicitTransformation.getTargetMimetype()) == true) + { + result = true; + break; + } + } + return result; + } + + /** + * @return Returns the calculated running average of the current transformations + */ + public synchronized long getTransformationTime() + { + return (long) averageTime; + } + + /** + * Records and updates the average transformation time for this transformer. + *

+ * Subclasses should call this after every transformation in order to keep + * the running average of the transformation times up to date. + *

+ * This method is thread-safe. The time spent in this method is negligible + * so the impact will be minor. + * + * @param transformationTime the time it took to perform the transformation. + * The value may be 0. + */ + protected final synchronized void recordTime(long transformationTime) + { + if (count == Long.MAX_VALUE) + { + // we have reached the max count - reduce it by half + // the average fluctuation won't be extreme + count /= 2L; + } + // adjust the average + count++; + double diffTime = ((double) transformationTime) - averageTime; + averageTime += diffTime / (double) count; + } +} diff --git a/source/java/org/alfresco/repo/content/transform/AbstractContentTransformerTest.java b/source/java/org/alfresco/repo/content/transform/AbstractContentTransformerTest.java index f8f4762245..a801f08d5e 100644 --- a/source/java/org/alfresco/repo/content/transform/AbstractContentTransformerTest.java +++ b/source/java/org/alfresco/repo/content/transform/AbstractContentTransformerTest.java @@ -170,7 +170,7 @@ public abstract class AbstractContentTransformerTest extends TestCase // must we test the transformation? ContentTransformer transformer = getTransformer(sourceMimetype, targetMimetype); - if (transformer == null || transformer.getReliability(sourceMimetype, targetMimetype) <= 0.0) + if (transformer == null || transformer.isTransformable(sourceMimetype, targetMimetype, null) == false) { // no transformer continue; diff --git a/source/java/org/alfresco/repo/content/transform/BinaryPassThroughContentTransformer.java b/source/java/org/alfresco/repo/content/transform/BinaryPassThroughContentTransformer.java index ff278ce030..bb7031bb7e 100644 --- a/source/java/org/alfresco/repo/content/transform/BinaryPassThroughContentTransformer.java +++ b/source/java/org/alfresco/repo/content/transform/BinaryPassThroughContentTransformer.java @@ -24,10 +24,9 @@ */ package org.alfresco.repo.content.transform; -import java.util.Map; - import org.alfresco.service.cmr.repository.ContentReader; import org.alfresco.service.cmr.repository.ContentWriter; +import org.alfresco.service.cmr.repository.TransformationOptions; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -42,41 +41,38 @@ import org.apache.commons.logging.LogFactory; * * @author Derek Hulley */ -public class BinaryPassThroughContentTransformer extends AbstractContentTransformer +public class BinaryPassThroughContentTransformer extends AbstractContentTransformer2 { + @SuppressWarnings("unused") private static final Log logger = LogFactory.getLog(BinaryPassThroughContentTransformer.class); - - /** - * @return Returns 1.0 if the formats are identical and not text - */ - public double getReliability(String sourceMimetype, String targetMimetype) + + @Override + protected void transformInternal(ContentReader reader, + ContentWriter writer, TransformationOptions options) + throws Exception + { + // just stream it + writer.putContent(reader.getContentInputStream()); + + } + + public boolean isTransformable(String sourceMimetype, + String targetMimetype, TransformationOptions options) { if (sourceMimetype.startsWith(StringExtractingContentTransformer.PREFIX_TEXT)) { // we can only stream binary content through - return 0.0; + return false; } else if (!sourceMimetype.equals(targetMimetype)) { // no transformation is possible so formats must be exact - return 0.0; + return false; } else { // formats are the same and are not text - return 1.0; + return true; } } - - /** - * Performs a direct stream provided the preconditions are met - */ - public void transformInternal( - ContentReader reader, - ContentWriter writer, - Map options) throws Exception - { - // just stream it - writer.putContent(reader.getContentInputStream()); - } } diff --git a/source/java/org/alfresco/repo/content/transform/BinaryPassThroughContentTransformerTest.java b/source/java/org/alfresco/repo/content/transform/BinaryPassThroughContentTransformerTest.java index ee35f91392..7221513244 100644 --- a/source/java/org/alfresco/repo/content/transform/BinaryPassThroughContentTransformerTest.java +++ b/source/java/org/alfresco/repo/content/transform/BinaryPassThroughContentTransformerTest.java @@ -25,6 +25,7 @@ package org.alfresco.repo.content.transform; import org.alfresco.repo.content.MimetypeMap; +import org.alfresco.service.cmr.repository.TransformationOptions; /** * @see org.alfresco.repo.content.transform.BinaryPassThroughContentTransformer @@ -51,16 +52,18 @@ public class BinaryPassThroughContentTransformerTest extends AbstractContentTran return transformer; } - public void testReliability() throws Exception + public void testIsTransformable() throws Exception { - double reliability = 0.0; - reliability = transformer.getReliability(MimetypeMap.MIMETYPE_TEXT_PLAIN, MimetypeMap.MIMETYPE_TEXT_PLAIN); - assertEquals("Mimetype should not be supported", 0.0, reliability); - reliability = transformer.getReliability(MimetypeMap.MIMETYPE_XML, MimetypeMap.MIMETYPE_XML); - assertEquals("Mimetype should not be supported", 0.0, reliability); - reliability = transformer.getReliability(MimetypeMap.MIMETYPE_WORD, MimetypeMap.MIMETYPE_WORD); - assertEquals("Mimetype should be supported", 1.0, reliability); - reliability = transformer.getReliability(MimetypeMap.MIMETYPE_EXCEL, MimetypeMap.MIMETYPE_EXCEL); - assertEquals("Mimetype should be supported", 1.0, reliability); + TransformationOptions options = new TransformationOptions(); + boolean reliability = false; + + reliability = transformer.isTransformable(MimetypeMap.MIMETYPE_TEXT_PLAIN, MimetypeMap.MIMETYPE_TEXT_PLAIN, options); + assertFalse("Mimetype should not be supported", reliability); + reliability = transformer.isTransformable(MimetypeMap.MIMETYPE_XML, MimetypeMap.MIMETYPE_XML, options); + assertFalse("Mimetype should not be supported", reliability); + reliability = transformer.isTransformable(MimetypeMap.MIMETYPE_WORD, MimetypeMap.MIMETYPE_WORD, options); + assertTrue("Mimetype should be supported", reliability); + reliability = transformer.isTransformable(MimetypeMap.MIMETYPE_EXCEL, MimetypeMap.MIMETYPE_EXCEL, options); + assertTrue("Mimetype should be supported", reliability); } } diff --git a/source/java/org/alfresco/repo/content/transform/ComplexContentTransformer.java b/source/java/org/alfresco/repo/content/transform/ComplexContentTransformer.java index dded8bbfca..f148013b1e 100644 --- a/source/java/org/alfresco/repo/content/transform/ComplexContentTransformer.java +++ b/source/java/org/alfresco/repo/content/transform/ComplexContentTransformer.java @@ -3,12 +3,12 @@ package org.alfresco.repo.content.transform; import java.io.File; import java.util.Iterator; import java.util.List; -import java.util.Map; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.repo.content.filestore.FileContentWriter; import org.alfresco.service.cmr.repository.ContentReader; import org.alfresco.service.cmr.repository.ContentWriter; +import org.alfresco.service.cmr.repository.TransformationOptions; import org.alfresco.util.TempFileProvider; import org.springframework.beans.factory.InitializingBean; @@ -18,7 +18,7 @@ import org.springframework.beans.factory.InitializingBean; * * @author Derek Hulley */ -public class ComplexContentTransformer extends AbstractContentTransformer implements InitializingBean +public class ComplexContentTransformer extends AbstractContentTransformer2 implements InitializingBean { private List transformers; private List intermediateMimetypes; @@ -74,13 +74,15 @@ public class ComplexContentTransformer extends AbstractContentTransformer implem throw new AlfrescoRuntimeException("'mimetypeService' is a required property"); } } - + /** - * @return Returns the multiple of the reliabilities of the chain of transformers + * Check we can transform all the way along the chain of mimetypes + * + * @see org.alfresco.repo.content.transform.ContentTransformer#isTransformable(java.lang.String, java.lang.String, org.alfresco.service.cmr.repository.TransformationOptions) */ - public double getReliability(String sourceMimetype, String targetMimetype) + public boolean isTransformable(String sourceMimetype, String targetMimetype, TransformationOptions options) { - double reliability = 1.0; + boolean result = true; String currentSourceMimetype = sourceMimetype; Iterator transformerIterator = transformers.iterator(); @@ -99,20 +101,29 @@ public class ComplexContentTransformer extends AbstractContentTransformer implem // use an intermediate transformation mimetype currentTargetMimetype = intermediateMimetypeIterator.next(); } - // the reliability is a multiple - reliability *= transformer.getReliability(currentSourceMimetype, currentTargetMimetype); - // move the source on + + // check we can tranform the current stage + if (transformer.isTransformable(currentSourceMimetype, currentTargetMimetype, options) == false) + { + result = false; + break; + } + + // move on currentSourceMimetype = currentTargetMimetype; } - // done - return reliability; + + return result; } + /** + * @see org.alfresco.repo.content.transform.AbstractContentTransformer2#transformInternal(org.alfresco.service.cmr.repository.ContentReader, org.alfresco.service.cmr.repository.ContentWriter, org.alfresco.service.cmr.repository.TransformationOptions) + */ @Override public void transformInternal( ContentReader reader, ContentWriter writer, - Map options) throws Exception + TransformationOptions options) throws Exception { ContentReader currentReader = reader; @@ -145,5 +156,5 @@ public class ComplexContentTransformer extends AbstractContentTransformer implem currentReader = currentWriter.getReader(); } // done - } + } } diff --git a/source/java/org/alfresco/repo/content/transform/ComplexContentTransformerTest.java b/source/java/org/alfresco/repo/content/transform/ComplexContentTransformerTest.java index 09989973cc..373b6e4fa6 100644 --- a/source/java/org/alfresco/repo/content/transform/ComplexContentTransformerTest.java +++ b/source/java/org/alfresco/repo/content/transform/ComplexContentTransformerTest.java @@ -29,6 +29,7 @@ import java.util.Collections; import java.util.List; import org.alfresco.repo.content.MimetypeMap; +import org.alfresco.service.cmr.repository.TransformationOptions; /** * Tests a transformation from Powerpoint->PDF->Text. @@ -50,12 +51,12 @@ public class ComplexContentTransformerTest extends AbstractContentTransformerTes ContentTransformer unoTransformer = (ContentTransformer) ctx.getBean("transformer.OpenOffice"); ContentTransformer pdfBoxTransformer = (ContentTransformer) ctx.getBean("transformer.PdfBox"); // make sure that they are working for this test - if (unoTransformer.getReliability(MimetypeMap.MIMETYPE_PPT, MimetypeMap.MIMETYPE_PDF) == 0.0) + if (unoTransformer.isTransformable(MimetypeMap.MIMETYPE_PPT, MimetypeMap.MIMETYPE_PDF, new TransformationOptions()) == false) { isAvailable = false; return; } - else if (pdfBoxTransformer.getReliability(MimetypeMap.MIMETYPE_PDF, MimetypeMap.MIMETYPE_TEXT_PLAIN) == 0.0) + else if (pdfBoxTransformer.isTransformable(MimetypeMap.MIMETYPE_PDF, MimetypeMap.MIMETYPE_TEXT_PLAIN, new TransformationOptions()) == false) { isAvailable = false; return; @@ -91,10 +92,9 @@ public class ComplexContentTransformerTest extends AbstractContentTransformerTes { return; } - double reliability = 0.0; - reliability = transformer.getReliability(MimetypeMap.MIMETYPE_PPT, MimetypeMap.MIMETYPE_PDF); - assertEquals("Mimetype should not be supported", 0.0, reliability); - reliability = transformer.getReliability(MimetypeMap.MIMETYPE_PPT, MimetypeMap.MIMETYPE_TEXT_PLAIN); - assertEquals("Mimetype should be supported", 1.0, reliability); + boolean reliability = transformer.isTransformable(MimetypeMap.MIMETYPE_PPT, MimetypeMap.MIMETYPE_PDF, new TransformationOptions()); + assertEquals("Mimetype should not be supported", false, reliability); + reliability = transformer.isTransformable(MimetypeMap.MIMETYPE_PPT, MimetypeMap.MIMETYPE_TEXT_PLAIN, new TransformationOptions()); + assertEquals("Mimetype should be supported", true, reliability); } } diff --git a/source/java/org/alfresco/repo/content/transform/CompoundContentTransformer.java b/source/java/org/alfresco/repo/content/transform/CompoundContentTransformer.java deleted file mode 100644 index 97772eb4e7..0000000000 --- a/source/java/org/alfresco/repo/content/transform/CompoundContentTransformer.java +++ /dev/null @@ -1,256 +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; - -import java.io.File; -import java.util.LinkedList; -import java.util.Map; - -import org.alfresco.error.AlfrescoRuntimeException; -import org.alfresco.repo.content.filestore.FileContentWriter; -import org.alfresco.service.cmr.repository.ContentIOException; -import org.alfresco.service.cmr.repository.ContentReader; -import org.alfresco.service.cmr.repository.ContentWriter; -import org.alfresco.util.TempFileProvider; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * A chain of transformations that is able to produce non-zero reliability - * transformation from one mimetype to another. - *

- * The reliability of the chain is the product of all the individual - * transformations. - * - * @author Derek Hulley - */ -public class CompoundContentTransformer implements ContentTransformer -{ - private static final Log logger = LogFactory.getLog(CompoundContentTransformer.class); - - /** a sequence of transformers to apply */ - private LinkedList chain; - /** the combined reliability of all the transformations in the chain */ - private double reliability; - - public CompoundContentTransformer() - { - chain = new LinkedList(); - reliability = 1.0; - } - - /** - * Adds a transformation to the chain. The reliability of each transformation - * added must be greater than 0.0. - * - * @param sourceMimetype - * @param targetMimetype - * @param transformer the transformer that will transform from the source to - * the target mimetype - */ - public void addTransformation(String sourceMimetype, String targetMimetype, ContentTransformer transformer) - { - // create a transformation that aggregates the transform info - Transformation transformation = new Transformation( - transformer, - sourceMimetype, - targetMimetype); - // add to the chain - chain.add(transformation); - // recalculate combined reliability - double transformerReliability = transformer.getReliability(sourceMimetype, targetMimetype); - if (transformerReliability <= 0.0 || transformerReliability > 1.0) - { - throw new AlfrescoRuntimeException( - "Reliability of transformer must be between 0.0 and 1.0: \n" + - " transformer: " + transformer + "\n" + - " source: " + sourceMimetype + "\n" + - " target: " + targetMimetype + "\n" + - " reliability: " + transformerReliability); - } - this.reliability *= transformerReliability; - } - - /** - * In order to score anything, the source mimetype must match the source - * mimetype of the first transformer and the target mimetype must match - * the target mimetype of the last transformer in the chain. - * - * @return Returns the product of the individual reliability scores of the - * transformations in the chain - */ - public double getReliability(String sourceMimetype, String targetMimetype) - { - if (chain.size() == 0) - { - // no transformers therefore no transformation possible - return 0.0; - } - Transformation first = chain.getFirst(); - Transformation last = chain.getLast(); - if (!first.getSourceMimetype().equals(sourceMimetype) - && last.getTargetMimetype().equals(targetMimetype)) - { - // the source type of the first transformation must match the source - // the target type of the last transformation must match the target - return 0.0; - } - return reliability; - } - - /** - * @return Returns 0 if there are no transformers in the chain otherwise - * returns the sum of all the individual transformation times - */ - public long getTransformationTime() - { - long transformationTime = 0L; - for (Transformation transformation : chain) - { - ContentTransformer transformer = transformation.transformer; - transformationTime += transformer.getTransformationTime(); - } - return transformationTime; - } - - /** - * - */ - public void transform(ContentReader reader, ContentWriter writer) throws ContentIOException - { - transform(reader, writer, null); - } - - /** - * Executes each transformer in the chain, passing the content between them - */ - public void transform(ContentReader reader, ContentWriter writer, Map options) - throws ContentIOException - { - if (chain.size() == 0) - { - throw new AlfrescoRuntimeException("No transformations present in chain"); - } - - // check that the mimetypes of the transformation are valid for the chain - String sourceMimetype = reader.getMimetype(); - String targetMimetype = writer.getMimetype(); - Transformation firstTransformation = chain.getFirst(); - Transformation lastTransformation = chain.getLast(); - if (!firstTransformation.getSourceMimetype().equals(sourceMimetype) - && lastTransformation.getTargetMimetype().equals(targetMimetype)) - { - throw new AlfrescoRuntimeException("Attempting to perform unreliable transformation: \n" + - " reader: " + reader + "\n" + - " writer: " + writer); - } - - ContentReader currentReader = reader; - ContentWriter currentWriter = null; - int currentIndex = 0; - for (Transformation transformation : chain) - { - boolean last = (currentIndex == chain.size() - 1); - if (last) - { - // we are on the last transformation so use the final output writer - currentWriter = writer; - } - else - { - // have to create an intermediate writer - just use a file writer - File tempFile = TempFileProvider.createTempFile("transform", ".tmp"); - currentWriter = new FileContentWriter(tempFile); - // set the writer's mimetype to conform to the transformation we are using - currentWriter.setMimetype(transformation.getTargetMimetype()); - } - // transform from the current reader to the current writer - transformation.execute(currentReader, currentWriter, options); - if (!currentWriter.isClosed()) - { - throw new AlfrescoRuntimeException("Writer not closed by transformation: \n" + - " transformation: " + transformation + "\n" + - " writer: " + currentWriter); - } - // if we have more transformations, then use the written content - // as the next source - if (!last) - { - currentReader = currentWriter.getReader(); - } - } - // done - if (logger.isDebugEnabled()) - { - logger.debug("Executed complex transformation: \n" + - " chain: " + chain + "\n" + - " reader: " + reader + "\n" + - " writer: " + writer); - } - } - - /** - * A transformation that contains the transformer as well as the - * transformation mimetypes to be used - */ - public static class Transformation extends ContentTransformerRegistry.TransformationKey - { - private ContentTransformer transformer; - public Transformation(ContentTransformer transformer, String sourceMimetype, String targetMimetype) - { - super(sourceMimetype, targetMimetype); - this.transformer = transformer; - } - - /** - * Executs the transformation - * - * @param reader the reader from which to read the content - * @param writer the writer to write content to - * @param options the options to execute with - * @throws ContentIOException if the transformation fails - */ - public void execute(ContentReader reader, ContentWriter writer, Map options) - throws ContentIOException - { - String sourceMimetype = getSourceMimetype(); - String targetMimetype = getTargetMimetype(); - // check that the source and target mimetypes of the reader and writer match - if (!sourceMimetype.equals(reader.getMimetype())) - { - throw new AlfrescoRuntimeException("The source mimetype doesn't match the reader's mimetype: \n" + - " source mimetype: " + sourceMimetype + "\n" + - " reader: " + reader); - } - if (!targetMimetype.equals(writer.getMimetype())) - { - throw new AlfrescoRuntimeException("The target mimetype doesn't match the writer's mimetype: \n" + - " target mimetype: " + targetMimetype + "\n" + - " writer: " + writer); - } - transformer.transform(reader, writer, options); - } - } -} \ No newline at end of file diff --git a/source/java/org/alfresco/repo/content/transform/ContentTransformer.java b/source/java/org/alfresco/repo/content/transform/ContentTransformer.java index 4f362ee07a..5859aaaa46 100644 --- a/source/java/org/alfresco/repo/content/transform/ContentTransformer.java +++ b/source/java/org/alfresco/repo/content/transform/ContentTransformer.java @@ -30,6 +30,7 @@ import org.alfresco.repo.content.ContentWorker; import org.alfresco.service.cmr.repository.ContentIOException; import org.alfresco.service.cmr.repository.ContentReader; import org.alfresco.service.cmr.repository.ContentWriter; +import org.alfresco.service.cmr.repository.TransformationOptions; /** * Interface for class that allow content transformation from one mimetype to another. @@ -45,8 +46,8 @@ public interface ContentTransformer extends ContentWorker * options are used, but they should be considered optional and their absence * should not interfere with the execution of the transformer. */ - public static final String OPT_SOURCE_NODEREF = "sourceNodeRef"; - public static final String OPT_DESTINATION_NODEREF = "destinationNodeRef"; + //public static final String OPT_SOURCE_NODEREF = "sourceNodeRef"; + //public static final String OPT_DESTINATION_NODEREF = "destinationNodeRef"; /** * Provides the approximate accuracy with which this transformer can @@ -61,7 +62,27 @@ public interface ContentTransformer extends ContentWorker * transformation cannot be performed at all. 1.0 indicates that * the transformation can be performed perfectly. */ - public double getReliability(String sourceMimetype, String targetMimetype); + //public double getReliability(String sourceMimetype, String targetMimetype); + + /** + * Indicates whether the provided source mimetype can be transformed into the target mimetype with + * the options specified by this content transformer. + * + * @param sourceMimetype the source mimetype + * @param destinationMimetype the destination mimetype + * @param options the transformation options + * @return boolean true if this content transformer can satify the mimetypes and options specified, false otherwise + */ + public boolean isTransformable(String sourceMimetype, String targetMimetype, TransformationOptions options); + + /** + * + * @param sourceMimetype + * @param targetMimetype + * @param options + * @return + */ + public boolean isExplicitTransformation(String sourceMimetype, String targetMimetype, TransformationOptions options); /** * Provides an estimate, usually a worst case guess, of how long a transformation @@ -75,7 +96,7 @@ public interface ContentTransformer extends ContentWorker public long getTransformationTime(); /** - * @see #transform(ContentReader, ContentWriter, Map) + * @see #transform(ContentReader, ContentWriter, TransformationOptions) */ public void transform(ContentReader reader, ContentWriter writer) throws ContentIOException; @@ -97,9 +118,36 @@ public interface ContentTransformer extends ContentWorker * @param options options to pass to the transformer. These are transformer dependent * and may be null. * @throws ContentIOException if an IO exception occurs + * + * @deprecated + * Deprecated since 3.0. Options should now be provided as a TransformationOptions object. */ + @Deprecated public void transform( ContentReader reader, ContentWriter writer, Map options) throws ContentIOException; + + /** + * Transforms the content provided by the reader and source mimetype + * to the writer and target mimetype with the provided transformation options. + *

+ * The transformation viability can be determined by an up front call + * to {@link #isTransformable(String, String, TransformationOptions)}. + *

+ * The source and target mimetypes must be available on the + * {@link org.alfresco.service.cmr.repository.ContentAccessor#getMimetype()} methods of + * both the reader and the writer. + *

+ * Both reader and writer will be closed after the transformation completes. + *

+ * The provided options can be null. + * + * @param reader the source of the content + * @param contentWriter the destination of the transformed content + * @param options transformation options, these can be null + * @throws ContentIOException if an IO exception occurs + */ + public void transform(ContentReader reader, ContentWriter contentWriter, TransformationOptions options) + throws ContentIOException; } diff --git a/source/java/org/alfresco/repo/content/transform/ContentTransformerRegistry.java b/source/java/org/alfresco/repo/content/transform/ContentTransformerRegistry.java index 40d80983b0..54f5a7f7d9 100644 --- a/source/java/org/alfresco/repo/content/transform/ContentTransformerRegistry.java +++ b/source/java/org/alfresco/repo/content/transform/ContentTransformerRegistry.java @@ -26,13 +26,9 @@ package org.alfresco.repo.content.transform; import java.util.ArrayList; import java.util.Collections; -import java.util.HashMap; import java.util.List; -import java.util.Map; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReadWriteLock; -import java.util.concurrent.locks.ReentrantReadWriteLock; +import org.alfresco.service.cmr.repository.TransformationOptions; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -52,12 +48,13 @@ public class ContentTransformerRegistry private static final Log logger = LogFactory.getLog(ContentTransformerRegistry.class); private List transformers; + /** Cache of previously used transactions */ - private Map> transformationCache; + //private Map> transformationCache; /** Controls read access to the transformation cache */ - private Lock transformationCacheReadLock; + //private Lock transformationCacheReadLock; /** controls write access to the transformation cache */ - private Lock transformationCacheWriteLock; + //private Lock transformationCacheWriteLock; /** * @param mimetypeMap all the mimetypes available to the system @@ -65,12 +62,13 @@ public class ContentTransformerRegistry public ContentTransformerRegistry() { this.transformers = new ArrayList(10); - transformationCache = new HashMap>(17); + + //transformationCache = new HashMap>(17); // create lock objects for access to the cache - ReadWriteLock transformationCacheLock = new ReentrantReadWriteLock(); - transformationCacheReadLock = transformationCacheLock.readLock(); - transformationCacheWriteLock = transformationCacheLock.writeLock(); + //ReadWriteLock transformationCacheLock = new ReentrantReadWriteLock(); + //transformationCacheReadLock = transformationCacheLock.readLock(); + //transformationCacheWriteLock = transformationCacheLock.writeLock(); } /** @@ -80,17 +78,17 @@ public class ContentTransformerRegistry * @param key the mapping from one mimetype to the next * @param transformer the content transformer */ - public void addExplicitTransformer(TransformationKey key, ContentTransformer transformer) - { - transformationCache.put(key, Collections.singletonList(transformer)); + //public void addExplicitTransformer(TransformationKey key, ContentTransformer transformer) + //{ + // transformationCache.put(key, Collections.singletonList(transformer)); // done - if (logger.isDebugEnabled()) - { - logger.debug("Registered explicit transformation: \n" + - " key: " + key + "\n" + - " transformer: " + transformer); - } - } + // if (logger.isDebugEnabled()) + // { + // logger.debug("Registered explicit transformation: \n" + + // " key: " + key + "\n" + + // " transformer: " + transformer); + // } + // } /** * Registers an individual transformer that can be queried to check for applicability. @@ -112,81 +110,75 @@ public class ContentTransformerRegistry * Resets the transformation cache. This allows a fresh analysis of the best * conversions based on actual average performance of the transformers. */ - public void resetCache() - { - // get a write lock on the cache - transformationCacheWriteLock.lock(); - try - { - transformationCache.clear(); - } - finally - { - transformationCacheWriteLock.unlock(); - } - // done - if (logger.isDebugEnabled()) - { - logger.debug("Content transformation cache reset"); - } - } +// public void resetCache() +// { +// // get a write lock on the cache +// transformationCacheWriteLock.lock(); +// try +// { +// transformationCache.clear(); +// } +// finally +// { +// transformationCacheWriteLock.unlock(); +// } +// // done +// if (logger.isDebugEnabled()) +// { +// logger.debug("Content transformation cache reset"); +// } +// } /** * Gets the best transformer possible. This is a combination of the most reliable * and the most performant transformer. - *

- * The result is cached for quicker access next time. - * - * @param sourceMimetype the source mimetype of the transformation - * @param targetMimetype the target mimetype of the transformation - * @return Returns a content transformer that can perform the desired - * transformation or null if no transformer could be found that would do it. + * + * TODO */ - public ContentTransformer getTransformer(String sourceMimetype, String targetMimetype) + public ContentTransformer getTransformer(String sourceMimetype, String targetMimetype, TransformationOptions options) { - TransformationKey key = new TransformationKey(sourceMimetype, targetMimetype); + //TransformationKey key = new TransformationKey(sourceMimetype, targetMimetype); List transformers = null; - transformationCacheReadLock.lock(); - try - { - if (transformationCache.containsKey(key)) - { + //transformationCacheReadLock.lock(); + //try + //{ + // if (transformationCache.containsKey(key)) + // { // the translation has been requested before // it might have been null - transformers = transformationCache.get(key); - } - } - finally - { - transformationCacheReadLock.unlock(); - } + // transformers = transformationCache.get(key); + // } + //} + // finally + // { + // transformationCacheReadLock.unlock(); + // } - if (transformers == null) - { + // if (transformers == null) + // { // the translation has not been requested before // get a write lock on the cache // no double check done as it is not an expensive task - transformationCacheWriteLock.lock(); - try - { + // transformationCacheWriteLock.lock(); + // try + // { // find the most suitable transformer - may be empty list - transformers = findTransformers(sourceMimetype, targetMimetype); + transformers = findTransformers(sourceMimetype, targetMimetype, options); // store the result even if it is null - transformationCache.put(key, transformers); - } - finally - { - transformationCacheWriteLock.unlock(); - } - } + // transformationCache.put(key, transformers); + // } + // finally + // { + // transformationCacheWriteLock.unlock(); + // } + //} // select the most performant transformer long bestTime = -1L; ContentTransformer bestTransformer = null; for (ContentTransformer transformer : transformers) { - // Reliability can be dynamic, i.e. it may have become unreliable - double reliability = transformer.getReliability(sourceMimetype, targetMimetype); - if (reliability == 0.0) + // Transformability can be dynamic, i.e. it may have become unusable + if (transformer.isTransformable(sourceMimetype, targetMimetype, options) == false) { // It is unreliable now. continue; @@ -210,12 +202,12 @@ public class ContentTransformerRegistry * @return Returns best transformer for the translation - null if all * score 0.0 on reliability */ - private List findTransformers(String sourceMimetype, String targetMimetype) + private List findTransformers(String sourceMimetype, String targetMimetype, TransformationOptions options) { // search for a simple transformer that can do the job - List transformers = findDirectTransformers(sourceMimetype, targetMimetype); + List transformers = findDirectTransformers(sourceMimetype, targetMimetype, options); // get the complex transformers that can do the job - List complexTransformers = findComplexTransformer(sourceMimetype, targetMimetype); + List complexTransformers = findComplexTransformer(sourceMimetype, targetMimetype, options); transformers.addAll(complexTransformers); // done if (logger.isDebugEnabled()) @@ -236,45 +228,68 @@ public class ContentTransformerRegistry * @return Returns the most reliable transformers for the translation - empty list if there * are none. */ - private List findDirectTransformers(String sourceMimetype, String targetMimetype) + private List findDirectTransformers(String sourceMimetype, String targetMimetype, TransformationOptions options) { - double maxReliability = 0.0; - List bestTransformers = new ArrayList(2); + //double maxReliability = 0.0; + + List transformers = new ArrayList(2); + boolean foundExplicit = false; + // loop through transformers for (ContentTransformer transformer : this.transformers) { - double reliability = transformer.getReliability(sourceMimetype, targetMimetype); - if (reliability <= 0.0) + if (transformer.isTransformable(sourceMimetype, targetMimetype, options) == true) { - // it is unusable - continue; + if (transformer.isExplicitTransformation(sourceMimetype, targetMimetype, options) == true) + { + if (foundExplicit == false) + { + transformers.clear(); + foundExplicit = true; + } + transformers.add(transformer); + } + else + { + if (foundExplicit == false) + { + transformers.add(transformer); + } + } } - else if (reliability < maxReliability) - { - // it is not the best one to use - continue; - } - else if (reliability == maxReliability) - { - // it is as reliable as a previous transformer - } - else - { - // it is better than any previous transformer - wipe them - bestTransformers.clear(); - maxReliability = reliability; - } - // add the transformer to the list - bestTransformers.add(transformer); + +// double reliability = transformer.getReliability(sourceMimetype, targetMimetype); +// if (reliability <= 0.0) +// { +// // it is unusable +// continue; +// } +// else if (reliability < maxReliability) +// { +// // it is not the best one to use +// continue; +// } +// else if (reliability == maxReliability) +// { +// // it is as reliable as a previous transformer +// } +// else +// { +// // it is better than any previous transformer - wipe them +// bestTransformers.clear(); +// maxReliability = reliability; +// } +// // add the transformer to the list +// bestTransformers.add(transformer); } // done - return bestTransformers; + return transformers; } /** * Uses a list of known mimetypes to build transformations from several direct transformations. */ - private List findComplexTransformer(String sourceMimetype, String targetMimetype) + private List findComplexTransformer(String sourceMimetype, String targetMimetype, TransformationOptions options) { // get a complete list of mimetypes // TODO: Build complex transformers by searching for transformations by mimetype @@ -296,7 +311,10 @@ public class ContentTransformerRegistry /** * A key for a combination of a source and target mimetype + * + * @Deprecated since 3.0 */ + @Deprecated public static class TransformationKey { private final String sourceMimetype; diff --git a/source/java/org/alfresco/repo/content/transform/ContentTransformerRegistryTest.java b/source/java/org/alfresco/repo/content/transform/ContentTransformerRegistryTest.java index 0b9df2b016..9cea320628 100644 --- a/source/java/org/alfresco/repo/content/transform/ContentTransformerRegistryTest.java +++ b/source/java/org/alfresco/repo/content/transform/ContentTransformerRegistryTest.java @@ -25,7 +25,6 @@ package org.alfresco.repo.content.transform; import java.util.Collections; -import java.util.Map; import org.alfresco.repo.content.MimetypeMap; import org.alfresco.repo.content.filestore.FileContentReader; @@ -33,6 +32,7 @@ import org.alfresco.repo.content.filestore.FileContentWriter; import org.alfresco.service.cmr.repository.ContentReader; import org.alfresco.service.cmr.repository.ContentWriter; import org.alfresco.service.cmr.repository.MimetypeService; +import org.alfresco.service.cmr.repository.TransformationOptions; import org.alfresco.util.TempFileProvider; /** @@ -46,6 +46,8 @@ public class ContentTransformerRegistryTest extends AbstractContentTransformerTe private static final String B = MimetypeMap.MIMETYPE_XML; private static final String C = MimetypeMap.MIMETYPE_WORD; private static final String D = MimetypeMap.MIMETYPE_HTML; + + private static final TransformationOptions OPTIONS = new TransformationOptions(); /** a real registry with real transformers */ private ContentTransformerRegistry registry; @@ -75,17 +77,17 @@ public class ContentTransformerRegistryTest extends AbstractContentTransformerTe // create the dummyRegistry dummyRegistry = new ContentTransformerRegistry(); // create some dummy transformers for reliability tests - new DummyTransformer(mimetypeService, dummyRegistry, A, B, 0.3, 10L); - new DummyTransformer(mimetypeService, dummyRegistry, A, B, 0.6, 10L); - new DummyTransformer(mimetypeService, dummyRegistry, A, C, 0.5, 10L); - new DummyTransformer(mimetypeService, dummyRegistry, A, C, 1.0, 10L); - new DummyTransformer(mimetypeService, dummyRegistry, B, C, 0.2, 10L); + new DummyTransformer(mimetypeService, dummyRegistry, A, B, 10L); + new DummyTransformer(mimetypeService, dummyRegistry, A, B, 10L); + new DummyTransformer(mimetypeService, dummyRegistry, A, C, 10L); + new DummyTransformer(mimetypeService, dummyRegistry, A, C, 10L); + new DummyTransformer(mimetypeService, dummyRegistry, B, C, 10L); // create some dummy transformers for speed tests - new DummyTransformer(mimetypeService, dummyRegistry, A, D, 1.0, 20L); - new DummyTransformer(mimetypeService, dummyRegistry, A, D, 1.0, 20L); - new DummyTransformer(mimetypeService, dummyRegistry, A, D, 1.0, 10L); // the fast one - new DummyTransformer(mimetypeService, dummyRegistry, A, D, 1.0, 20L); - new DummyTransformer(mimetypeService, dummyRegistry, A, D, 1.0, 20L); + new DummyTransformer(mimetypeService, dummyRegistry, A, D, 20L); + new DummyTransformer(mimetypeService, dummyRegistry, A, D, 20L); + new DummyTransformer(mimetypeService, dummyRegistry, A, D, 10L); // the fast one + new DummyTransformer(mimetypeService, dummyRegistry, A, D, 20L); + new DummyTransformer(mimetypeService, dummyRegistry, A, D, 20L); } /** @@ -100,31 +102,31 @@ public class ContentTransformerRegistryTest extends AbstractContentTransformerTe /** * @return Returns the transformer provided by the real registry */ - protected ContentTransformer getTransformer(String sourceMimetype, String targetMimetype) + protected ContentTransformer getTransformer(String sourceMimetype, String targetMimetype, TransformationOptions options) { - return registry.getTransformer(sourceMimetype, targetMimetype); + return registry.getTransformer(sourceMimetype, targetMimetype, options); } public void testNullRetrieval() throws Exception { ContentTransformer transformer = null; - transformer = dummyRegistry.getTransformer(C, B); + transformer = dummyRegistry.getTransformer(C, B, OPTIONS); assertNull("No transformer expected", transformer); - transformer = dummyRegistry.getTransformer(C, A); + transformer = dummyRegistry.getTransformer(C, A, OPTIONS); assertNull("No transformer expected", transformer); - transformer = dummyRegistry.getTransformer(B, A); + transformer = dummyRegistry.getTransformer(B, A, OPTIONS); assertNull("No transformer expected", transformer); } public void testSimpleRetrieval() throws Exception { ContentTransformer transformer = null; - // B -> C expect 0.2 - transformer = dummyRegistry.getTransformer(B, C); - transformer = dummyRegistry.getTransformer(B, C); + // B -> C expect true + transformer = dummyRegistry.getTransformer(B, C, OPTIONS); + //transformer = dummyRegistry.getTransformer(B, C, OPTIONS); assertNotNull("No transformer found", transformer); - assertEquals("Incorrect reliability", 0.2, transformer.getReliability(B, C)); - assertEquals("Incorrect reliability", 0.0, transformer.getReliability(C, B)); + assertTrue("Incorrect reliability", transformer.isTransformable(B, C, OPTIONS)); + assertFalse("Incorrect reliability", transformer.isTransformable(C, B, OPTIONS)); } /** @@ -135,9 +137,9 @@ public class ContentTransformerRegistryTest extends AbstractContentTransformerTe public void testPerformanceRetrieval() throws Exception { // A -> D expect 1.0, 10ms - ContentTransformer transformer1 = dummyRegistry.getTransformer(A, D); - assertEquals("Incorrect reliability", 1.0, transformer1.getReliability(A, D)); - assertEquals("Incorrect reliability", 0.0, transformer1.getReliability(D, A)); + ContentTransformer transformer1 = dummyRegistry.getTransformer(A, D, OPTIONS); + assertTrue("Incorrect reliability", transformer1.isTransformable(A, D, OPTIONS)); + assertFalse("Incorrect reliability", transformer1.isTransformable(D, A, OPTIONS)); assertEquals("Incorrect transformation time", 10L, transformer1.getTransformationTime()); } @@ -145,15 +147,15 @@ public class ContentTransformerRegistryTest extends AbstractContentTransformerTe { ContentTransformer transformer = null; // A -> B expect 0.6 - transformer = dummyRegistry.getTransformer(A, B); + transformer = dummyRegistry.getTransformer(A, B, OPTIONS); assertNotNull("No transformer found", transformer); - assertEquals("Incorrect reliability", 0.6, transformer.getReliability(A, B)); - assertEquals("Incorrect reliability", 0.0, transformer.getReliability(B, A)); + assertTrue("Incorrect reliability", transformer.isTransformable(A, B, OPTIONS)); + assertFalse("Incorrect reliability", transformer.isTransformable(B, A, OPTIONS)); // A -> C expect 1.0 - transformer = dummyRegistry.getTransformer(A, C); + transformer = dummyRegistry.getTransformer(A, C, OPTIONS); assertNotNull("No transformer found", transformer); - assertEquals("Incorrect reliability", 1.0, transformer.getReliability(A, C)); - assertEquals("Incorrect reliability", 0.0, transformer.getReliability(C, A)); + assertTrue("Incorrect reliability", transformer.isTransformable(A, C, OPTIONS)); + assertFalse("Incorrect reliability", transformer.isTransformable(C, A, OPTIONS)); } /** @@ -162,22 +164,22 @@ public class ContentTransformerRegistryTest extends AbstractContentTransformerTe */ public void testExplicitTransformation() { - AbstractContentTransformer dummyTransformer = new DummyTransformer( + AbstractContentTransformer2 dummyTransformer = new DummyTransformer( mimetypeService, dummyRegistry, MimetypeMap.MIMETYPE_FLASH, MimetypeMap.MIMETYPE_EXCEL, - 1.0, 12345); + 12345); // set an explicit transformation - ContentTransformerRegistry.TransformationKey key = - new ContentTransformerRegistry.TransformationKey( - MimetypeMap.MIMETYPE_FLASH, MimetypeMap.MIMETYPE_EXCEL); + ExplictTransformationDetails key = + new ExplictTransformationDetails( + MimetypeMap.MIMETYPE_FLASH, + MimetypeMap.MIMETYPE_EXCEL); dummyTransformer.setExplicitTransformations(Collections.singletonList(key)); // register again dummyTransformer.register(); // get the appropriate transformer for the bizarre mapping - ContentTransformer checkTransformer = dummyRegistry.getTransformer( - MimetypeMap.MIMETYPE_FLASH, MimetypeMap.MIMETYPE_EXCEL); + ContentTransformer checkTransformer = dummyRegistry.getTransformer(MimetypeMap.MIMETYPE_FLASH, MimetypeMap.MIMETYPE_EXCEL, OPTIONS); assertNotNull("No explicit transformer found", checkTransformer); assertTrue("Expected explicit transformer", dummyTransformer == checkTransformer); @@ -187,39 +189,37 @@ public class ContentTransformerRegistryTest extends AbstractContentTransformerTe * Dummy transformer that does no transformation and scores exactly as it is * told to in the constructor. It enables the tests to be sure of what to expect. */ - private static class DummyTransformer extends AbstractContentTransformer + private static class DummyTransformer extends AbstractContentTransformer2 { private String sourceMimetype; private String targetMimetype; - private double reliability; private long transformationTime; public DummyTransformer( MimetypeService mimetypeService, ContentTransformerRegistry registry, String sourceMimetype, String targetMimetype, - double reliability, long transformationTime) + long transformationTime) { super.setMimetypeService(mimetypeService); super.setRegistry(registry); this.sourceMimetype = sourceMimetype; this.targetMimetype = targetMimetype; - this.reliability = reliability; this.transformationTime = transformationTime; // register register(); } - public double getReliability(String sourceMimetype, String targetMimetype) + public boolean isTransformable(String sourceMimetype, String targetMimetype, TransformationOptions options) { if (this.sourceMimetype.equals(sourceMimetype) && this.targetMimetype.equals(targetMimetype)) { - return reliability; + return true; } else { - return 0.0; + return false; } } @@ -229,7 +229,7 @@ public class ContentTransformerRegistryTest extends AbstractContentTransformerTe public void transformInternal( ContentReader reader, ContentWriter writer, - Map options) throws Exception + TransformationOptions options) throws Exception { // just update the transformation time super.recordTime(transformationTime); @@ -243,4 +243,11 @@ public class ContentTransformerRegistryTest extends AbstractContentTransformerTe return transformationTime; } } + + @Override + protected ContentTransformer getTransformer(String sourceMimetype, String targetMimetype) + { + // TODO Auto-generated method stub + return null; + } } diff --git a/source/java/org/alfresco/repo/content/transform/ExplictTransformationDetails.java b/source/java/org/alfresco/repo/content/transform/ExplictTransformationDetails.java new file mode 100644 index 0000000000..ffb5dee54a --- /dev/null +++ b/source/java/org/alfresco/repo/content/transform/ExplictTransformationDetails.java @@ -0,0 +1,61 @@ +/* + * 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; + +public class ExplictTransformationDetails +{ + private String sourceMimetype; + private String targetMimetype; + + public ExplictTransformationDetails() + { + } + + public ExplictTransformationDetails(String sourceMimetype, String targetMimetype) + { + this.sourceMimetype = sourceMimetype; + this.targetMimetype = targetMimetype; + } + + public void setSourceMimetype(String sourceMimetype) + { + this.sourceMimetype = sourceMimetype; + } + + public String getSourceMimetype() + { + return sourceMimetype; + } + + public void setTargetMimetype(String targetMimetype) + { + this.targetMimetype = targetMimetype; + } + + public String getTargetMimetype() + { + return targetMimetype; + } +} \ No newline at end of file diff --git a/source/java/org/alfresco/repo/content/transform/HtmlParserContentTransformer.java b/source/java/org/alfresco/repo/content/transform/HtmlParserContentTransformer.java index 62e5e3e75f..3bc8866c7c 100644 --- a/source/java/org/alfresco/repo/content/transform/HtmlParserContentTransformer.java +++ b/source/java/org/alfresco/repo/content/transform/HtmlParserContentTransformer.java @@ -25,11 +25,11 @@ package org.alfresco.repo.content.transform; import java.io.File; -import java.util.Map; import org.alfresco.repo.content.MimetypeMap; import org.alfresco.service.cmr.repository.ContentReader; import org.alfresco.service.cmr.repository.ContentWriter; +import org.alfresco.service.cmr.repository.TransformationOptions; import org.alfresco.util.TempFileProvider; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -41,28 +41,29 @@ import org.htmlparser.beans.StringBean; * * @author Derek Hulley */ -public class HtmlParserContentTransformer extends AbstractContentTransformer +public class HtmlParserContentTransformer extends AbstractContentTransformer2 { + @SuppressWarnings("unused") private static final Log logger = LogFactory.getLog(HtmlParserContentTransformer.class); /** * Only support HTML to TEXT. */ - public double getReliability(String sourceMimetype, String targetMimetype) + public boolean isTransformable(String sourceMimetype, String targetMimetype, TransformationOptions options) { if (!MimetypeMap.MIMETYPE_HTML.equals(sourceMimetype) || !MimetypeMap.MIMETYPE_TEXT_PLAIN.equals(targetMimetype)) { // only support HTML -> TEXT - return 0.0; + return false; } else { - return 1.0; + return true; } } - public void transformInternal(ContentReader reader, ContentWriter writer, Map options) + public void transformInternal(ContentReader reader, ContentWriter writer, TransformationOptions options) throws Exception { // we can only work from a file diff --git a/source/java/org/alfresco/repo/content/transform/HtmlParserContentTransformerTest.java b/source/java/org/alfresco/repo/content/transform/HtmlParserContentTransformerTest.java index 316bb21ffb..f4a15586bb 100644 --- a/source/java/org/alfresco/repo/content/transform/HtmlParserContentTransformerTest.java +++ b/source/java/org/alfresco/repo/content/transform/HtmlParserContentTransformerTest.java @@ -25,6 +25,7 @@ package org.alfresco.repo.content.transform; import org.alfresco.repo.content.MimetypeMap; +import org.alfresco.service.cmr.repository.TransformationOptions; /** * @see org.alfresco.repo.content.transform.HtmlParserContentTransformer @@ -52,14 +53,14 @@ public class HtmlParserContentTransformerTest extends AbstractContentTransformer assertNotNull(transformer); } - public void checkReliability() throws Exception + public void checkIsTransformable() throws Exception { // check reliability - double reliability = transformer.getReliability(MimetypeMap.MIMETYPE_HTML, MimetypeMap.MIMETYPE_TEXT_PLAIN); - assertEquals("Reliability incorrect", 1.0, reliability); // plain text to plain text is 100% + boolean reliability = transformer.isTransformable(MimetypeMap.MIMETYPE_HTML, MimetypeMap.MIMETYPE_TEXT_PLAIN, new TransformationOptions()); + assertTrue(reliability); // plain text to plain text is supported // check other way around - reliability = transformer.getReliability(MimetypeMap.MIMETYPE_TEXT_PLAIN, MimetypeMap.MIMETYPE_HTML); - assertEquals("Reliability incorrect", 0.0, reliability); // plain text to plain text is 0% + reliability = transformer.isTransformable(MimetypeMap.MIMETYPE_TEXT_PLAIN, MimetypeMap.MIMETYPE_HTML, new TransformationOptions()); + assertFalse(reliability); // plain text to plain text is not supported } } diff --git a/source/java/org/alfresco/repo/content/transform/MailContentTransformer.java b/source/java/org/alfresco/repo/content/transform/MailContentTransformer.java index 010d766bb6..d49e284eec 100644 --- a/source/java/org/alfresco/repo/content/transform/MailContentTransformer.java +++ b/source/java/org/alfresco/repo/content/transform/MailContentTransformer.java @@ -26,12 +26,12 @@ package org.alfresco.repo.content.transform; import java.io.IOException; import java.io.InputStream; -import java.util.Map; import org.alfresco.repo.content.MimetypeMap; import org.alfresco.service.cmr.repository.ContentIOException; import org.alfresco.service.cmr.repository.ContentReader; import org.alfresco.service.cmr.repository.ContentWriter; +import org.alfresco.service.cmr.repository.TransformationOptions; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.poi.poifs.eventfilesystem.POIFSReader; @@ -44,7 +44,7 @@ import org.apache.poi.poifs.filesystem.DocumentInputStream; * * @author Kevin Roast */ -public class MailContentTransformer extends AbstractContentTransformer +public class MailContentTransformer extends AbstractContentTransformer2 { private static final Log logger = LogFactory.getLog(MailContentTransformer.class); @@ -54,17 +54,17 @@ public class MailContentTransformer extends AbstractContentTransformer /** * Only support MSG to text */ - public double getReliability(String sourceMimetype, String targetMimetype) + public boolean isTransformable(String sourceMimetype, String targetMimetype, TransformationOptions options) { if (!MimetypeMap.MIMETYPE_RFC822.equals(sourceMimetype) || !MimetypeMap.MIMETYPE_TEXT_PLAIN.equals(targetMimetype)) { // only support MSG -> TEXT - return 0.0; + return false; } else { - return 1.0; + return true; } } @@ -72,7 +72,7 @@ public class MailContentTransformer extends AbstractContentTransformer * @see org.alfresco.repo.content.transform.AbstractContentTransformer#transformInternal(org.alfresco.service.cmr.repository.ContentReader, org.alfresco.service.cmr.repository.ContentWriter, java.util.Map) */ @Override - protected void transformInternal(final ContentReader reader, ContentWriter writer, Map options) + protected void transformInternal(final ContentReader reader, ContentWriter writer, TransformationOptions options) throws Exception { final StringBuilder sb = new StringBuilder(); diff --git a/source/java/org/alfresco/repo/content/transform/MailContentTransformerTest.java b/source/java/org/alfresco/repo/content/transform/MailContentTransformerTest.java index 5a1f4aa245..9a397939ba 100644 --- a/source/java/org/alfresco/repo/content/transform/MailContentTransformerTest.java +++ b/source/java/org/alfresco/repo/content/transform/MailContentTransformerTest.java @@ -31,6 +31,7 @@ import org.alfresco.repo.content.filestore.FileContentReader; import org.alfresco.repo.content.filestore.FileContentWriter; import org.alfresco.service.cmr.repository.ContentReader; import org.alfresco.service.cmr.repository.ContentWriter; +import org.alfresco.service.cmr.repository.TransformationOptions; import org.alfresco.util.TempFileProvider; /** @@ -58,13 +59,10 @@ public class MailContentTransformerTest extends AbstractContentTransformerTest return transformer; } - public void testReliability() throws Exception + public void testIsTransformable() throws Exception { - double reliability = 0.0; - reliability = transformer.getReliability(MimetypeMap.MIMETYPE_TEXT_PLAIN, MimetypeMap.MIMETYPE_RFC822); - assertEquals("Mimetype should not be supported", 0.0, reliability); - reliability = transformer.getReliability(MimetypeMap.MIMETYPE_RFC822, MimetypeMap.MIMETYPE_TEXT_PLAIN); - assertEquals("Mimetype should be supported", 1.0, reliability); + assertFalse(transformer.isTransformable(MimetypeMap.MIMETYPE_TEXT_PLAIN, MimetypeMap.MIMETYPE_RFC822, new TransformationOptions())); + assertTrue(transformer.isTransformable(MimetypeMap.MIMETYPE_RFC822, MimetypeMap.MIMETYPE_TEXT_PLAIN, new TransformationOptions())); } /** diff --git a/source/java/org/alfresco/repo/content/transform/MediaWikiContentTransformer.java b/source/java/org/alfresco/repo/content/transform/MediaWikiContentTransformer.java index a97d59c101..b8a80cd663 100644 --- a/source/java/org/alfresco/repo/content/transform/MediaWikiContentTransformer.java +++ b/source/java/org/alfresco/repo/content/transform/MediaWikiContentTransformer.java @@ -29,7 +29,6 @@ import info.bliki.wiki.model.WikiModel; import info.bliki.wiki.tags.ATag; import java.util.List; -import java.util.Map; import org.alfresco.repo.content.MimetypeMap; import org.alfresco.service.cmr.model.FileFolderService; @@ -38,6 +37,7 @@ 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.NodeService; +import org.alfresco.service.cmr.repository.TransformationOptions; import org.htmlcleaner.ContentToken; /** @@ -47,7 +47,7 @@ import org.htmlcleaner.ContentToken; * * @author Roy Wetherall */ -public class MediaWikiContentTransformer extends AbstractContentTransformer +public class MediaWikiContentTransformer extends AbstractContentTransformer2 { /** The file folder service */ private FileFolderService fileFolderService; @@ -76,35 +76,36 @@ public class MediaWikiContentTransformer extends AbstractContentTransformer } /** - * Only support MEDIAWIKI to HTML - */ - public double getReliability(String sourceMimetype, String targetMimetype) + * Only transform from mediawiki to html + * + * @see org.alfresco.repo.content.transform.ContentTransformer#isTransformable(java.lang.String, java.lang.String, org.alfresco.service.cmr.repository.TransformationOptions) + */public boolean isTransformable(String sourceMimetype, String targetMimetype, TransformationOptions options) { if (!MimetypeMap.MIMETYPE_TEXT_MEDIAWIKI.equals(sourceMimetype) || !MimetypeMap.MIMETYPE_HTML.equals(targetMimetype)) { // only support MEDIAWIKI -> HTML - return 0.0; + return false; } else { - return 1.0; + return true; } } - /** - * @see org.alfresco.repo.content.transform.AbstractContentTransformer#transformInternal(org.alfresco.service.cmr.repository.ContentReader, org.alfresco.service.cmr.repository.ContentWriter, java.util.Map) - */ - public void transformInternal(ContentReader reader, ContentWriter writer, Map options) + /** + * @see org.alfresco.repo.content.transform.AbstractContentTransformer2#transformInternal(org.alfresco.service.cmr.repository.ContentReader, org.alfresco.service.cmr.repository.ContentWriter, org.alfresco.service.cmr.repository.TransformationOptions) + */ + public void transformInternal(ContentReader reader, ContentWriter writer, TransformationOptions options) throws Exception { String imageURL = "{$image}"; String pageURL = "${title}"; - if (options.containsKey(ContentTransformer.OPT_DESTINATION_NODEREF) == true) + // If we have context about the destination of the transformation then use it + if (options.getTargetNodeRef() != null) { - NodeRef destinationNodeRef = (NodeRef)options.get(ContentTransformer.OPT_DESTINATION_NODEREF); - NodeRef parentNodeRef = this.nodeService.getPrimaryParent(destinationNodeRef).getParentRef(); + NodeRef parentNodeRef = this.nodeService.getPrimaryParent(options.getTargetNodeRef()).getParentRef(); StringBuffer folderPath = new StringBuffer(256); List fileInfos = this.fileFolderService.getNamePath(null, parentNodeRef); @@ -124,6 +125,11 @@ public class MediaWikiContentTransformer extends AbstractContentTransformer writer.putContent(wikiModel.render(reader.getContentString())); } + /** + * Alfresco custom Wiki model used to generate links and image references + * + * @author Roy Wetherall + */ private class AlfrescoWikiModel extends WikiModel { public AlfrescoWikiModel(String imageBaseURL, String linkBaseURL) diff --git a/source/java/org/alfresco/repo/content/transform/MediaWikiContentTransformerTest.java b/source/java/org/alfresco/repo/content/transform/MediaWikiContentTransformerTest.java index 38c196aac7..08c9451eee 100644 --- a/source/java/org/alfresco/repo/content/transform/MediaWikiContentTransformerTest.java +++ b/source/java/org/alfresco/repo/content/transform/MediaWikiContentTransformerTest.java @@ -33,6 +33,7 @@ import org.alfresco.repo.content.filestore.FileContentReader; import org.alfresco.repo.content.filestore.FileContentWriter; import org.alfresco.service.cmr.repository.ContentReader; import org.alfresco.service.cmr.repository.ContentWriter; +import org.alfresco.service.cmr.repository.TransformationOptions; import de.schlichtherle.io.FileOutputStream; @@ -85,15 +86,11 @@ public class MediaWikiContentTransformerTest extends AbstractContentTransformerT assertNotNull(transformer); } - public void checkReliability() throws Exception + public void testIsTransformable() throws Exception { // check reliability - double reliability = transformer.getReliability(MimetypeMap.MIMETYPE_TEXT_MEDIAWIKI, MimetypeMap.MIMETYPE_HTML); - assertEquals("Reliability incorrect", 1.0, reliability); // plain text to html is 100% - - // check other way around - reliability = transformer.getReliability(MimetypeMap.MIMETYPE_HTML, MimetypeMap.MIMETYPE_TEXT_MEDIAWIKI); - assertEquals("Reliability incorrect", 0.0, reliability); // html to plain text is 0% + assertTrue(transformer.isTransformable(MimetypeMap.MIMETYPE_TEXT_MEDIAWIKI, MimetypeMap.MIMETYPE_HTML, new TransformationOptions())); + assertFalse(transformer.isTransformable(MimetypeMap.MIMETYPE_HTML, MimetypeMap.MIMETYPE_TEXT_MEDIAWIKI, new TransformationOptions())); } public void testMediaWikiToHTML() throws Exception diff --git a/source/java/org/alfresco/repo/content/transform/OpenOfficeContentTransformer.java b/source/java/org/alfresco/repo/content/transform/OpenOfficeContentTransformer.java index 00e33ba2db..a169f18a8e 100644 --- a/source/java/org/alfresco/repo/content/transform/OpenOfficeContentTransformer.java +++ b/source/java/org/alfresco/repo/content/transform/OpenOfficeContentTransformer.java @@ -27,7 +27,6 @@ package org.alfresco.repo.content.transform; import java.io.File; import java.io.IOException; import java.io.InputStream; -import java.util.Map; import net.sf.jooreports.converter.DocumentFamily; import net.sf.jooreports.converter.DocumentFormat; @@ -43,6 +42,7 @@ import org.alfresco.service.cmr.repository.ContentIOException; import org.alfresco.service.cmr.repository.ContentReader; import org.alfresco.service.cmr.repository.ContentWriter; import org.alfresco.service.cmr.repository.MimetypeService; +import org.alfresco.service.cmr.repository.TransformationOptions; import org.alfresco.util.PropertyCheck; import org.alfresco.util.TempFileProvider; import org.springframework.core.io.DefaultResourceLoader; @@ -53,7 +53,7 @@ import org.springframework.core.io.DefaultResourceLoader; * * @author Derek Hulley */ -public class OpenOfficeContentTransformer extends AbstractContentTransformer +public class OpenOfficeContentTransformer extends AbstractContentTransformer2 { private OpenOfficeConnection connection; private OpenOfficeDocumentConverter converter; @@ -119,22 +119,22 @@ public class OpenOfficeContentTransformer extends AbstractContentTransformer /** * @see DocumentFormatRegistry */ - public double getReliability(String sourceMimetype, String targetMimetype) + public boolean isTransformable(String sourceMimetype, String targetMimetype, TransformationOptions options) { if (!isConnected()) { // The connection management is must take care of this - return 0.0; + return false; } // there are some conversions that fail, despite the converter believing them possible if (targetMimetype.equals(MimetypeMap.MIMETYPE_XHTML)) { - return 0.0; + return false; } else if (targetMimetype.equals(MimetypeMap.MIMETYPE_WORDPERFECT)) { - return 0.0; + return false; } MimetypeService mimetypeService = getMimetypeService(); @@ -145,14 +145,14 @@ public class OpenOfficeContentTransformer extends AbstractContentTransformer if (sourceFormat == null) { // no document format - return 0.0; + return false; } // query the registry for the target format DocumentFormat targetFormat = formatRegistry.getFormatByFileExtension(targetExtension); if (targetFormat == null) { // no document format - return 0.0; + return false; } // get the family of the target document @@ -161,18 +161,18 @@ public class OpenOfficeContentTransformer extends AbstractContentTransformer if (!targetFormat.isExportableFrom(sourceFamily)) { // unable to export from source family of documents to the target format - return 0.0; + return false; } else { - return 1.0; + return true; } } protected void transformInternal( ContentReader reader, ContentWriter writer, - Map options) throws Exception + TransformationOptions options) throws Exception { String sourceMimetype = getMimetype(reader); String targetMimetype = getMimetype(writer); diff --git a/source/java/org/alfresco/repo/content/transform/OpenOfficeContentTransformerTest.java b/source/java/org/alfresco/repo/content/transform/OpenOfficeContentTransformerTest.java index 9f410b6a90..b54647f6a1 100644 --- a/source/java/org/alfresco/repo/content/transform/OpenOfficeContentTransformerTest.java +++ b/source/java/org/alfresco/repo/content/transform/OpenOfficeContentTransformerTest.java @@ -33,6 +33,7 @@ import org.alfresco.repo.content.filestore.FileContentReader; import org.alfresco.repo.content.filestore.FileContentWriter; import org.alfresco.service.cmr.repository.ContentReader; import org.alfresco.service.cmr.repository.ContentWriter; +import org.alfresco.service.cmr.repository.TransformationOptions; import org.alfresco.util.TempFileProvider; /** @@ -81,17 +82,16 @@ public class OpenOfficeContentTransformerTest extends AbstractContentTransformer // no connection return; } - double reliability = 0.0; - reliability = transformer.getReliability(MIMETYPE_RUBBISH, MimetypeMap.MIMETYPE_TEXT_PLAIN); - assertEquals("Mimetype should not be supported", 0.0, reliability); - reliability = transformer.getReliability(MimetypeMap.MIMETYPE_TEXT_PLAIN, MIMETYPE_RUBBISH); - assertEquals("Mimetype should not be supported", 0.0, reliability); - reliability = transformer.getReliability(MimetypeMap.MIMETYPE_TEXT_PLAIN, MimetypeMap.MIMETYPE_XHTML); - assertEquals("Mimetype should not be supported", 0.0, reliability); - reliability = transformer.getReliability(MimetypeMap.MIMETYPE_TEXT_PLAIN, MimetypeMap.MIMETYPE_WORD); - assertEquals("Mimetype should be supported", 1.0, reliability); - reliability = transformer.getReliability(MimetypeMap.MIMETYPE_WORD, MimetypeMap.MIMETYPE_TEXT_PLAIN); - assertEquals("Mimetype should be supported", 1.0, reliability); + boolean reliability = transformer.isTransformable(MIMETYPE_RUBBISH, MimetypeMap.MIMETYPE_TEXT_PLAIN, new TransformationOptions()); + assertEquals("Mimetype should not be supported", false, reliability); + reliability = transformer.isTransformable(MimetypeMap.MIMETYPE_TEXT_PLAIN, MIMETYPE_RUBBISH, new TransformationOptions()); + assertEquals("Mimetype should not be supported", false, reliability); + reliability = transformer.isTransformable(MimetypeMap.MIMETYPE_TEXT_PLAIN, MimetypeMap.MIMETYPE_XHTML, new TransformationOptions()); + assertEquals("Mimetype should not be supported", false, reliability); + reliability = transformer.isTransformable(MimetypeMap.MIMETYPE_TEXT_PLAIN, MimetypeMap.MIMETYPE_WORD, new TransformationOptions()); + assertEquals("Mimetype should be supported", true, reliability); + reliability = transformer.isTransformable(MimetypeMap.MIMETYPE_WORD, MimetypeMap.MIMETYPE_TEXT_PLAIN, new TransformationOptions()); + assertEquals("Mimetype should be supported", true, reliability); } /** diff --git a/source/java/org/alfresco/repo/content/transform/PdfBoxContentTransformer.java b/source/java/org/alfresco/repo/content/transform/PdfBoxContentTransformer.java index 699d075684..7f07f33b55 100644 --- a/source/java/org/alfresco/repo/content/transform/PdfBoxContentTransformer.java +++ b/source/java/org/alfresco/repo/content/transform/PdfBoxContentTransformer.java @@ -25,11 +25,11 @@ package org.alfresco.repo.content.transform; import java.io.InputStream; -import java.util.Map; import org.alfresco.repo.content.MimetypeMap; import org.alfresco.service.cmr.repository.ContentReader; import org.alfresco.service.cmr.repository.ContentWriter; +import org.alfresco.service.cmr.repository.TransformationOptions; import org.pdfbox.pdmodel.PDDocument; import org.pdfbox.util.PDFTextStripper; @@ -39,12 +39,12 @@ import org.pdfbox.util.PDFTextStripper; * * @author Derek Hulley */ -public class PdfBoxContentTransformer extends AbstractContentTransformer +public class PdfBoxContentTransformer extends AbstractContentTransformer2 { /** * Currently the only transformation performed is that of text extraction from PDF documents. */ - public double getReliability(String sourceMimetype, String targetMimetype) + public boolean isTransformable(String sourceMimetype, String targetMimetype, TransformationOptions options) { // TODO: Expand PDFBox usage to convert images to PDF and investigate other conversions @@ -52,18 +52,18 @@ public class PdfBoxContentTransformer extends AbstractContentTransformer !MimetypeMap.MIMETYPE_TEXT_PLAIN.equals(targetMimetype)) { // only support PDF -> Text - return 0.0; + return false; } else { - return 1.0; + return true; } } protected void transformInternal( ContentReader reader, ContentWriter writer, - Map options) throws Exception + TransformationOptions options) throws Exception { PDDocument pdf = null; InputStream is = null; diff --git a/source/java/org/alfresco/repo/content/transform/PdfBoxContentTransformerTest.java b/source/java/org/alfresco/repo/content/transform/PdfBoxContentTransformerTest.java index 415998e3ca..d6c8356a24 100644 --- a/source/java/org/alfresco/repo/content/transform/PdfBoxContentTransformerTest.java +++ b/source/java/org/alfresco/repo/content/transform/PdfBoxContentTransformerTest.java @@ -25,6 +25,7 @@ package org.alfresco.repo.content.transform; import org.alfresco.repo.content.MimetypeMap; +import org.alfresco.service.cmr.repository.TransformationOptions; /** * @see org.alfresco.repo.content.transform.PdfBoxContentTransformer @@ -51,12 +52,9 @@ public class PdfBoxContentTransformerTest extends AbstractContentTransformerTest return transformer; } - public void testReliability() throws Exception + public void testIsTransformable() throws Exception { - double reliability = 0.0; - reliability = transformer.getReliability(MimetypeMap.MIMETYPE_TEXT_PLAIN, MimetypeMap.MIMETYPE_PDF); - assertEquals("Mimetype should not be supported", 0.0, reliability); - reliability = transformer.getReliability(MimetypeMap.MIMETYPE_PDF, MimetypeMap.MIMETYPE_TEXT_PLAIN); - assertEquals("Mimetype should be supported", 1.0, reliability); + assertFalse(transformer.isTransformable(MimetypeMap.MIMETYPE_TEXT_PLAIN, MimetypeMap.MIMETYPE_PDF, new TransformationOptions())); + assertTrue(transformer.isTransformable(MimetypeMap.MIMETYPE_PDF, MimetypeMap.MIMETYPE_TEXT_PLAIN, new TransformationOptions())); } } diff --git a/source/java/org/alfresco/repo/content/transform/PoiHssfContentTransformer.java b/source/java/org/alfresco/repo/content/transform/PoiHssfContentTransformer.java index ebe7e8cdf6..77e818e6b5 100644 --- a/source/java/org/alfresco/repo/content/transform/PoiHssfContentTransformer.java +++ b/source/java/org/alfresco/repo/content/transform/PoiHssfContentTransformer.java @@ -26,11 +26,11 @@ package org.alfresco.repo.content.transform; import java.io.InputStream; import java.io.OutputStream; -import java.util.Map; import org.alfresco.repo.content.MimetypeMap; import org.alfresco.service.cmr.repository.ContentReader; import org.alfresco.service.cmr.repository.ContentWriter; +import org.alfresco.service.cmr.repository.TransformationOptions; import org.apache.poi.hssf.usermodel.HSSFCell; import org.apache.poi.hssf.usermodel.HSSFRow; import org.apache.poi.hssf.usermodel.HSSFSheet; @@ -51,7 +51,7 @@ import org.apache.poi.hssf.usermodel.HSSFWorkbook; * * @author Derek Hulley */ -public class PoiHssfContentTransformer extends AbstractContentTransformer +public class PoiHssfContentTransformer extends AbstractContentTransformer2 { /** * Windows carriage return line feed pair. @@ -61,21 +61,21 @@ public class PoiHssfContentTransformer extends AbstractContentTransformer /** * Currently the only transformation performed is that of text extraction from XLS documents. */ - public double getReliability(String sourceMimetype, String targetMimetype) + public boolean isTransformable(String sourceMimetype, String targetMimetype, TransformationOptions options) { if (!MimetypeMap.MIMETYPE_EXCEL.equals(sourceMimetype) || !MimetypeMap.MIMETYPE_TEXT_PLAIN.equals(targetMimetype)) { // only support XLS -> Text - return 0.0; + return false; } else { - return 1.0; + return true; } } - public void transformInternal(ContentReader reader, ContentWriter writer, Map options) + public void transformInternal(ContentReader reader, ContentWriter writer, TransformationOptions options) throws Exception { InputStream is = reader.getContentInputStream(); @@ -135,6 +135,7 @@ public class PoiHssfContentTransformer extends AbstractContentTransformer } } + @SuppressWarnings("deprecation") private void writeRow(OutputStream os, HSSFRow row, String encoding) throws Exception { short firstCellNum = row.getFirstCellNum(); diff --git a/source/java/org/alfresco/repo/content/transform/PoiHssfContentTransformerTest.java b/source/java/org/alfresco/repo/content/transform/PoiHssfContentTransformerTest.java index de356cc695..df5aa2a5fb 100644 --- a/source/java/org/alfresco/repo/content/transform/PoiHssfContentTransformerTest.java +++ b/source/java/org/alfresco/repo/content/transform/PoiHssfContentTransformerTest.java @@ -30,6 +30,7 @@ import java.io.InputStream; import org.alfresco.repo.content.MimetypeMap; import org.alfresco.repo.content.filestore.FileContentWriter; import org.alfresco.service.cmr.repository.ContentReader; +import org.alfresco.service.cmr.repository.TransformationOptions; import org.alfresco.util.TempFileProvider; /** @@ -57,13 +58,10 @@ public class PoiHssfContentTransformerTest extends AbstractContentTransformerTes return transformer; } - public void testReliability() throws Exception + public void testIsTransformable() throws Exception { - double reliability = 0.0; - reliability = transformer.getReliability(MimetypeMap.MIMETYPE_TEXT_PLAIN, MimetypeMap.MIMETYPE_EXCEL); - assertEquals("Mimetype should not be supported", 0.0, reliability); - reliability = transformer.getReliability(MimetypeMap.MIMETYPE_EXCEL, MimetypeMap.MIMETYPE_TEXT_PLAIN); - assertEquals("Mimetype should be supported", 1.0, reliability); + assertFalse(transformer.isTransformable(MimetypeMap.MIMETYPE_TEXT_PLAIN, MimetypeMap.MIMETYPE_EXCEL, new TransformationOptions())); + assertTrue(transformer.isTransformable(MimetypeMap.MIMETYPE_EXCEL, MimetypeMap.MIMETYPE_TEXT_PLAIN, new TransformationOptions())); } /** diff --git a/source/java/org/alfresco/repo/content/transform/RuntimeExecutableContentTransformer.java b/source/java/org/alfresco/repo/content/transform/RuntimeExecutableContentTransformer.java index 889aa1651d..f26d33ee1d 100644 --- a/source/java/org/alfresco/repo/content/transform/RuntimeExecutableContentTransformer.java +++ b/source/java/org/alfresco/repo/content/transform/RuntimeExecutableContentTransformer.java @@ -30,10 +30,10 @@ import java.util.List; import java.util.Map; import org.alfresco.error.AlfrescoRuntimeException; -import org.alfresco.repo.content.transform.ContentTransformerRegistry.TransformationKey; import org.alfresco.service.cmr.repository.ContentIOException; import org.alfresco.service.cmr.repository.ContentReader; import org.alfresco.service.cmr.repository.ContentWriter; +import org.alfresco.service.cmr.repository.TransformationOptions; import org.alfresco.util.TempFileProvider; import org.alfresco.util.exec.RuntimeExec; import org.alfresco.util.exec.RuntimeExec.ExecutionResult; @@ -67,7 +67,7 @@ import org.apache.commons.logging.LogFactory; * @since 1.1 * @author Derek Hulley */ -public class RuntimeExecutableContentTransformer extends AbstractContentTransformer +public class RuntimeExecutableContentTransformer extends AbstractContentTransformer2 { public static final String VAR_SOURCE = "source"; public static final String VAR_TARGET = "target"; @@ -168,28 +168,20 @@ public class RuntimeExecutableContentTransformer extends AbstractContentTransfor * * @see AbstractContentTransformer#setExplicitTransformations(List) */ - public double getReliability(String sourceMimetype, String targetMimetype) + public boolean isTransformable(String sourceMimetype, String targetMimetype, TransformationOptions options) { if (!available) { - return 0.0; + return false; } - // check whether the transformation was one of the explicit transformations - TransformationKey transformationKey = new TransformationKey(sourceMimetype, targetMimetype); - List explicitTransformations = getExplicitTransformations(); - if (explicitTransformations.size() == 0) + + if (isExplicitTransformation(sourceMimetype, targetMimetype, options) == true) { - logger.warn( - "Property 'explicitTransformations' should be set to enable this transformer: \n" + - " transformer: " + this); - } - if (explicitTransformations.contains(transformationKey)) - { - return 1.0; + return true; } else { - return 0.0; + return false; } } @@ -202,7 +194,7 @@ public class RuntimeExecutableContentTransformer extends AbstractContentTransfor protected final void transformInternal( ContentReader reader, ContentWriter writer, - Map options) throws Exception + TransformationOptions options) throws Exception { // get mimetypes String sourceMimetype = getMimetype(reader); @@ -230,11 +222,15 @@ public class RuntimeExecutableContentTransformer extends AbstractContentTransfor Map properties = new HashMap(5); // copy options over - for (Map.Entry entry : options.entrySet()) + if (options instanceof RuntimeExecutableContentTransformerOptions) { - String key = entry.getKey(); - Object value = entry.getValue(); - properties.put(key, (value == null ? null : value.toString())); + RuntimeExecutableContentTransformerOptions runtimeOptions = (RuntimeExecutableContentTransformerOptions)options; + for (Map.Entry entry : runtimeOptions.getPropertyValues().entrySet()) + { + String key = entry.getKey(); + Object value = entry.getValue(); + properties.put(key, (value == null ? null : value.toString())); + } } // add the source and target properties properties.put(VAR_SOURCE, sourceFile.getAbsolutePath()); diff --git a/source/java/org/alfresco/repo/content/transform/RuntimeExecutableContentTransformerOptions.java b/source/java/org/alfresco/repo/content/transform/RuntimeExecutableContentTransformerOptions.java new file mode 100644 index 0000000000..5b233a4d7f --- /dev/null +++ b/source/java/org/alfresco/repo/content/transform/RuntimeExecutableContentTransformerOptions.java @@ -0,0 +1,64 @@ +/* + * 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; + +import java.util.HashMap; +import java.util.Map; + +import org.alfresco.service.cmr.repository.TransformationOptions; + +/** + * Transformation options for the runtime executable transformer. + *

+ * Values set here are mapped to ${valueName} style strings in the tranformer + * execution string. + * + * @author Roy Wetherall + */ +public class RuntimeExecutableContentTransformerOptions extends TransformationOptions +{ + /** Map of property values */ + private Map propertyValues = new HashMap(1); + + /** + * Sets the map of property values that are used when executing the transformer + * + * @param propertyValues property value + */ + public void setPropertyValues(Map propertyValues) + { + this.propertyValues = propertyValues; + } + + /** + * Gets the map of property values that are used when executing the transformer + * + * @return Map property values + */ + public Map getPropertyValues() + { + return propertyValues; + } +} diff --git a/source/java/org/alfresco/repo/content/transform/RuntimeExecutableContentTransformerTest.java b/source/java/org/alfresco/repo/content/transform/RuntimeExecutableContentTransformerTest.java index 1c8019b20d..32467fd151 100644 --- a/source/java/org/alfresco/repo/content/transform/RuntimeExecutableContentTransformerTest.java +++ b/source/java/org/alfresco/repo/content/transform/RuntimeExecutableContentTransformerTest.java @@ -32,13 +32,11 @@ import java.util.Map; import org.alfresco.repo.content.MimetypeMap; import org.alfresco.repo.content.filestore.FileContentWriter; -import org.alfresco.repo.content.transform.ContentTransformerRegistry.TransformationKey; import org.alfresco.service.cmr.repository.ContentReader; import org.alfresco.service.cmr.repository.ContentWriter; import org.alfresco.util.BaseAlfrescoTestCase; import org.alfresco.util.TempFileProvider; import org.alfresco.util.exec.RuntimeExec; -import org.apache.xml.security.transforms.TransformationException; /** * @see org.alfresco.repo.content.transform.RuntimeExecutableContentTransformer @@ -65,9 +63,9 @@ public class RuntimeExecutableContentTransformerTest extends BaseAlfrescoTestCas transformer.setTransformCommand(transformCommand); transformer.setMimetypeService(serviceRegistry.getMimetypeService()); // set the explicit transformations - List explicitTranformations = new ArrayList(1); + List explicitTranformations = new ArrayList(1); explicitTranformations.add( - new TransformationKey(MimetypeMap.MIMETYPE_TEXT_PLAIN, MimetypeMap.MIMETYPE_XML)); + new ExplictTransformationDetails(MimetypeMap.MIMETYPE_TEXT_PLAIN, MimetypeMap.MIMETYPE_XML)); transformer.setExplicitTransformations(explicitTranformations); // initialise so that it doesn't score 0 diff --git a/source/java/org/alfresco/repo/content/transform/StringExtractingContentTransformer.java b/source/java/org/alfresco/repo/content/transform/StringExtractingContentTransformer.java index 213193c56b..1e0ca47c99 100644 --- a/source/java/org/alfresco/repo/content/transform/StringExtractingContentTransformer.java +++ b/source/java/org/alfresco/repo/content/transform/StringExtractingContentTransformer.java @@ -28,11 +28,11 @@ import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.Reader; import java.io.Writer; -import java.util.Map; import org.alfresco.repo.content.MimetypeMap; import org.alfresco.service.cmr.repository.ContentReader; import org.alfresco.service.cmr.repository.ContentWriter; +import org.alfresco.service.cmr.repository.TransformationOptions; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -43,7 +43,7 @@ import org.apache.commons.logging.LogFactory; * * @author Derek Hulley */ -public class StringExtractingContentTransformer extends AbstractContentTransformer +public class StringExtractingContentTransformer extends AbstractContentTransformer2 { public static final String PREFIX_TEXT = "text/"; @@ -56,28 +56,28 @@ public class StringExtractingContentTransformer extends AbstractContentTransform *

* Extraction of text from binary data is wholly unreliable. */ - public double getReliability(String sourceMimetype, String targetMimetype) + public boolean isTransformable(String sourceMimetype, String targetMimetype, TransformationOptions options) { if (!targetMimetype.equals(MimetypeMap.MIMETYPE_TEXT_PLAIN)) { // can only convert to plain text - return 0.0; + return false; } else if (sourceMimetype.equals(MimetypeMap.MIMETYPE_TEXT_PLAIN) || sourceMimetype.equals(MimetypeMap.MIMETYPE_JAVASCRIPT)) { // conversions from any plain text format are very reliable - return 1.0; + return true; } else if (sourceMimetype.startsWith(PREFIX_TEXT)) { // the source is text, but probably with some kind of markup - return 0.1; + return true; } else { // extracting text from binary is not useful - return 0.0; + return false; } } @@ -90,17 +90,17 @@ public class StringExtractingContentTransformer extends AbstractContentTransform * be unformatted but valid. */ @Override - public void transformInternal(ContentReader reader, ContentWriter writer, Map options) + public void transformInternal(ContentReader reader, ContentWriter writer, TransformationOptions options) throws Exception { // is this a straight text-text transformation - transformText(reader, writer); + transformText(reader, writer, options); } /** * Transformation optimized for text-to-text conversion */ - private void transformText(ContentReader reader, ContentWriter writer) throws Exception + private void transformText(ContentReader reader, ContentWriter writer, TransformationOptions options) throws Exception { // get a char reader and writer Reader charReader = null; diff --git a/source/java/org/alfresco/repo/content/transform/StringExtractingContentTransformerTest.java b/source/java/org/alfresco/repo/content/transform/StringExtractingContentTransformerTest.java index f1774370af..ccd9ec5f12 100644 --- a/source/java/org/alfresco/repo/content/transform/StringExtractingContentTransformerTest.java +++ b/source/java/org/alfresco/repo/content/transform/StringExtractingContentTransformerTest.java @@ -38,6 +38,7 @@ import org.alfresco.repo.content.filestore.FileContentReader; import org.alfresco.repo.content.filestore.FileContentWriter; import org.alfresco.service.cmr.repository.ContentReader; import org.alfresco.service.cmr.repository.ContentWriter; +import org.alfresco.service.cmr.repository.TransformationOptions; import org.alfresco.util.TempFileProvider; /** @@ -116,9 +117,8 @@ public class StringExtractingContentTransformerTest extends AbstractContentTrans { ContentReader reader = writeContent("text/plain", "MacDingbat"); - // check reliability - double reliability = transformer.getReliability(reader.getMimetype(), targetWriter.getMimetype()); - assertEquals("Reliability incorrect", 1.0, reliability); // plain text to plain text is 100% + // check transformability + assertTrue(transformer.isTransformable(reader.getMimetype(), targetWriter.getMimetype(), new TransformationOptions())); // transform transformer.transform(reader, targetWriter); @@ -133,9 +133,8 @@ public class StringExtractingContentTransformerTest extends AbstractContentTrans { ContentReader reader = writeContent("text/xml", "MacDingbat"); - // check reliability - double reliability = transformer.getReliability(reader.getMimetype(), targetWriter.getMimetype()); - assertEquals("Reliability incorrect", 0.1, reliability); // markup to plain text not 100% + // check transformability + assertTrue(transformer.isTransformable(reader.getMimetype(), targetWriter.getMimetype(), new TransformationOptions())); // transform transformer.transform(reader, targetWriter); diff --git a/source/java/org/alfresco/repo/content/transform/TextMiningContentTransformer.java b/source/java/org/alfresco/repo/content/transform/TextMiningContentTransformer.java index 1425245faf..5018978045 100644 --- a/source/java/org/alfresco/repo/content/transform/TextMiningContentTransformer.java +++ b/source/java/org/alfresco/repo/content/transform/TextMiningContentTransformer.java @@ -26,11 +26,11 @@ package org.alfresco.repo.content.transform; import java.io.IOException; import java.io.InputStream; -import java.util.Map; import org.alfresco.repo.content.MimetypeMap; import org.alfresco.service.cmr.repository.ContentReader; import org.alfresco.service.cmr.repository.ContentWriter; +import org.alfresco.service.cmr.repository.TransformationOptions; import org.textmining.text.extraction.WordExtractor; /** @@ -39,7 +39,7 @@ import org.textmining.text.extraction.WordExtractor; * * @author Derek Hulley */ -public class TextMiningContentTransformer extends AbstractContentTransformer +public class TextMiningContentTransformer extends AbstractContentTransformer2 { private WordExtractor wordExtractor; @@ -51,21 +51,21 @@ public class TextMiningContentTransformer extends AbstractContentTransformer /** * Currently the only transformation performed is that of text extraction from Word documents. */ - public double getReliability(String sourceMimetype, String targetMimetype) + public boolean isTransformable(String sourceMimetype, String targetMimetype, TransformationOptions options) { if (!MimetypeMap.MIMETYPE_WORD.equals(sourceMimetype) || !MimetypeMap.MIMETYPE_TEXT_PLAIN.equals(targetMimetype)) { // only support DOC -> Text - return 0.0; + return false; } else { - return 1.0; + return true; } } - public void transformInternal(ContentReader reader, ContentWriter writer, Map options) + public void transformInternal(ContentReader reader, ContentWriter writer, TransformationOptions options) throws Exception { InputStream is = null; diff --git a/source/java/org/alfresco/repo/content/transform/TextMiningContentTransformerTest.java b/source/java/org/alfresco/repo/content/transform/TextMiningContentTransformerTest.java index a5bdc59867..677a49fc7d 100644 --- a/source/java/org/alfresco/repo/content/transform/TextMiningContentTransformerTest.java +++ b/source/java/org/alfresco/repo/content/transform/TextMiningContentTransformerTest.java @@ -30,6 +30,7 @@ import java.io.InputStream; import org.alfresco.repo.content.MimetypeMap; import org.alfresco.repo.content.filestore.FileContentWriter; import org.alfresco.service.cmr.repository.ContentReader; +import org.alfresco.service.cmr.repository.TransformationOptions; import org.alfresco.util.TempFileProvider; /** @@ -57,13 +58,10 @@ public class TextMiningContentTransformerTest extends AbstractContentTransformer return transformer; } - public void testReliability() throws Exception + public void testIsTransformable() throws Exception { - double reliability = 0.0; - reliability = transformer.getReliability(MimetypeMap.MIMETYPE_TEXT_PLAIN, MimetypeMap.MIMETYPE_WORD); - assertEquals("Mimetype should not be supported", 0.0, reliability); - reliability = transformer.getReliability(MimetypeMap.MIMETYPE_WORD, MimetypeMap.MIMETYPE_TEXT_PLAIN); - assertEquals("Mimetype should be supported", 1.0, reliability); + assertFalse(transformer.isTransformable(MimetypeMap.MIMETYPE_TEXT_PLAIN, MimetypeMap.MIMETYPE_WORD, new TransformationOptions())); + assertTrue(transformer.isTransformable(MimetypeMap.MIMETYPE_WORD, MimetypeMap.MIMETYPE_TEXT_PLAIN, new TransformationOptions())); } /** diff --git a/source/java/org/alfresco/repo/content/transform/TextToPdfContentTransformer.java b/source/java/org/alfresco/repo/content/transform/TextToPdfContentTransformer.java index 234bdd4ca8..086eebcc2d 100644 --- a/source/java/org/alfresco/repo/content/transform/TextToPdfContentTransformer.java +++ b/source/java/org/alfresco/repo/content/transform/TextToPdfContentTransformer.java @@ -27,12 +27,12 @@ package org.alfresco.repo.content.transform; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; -import java.util.Map; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.repo.content.MimetypeMap; import org.alfresco.service.cmr.repository.ContentReader; import org.alfresco.service.cmr.repository.ContentWriter; +import org.alfresco.service.cmr.repository.TransformationOptions; import org.pdfbox.TextToPDF; import org.pdfbox.pdmodel.PDDocument; import org.pdfbox.pdmodel.font.PDTrueTypeFont; @@ -44,7 +44,7 @@ import org.pdfbox.pdmodel.font.PDType1Font; * @author Derek Hulley * @since 2.1.0 */ -public class TextToPdfContentTransformer extends AbstractContentTransformer +public class TextToPdfContentTransformer extends AbstractContentTransformer2 { private TextToPDF transformer; @@ -92,24 +92,24 @@ public class TextToPdfContentTransformer extends AbstractContentTransformer /** * Only supports Text to PDF */ - public double getReliability(String sourceMimetype, String targetMimetype) + public boolean isTransformable(String sourceMimetype, String targetMimetype, TransformationOptions options) { if (!MimetypeMap.MIMETYPE_TEXT_PLAIN.equals(sourceMimetype) || !MimetypeMap.MIMETYPE_PDF.equals(targetMimetype)) { // only support Text -> PDF - return 0.0; + return false; } else { - return 1.0; + return true; } } protected void transformInternal( ContentReader reader, ContentWriter writer, - Map options) throws Exception + TransformationOptions options) throws Exception { PDDocument pdf = null; InputStream is = null; diff --git a/source/java/org/alfresco/repo/content/transform/TextToPdfContentTransformerTest.java b/source/java/org/alfresco/repo/content/transform/TextToPdfContentTransformerTest.java index 7f7b1a13f5..b6096b160f 100644 --- a/source/java/org/alfresco/repo/content/transform/TextToPdfContentTransformerTest.java +++ b/source/java/org/alfresco/repo/content/transform/TextToPdfContentTransformerTest.java @@ -25,6 +25,7 @@ package org.alfresco.repo.content.transform; import org.alfresco.repo.content.MimetypeMap; +import org.alfresco.service.cmr.repository.TransformationOptions; /** * @see org.alfresco.repo.content.transform.TextToPdfContentTransformer @@ -56,10 +57,9 @@ public class TextToPdfContentTransformerTest extends AbstractContentTransformerT public void testReliability() throws Exception { - double reliability = 0.0; - reliability = transformer.getReliability(MimetypeMap.MIMETYPE_PDF, MimetypeMap.MIMETYPE_TEXT_PLAIN); - assertEquals("Mimetype should not be supported", 0.0, reliability); - reliability = transformer.getReliability(MimetypeMap.MIMETYPE_TEXT_PLAIN, MimetypeMap.MIMETYPE_PDF); - assertEquals("Mimetype should be supported", 1.0, reliability); + boolean reliability = transformer.isTransformable(MimetypeMap.MIMETYPE_PDF, MimetypeMap.MIMETYPE_TEXT_PLAIN, new TransformationOptions()); + assertEquals("Mimetype should not be supported", false, reliability); + reliability = transformer.isTransformable(MimetypeMap.MIMETYPE_TEXT_PLAIN, MimetypeMap.MIMETYPE_PDF, new TransformationOptions()); + assertEquals("Mimetype should be supported", true, reliability); } } diff --git a/source/java/org/alfresco/repo/content/transform/TransformTestSuite.java b/source/java/org/alfresco/repo/content/transform/TransformTestSuite.java new file mode 100644 index 0000000000..dfcc741093 --- /dev/null +++ b/source/java/org/alfresco/repo/content/transform/TransformTestSuite.java @@ -0,0 +1,66 @@ +/* + * 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; + +import org.alfresco.repo.content.transform.magick.ImageMagickContentTransformerTest; +import org.alfresco.repo.content.transform.magick.JMagickContentTransformerTest; + +import junit.framework.Test; +import junit.framework.TestSuite; + + +/** + * Version test suite + * + * @author Roy Wetherall + */ +public class TransformTestSuite extends TestSuite +{ + /** + * Creates the test suite + * + * @return the test suite + */ + public static Test suite() + { + TestSuite suite = new TestSuite(); + suite.addTestSuite(BinaryPassThroughContentTransformerTest.class); + suite.addTestSuite(ComplexContentTransformerTest.class); + suite.addTestSuite(ContentTransformerRegistryTest.class); + suite.addTestSuite(HtmlParserContentTransformerTest.class); + suite.addTestSuite(MailContentTransformerTest.class); + suite.addTestSuite(MediaWikiContentTransformerTest.class); + suite.addTestSuite(OpenOfficeContentTransformerTest.class); + suite.addTestSuite(PdfBoxContentTransformerTest.class); + suite.addTestSuite(PoiHssfContentTransformerTest.class); + suite.addTestSuite(RuntimeExecutableContentTransformerTest.class); + suite.addTestSuite(StringExtractingContentTransformerTest.class); + 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/AbstractImageMagickContentTransformer.java b/source/java/org/alfresco/repo/content/transform/magick/AbstractImageMagickContentTransformer.java index 8913532d86..66fd2f6cb4 100644 --- a/source/java/org/alfresco/repo/content/transform/magick/AbstractImageMagickContentTransformer.java +++ b/source/java/org/alfresco/repo/content/transform/magick/AbstractImageMagickContentTransformer.java @@ -26,16 +26,15 @@ package org.alfresco.repo.content.transform.magick; import java.io.File; import java.io.InputStream; -import java.util.Collections; -import java.util.Map; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.repo.content.MimetypeMap; import org.alfresco.repo.content.filestore.FileContentWriter; -import org.alfresco.repo.content.transform.AbstractContentTransformer; +import org.alfresco.repo.content.transform.AbstractContentTransformer2; import org.alfresco.service.cmr.repository.ContentIOException; import org.alfresco.service.cmr.repository.ContentReader; import org.alfresco.service.cmr.repository.ContentWriter; +import org.alfresco.service.cmr.repository.TransformationOptions; import org.alfresco.util.TempFileProvider; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -45,7 +44,7 @@ import org.apache.commons.logging.LogFactory; * * @author Derek Hulley */ -public abstract class AbstractImageMagickContentTransformer extends AbstractContentTransformer +public abstract class AbstractImageMagickContentTransformer extends AbstractContentTransformer2 { /** the prefix for mimetypes supported by the transformer */ public static final String MIMETYPE_IMAGE_PREFIX = "image/"; @@ -111,8 +110,7 @@ public abstract class AbstractImageMagickContentTransformer extends AbstractCont ".png"); // execute it - Map options = Collections.emptyMap(); - transformInternal(inputFile, outputFile, options); + transformInternal(inputFile, outputFile, new TransformationOptions()); // check that the file exists if (!outputFile.exists()) @@ -167,21 +165,21 @@ public abstract class AbstractImageMagickContentTransformer extends AbstractCont * Supports image to image conversion, but only if the JMagick library and required * libraries are available. */ - public double getReliability(String sourceMimetype, String targetMimetype) + public boolean isTransformable(String sourceMimetype, String targetMimetype, TransformationOptions options) { if (!available) { - return 0.0; + return false; } if (!AbstractImageMagickContentTransformer.isSupported(sourceMimetype) || !AbstractImageMagickContentTransformer.isSupported(targetMimetype)) { // only support IMAGE -> IMAGE (excl. RGB) - return 0.0; + return false; } else { - return 1.0; + return true; } } @@ -191,7 +189,7 @@ public abstract class AbstractImageMagickContentTransformer extends AbstractCont protected final void transformInternal( ContentReader reader, ContentWriter writer, - Map options) throws Exception + TransformationOptions options) throws Exception { // get mimetypes String sourceMimetype = getMimetype(reader); @@ -251,5 +249,5 @@ public abstract class AbstractImageMagickContentTransformer extends AbstractCont protected abstract void transformInternal( File sourceFile, File targetFile, - Map options) throws Exception; + TransformationOptions options) throws Exception; } 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 f13ed1c470..6a60a36ef6 100644 --- a/source/java/org/alfresco/repo/content/transform/magick/ImageMagickContentTransformer.java +++ b/source/java/org/alfresco/repo/content/transform/magick/ImageMagickContentTransformer.java @@ -30,6 +30,7 @@ import java.util.Map; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.service.cmr.repository.ContentIOException; +import org.alfresco.service.cmr.repository.TransformationOptions; import org.alfresco.util.exec.RuntimeExec; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -41,14 +42,12 @@ import org.apache.commons.logging.LogFactory; */ public class ImageMagickContentTransformer extends AbstractImageMagickContentTransformer { - /** the command options, such as --resize, etc. */ - public static final String KEY_OPTIONS = "options"; + /** options variable name */ + private static final String KEY_OPTIONS = "options"; /** source variable name */ - public static final String VAR_OPTIONS = "options"; - /** source variable name */ - public static final String VAR_SOURCE = "source"; + private static final String VAR_SOURCE = "source"; /** target variable name */ - public static final String VAR_TARGET = "target"; + private static final String VAR_TARGET = "target"; private static final Log logger = LogFactory.getLog(ImageMagickContentTransformer.class); @@ -95,11 +94,14 @@ public class ImageMagickContentTransformer extends AbstractImageMagickContentTra /** * Transform the image content from the source file to the target file */ - protected void transformInternal(File sourceFile, File targetFile, Map options) throws Exception + protected void transformInternal(File sourceFile, File targetFile, TransformationOptions options) throws Exception { Map properties = new HashMap(5); // set properties - properties.put(KEY_OPTIONS, (String) options.get(KEY_OPTIONS)); + if (options instanceof ImageTransformationOptions) + { + properties.put(KEY_OPTIONS, (String) ((ImageTransformationOptions)options).getCommandOptions()); + } properties.put(VAR_SOURCE, sourceFile.getAbsolutePath()); properties.put(VAR_TARGET, targetFile.getAbsolutePath()); diff --git a/source/java/org/alfresco/repo/content/transform/magick/ImageMagickContentTransformerTest.java b/source/java/org/alfresco/repo/content/transform/magick/ImageMagickContentTransformerTest.java index db37bf66f0..d3298aa774 100644 --- a/source/java/org/alfresco/repo/content/transform/magick/ImageMagickContentTransformerTest.java +++ b/source/java/org/alfresco/repo/content/transform/magick/ImageMagickContentTransformerTest.java @@ -29,6 +29,7 @@ import java.util.Collections; 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; import org.alfresco.util.exec.RuntimeExec; /** @@ -69,10 +70,9 @@ public class ImageMagickContentTransformerTest extends AbstractContentTransforme { return; } - double reliability = 0.0; - reliability = transformer.getReliability(MimetypeMap.MIMETYPE_IMAGE_GIF, MimetypeMap.MIMETYPE_TEXT_PLAIN); - assertEquals("Mimetype should not be supported", 0.0, reliability); - reliability = transformer.getReliability(MimetypeMap.MIMETYPE_IMAGE_GIF, MimetypeMap.MIMETYPE_IMAGE_JPEG); - assertEquals("Mimetype should be supported", 1.0, reliability); + 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/content/transform/magick/ImageTransformationOptions.java b/source/java/org/alfresco/repo/content/transform/magick/ImageTransformationOptions.java new file mode 100644 index 0000000000..156f93bc76 --- /dev/null +++ b/source/java/org/alfresco/repo/content/transform/magick/ImageTransformationOptions.java @@ -0,0 +1,45 @@ +/* + * 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.service.cmr.repository.TransformationOptions; + +/** + * @author Roy Wetherall + */ +public class ImageTransformationOptions extends TransformationOptions +{ + private String commandOptions = ""; + + public void setCommandOptions(String commandOptions) + { + this.commandOptions = commandOptions; + } + + public String getCommandOptions() + { + return commandOptions; + } +} diff --git a/source/java/org/alfresco/repo/content/transform/magick/JMagickContentTransformer.java b/source/java/org/alfresco/repo/content/transform/magick/JMagickContentTransformer.java index 0bde223692..1954e5fe15 100644 --- a/source/java/org/alfresco/repo/content/transform/magick/JMagickContentTransformer.java +++ b/source/java/org/alfresco/repo/content/transform/magick/JMagickContentTransformer.java @@ -25,11 +25,11 @@ package org.alfresco.repo.content.transform.magick; import java.io.File; -import java.util.Map; 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; @@ -41,6 +41,7 @@ import org.apache.commons.logging.LogFactory; */ public class JMagickContentTransformer extends AbstractImageMagickContentTransformer { + @SuppressWarnings("unused") private static final Log logger = LogFactory.getLog(JMagickContentTransformer.class); public JMagickContentTransformer() @@ -55,7 +56,7 @@ public class JMagickContentTransformer extends AbstractImageMagickContentTransfo * @throws Exception */ @Override - protected void transformInternal(File sourceFile, File targetFile, Map options) throws Exception + protected void transformInternal(File sourceFile, File targetFile, TransformationOptions options) throws Exception { ImageInfo imageInfo = new ImageInfo(sourceFile.getAbsolutePath()); MagickImage image = new MagickImage(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 index 66c628cf9b..bfcfcf36d7 100644 --- a/source/java/org/alfresco/repo/content/transform/magick/JMagickContentTransformerTest.java +++ b/source/java/org/alfresco/repo/content/transform/magick/JMagickContentTransformerTest.java @@ -27,6 +27,7 @@ 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 @@ -61,10 +62,9 @@ public class JMagickContentTransformerTest extends AbstractContentTransformerTes { return; } - double reliability = 0.0; - reliability = transformer.getReliability(MimetypeMap.MIMETYPE_IMAGE_GIF, MimetypeMap.MIMETYPE_TEXT_PLAIN); - assertEquals("Mimetype should not be supported", 0.0, reliability); - reliability = transformer.getReliability(MimetypeMap.MIMETYPE_IMAGE_GIF, MimetypeMap.MIMETYPE_IMAGE_JPEG); - assertEquals("Mimetype should be supported", 1.0, reliability); + 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/jscript/ScriptNode.java b/source/java/org/alfresco/repo/jscript/ScriptNode.java index 12127b4184..a22f6c13d3 100644 --- a/source/java/org/alfresco/repo/jscript/ScriptNode.java +++ b/source/java/org/alfresco/repo/jscript/ScriptNode.java @@ -38,7 +38,7 @@ import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.model.ApplicationModel; import org.alfresco.model.ContentModel; import org.alfresco.repo.action.executer.TransformActionExecuter; -import org.alfresco.repo.content.transform.magick.ImageMagickContentTransformer; +import org.alfresco.repo.content.transform.magick.ImageTransformationOptions; import org.alfresco.repo.search.QueryParameterDefImpl; import org.alfresco.repo.version.VersionModel; import org.alfresco.service.ServiceRegistry; @@ -1742,9 +1742,12 @@ public class ScriptNode implements Serializable, Scopeable public ScriptNode transform(ContentService contentService, NodeRef nodeRef, ContentReader reader, ContentWriter writer) { - Map opts = new HashMap(1); - opts.put(ImageMagickContentTransformer.KEY_OPTIONS, options != null ? options : ""); - contentService.getImageTransformer().transform(reader, writer, opts); + ImageTransformationOptions imageOptions = new ImageTransformationOptions(); + if (options != null) + { + imageOptions.setCommandOptions(options); + } + contentService.getImageTransformer().transform(reader, writer, imageOptions); return newInstance(nodeRef, services, scope); } diff --git a/source/java/org/alfresco/repo/rule/RuleServiceCoverageTest.java b/source/java/org/alfresco/repo/rule/RuleServiceCoverageTest.java index 548f46a102..a45762ce62 100644 --- a/source/java/org/alfresco/repo/rule/RuleServiceCoverageTest.java +++ b/source/java/org/alfresco/repo/rule/RuleServiceCoverageTest.java @@ -79,6 +79,7 @@ import org.alfresco.service.cmr.repository.CopyService; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.StoreRef; +import org.alfresco.service.cmr.repository.TransformationOptions; import org.alfresco.service.cmr.rule.Rule; import org.alfresco.service.cmr.rule.RuleService; import org.alfresco.service.cmr.rule.RuleServiceException; @@ -836,7 +837,7 @@ public class RuleServiceCoverageTest extends TestCase */ public void testTransformAction() { - if (this.transformerRegistry.getTransformer(MimetypeMap.MIMETYPE_EXCEL, MimetypeMap.MIMETYPE_TEXT_PLAIN) != null) + if (this.transformerRegistry.getTransformer(MimetypeMap.MIMETYPE_EXCEL, MimetypeMap.MIMETYPE_TEXT_PLAIN, new TransformationOptions()) != null) { try { @@ -920,7 +921,7 @@ public class RuleServiceCoverageTest extends TestCase */ public void testImageTransformAction() { - if (this.transformerRegistry.getTransformer(MimetypeMap.MIMETYPE_IMAGE_GIF, MimetypeMap.MIMETYPE_IMAGE_JPEG) != null) + if (this.transformerRegistry.getTransformer(MimetypeMap.MIMETYPE_IMAGE_GIF, MimetypeMap.MIMETYPE_IMAGE_JPEG, new TransformationOptions()) != null) { try { @@ -1653,7 +1654,7 @@ public class RuleServiceCoverageTest extends TestCase public void testAsyncExecutionWithPotentialLoop() { - if (this.transformerRegistry.getTransformer(MimetypeMap.MIMETYPE_EXCEL, MimetypeMap.MIMETYPE_TEXT_PLAIN) != null) + if (this.transformerRegistry.getTransformer(MimetypeMap.MIMETYPE_EXCEL, MimetypeMap.MIMETYPE_TEXT_PLAIN, new TransformationOptions()) != null) { try { diff --git a/source/java/org/alfresco/repo/thumbnail/ThumbnailServiceImpl.java b/source/java/org/alfresco/repo/thumbnail/ThumbnailServiceImpl.java new file mode 100644 index 0000000000..852f284795 --- /dev/null +++ b/source/java/org/alfresco/repo/thumbnail/ThumbnailServiceImpl.java @@ -0,0 +1,149 @@ +/* + * 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.thumbnail; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.alfresco.model.ContentModel; +import org.alfresco.service.cmr.repository.ContentService; +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.thumbnail.ThumbnailService; +import org.alfresco.service.cmr.thumbnail.GenerateOptions.ParentAssociationDetails; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.namespace.QName; +import org.alfresco.util.GUID; + +/** + * @author Roy Wetherall + */ +public class ThumbnailServiceImpl implements ThumbnailService +{ + /** Node service */ + private NodeService nodeService; + + /** Content service */ + private ContentService contentService; + + /** + * Set the node service + * + * @param nodeService node service + */ + public void setNodeService(NodeService nodeService) + { + this.nodeService = nodeService; + } + + /** + * Set the content service + * + * @param contentService content service + */ + public void setContentService(ContentService contentService) + { + this.contentService = contentService; + } + + /** + * @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) + { + NodeRef thumbnail = null; + + // Apply the thumbnailed aspect to the node if it doesn't already have it + if (this.nodeService.hasAspect(node, ContentModel.ASPECT_THUMBNAILED) == false) + { + this.nodeService.addAspect(node, ContentModel.ASPECT_THUMBNAILED, null); + } + + // Get the name of the thumbnail and add to properties map + String thumbnailName = createOptions.getThumbnailName(); + 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 .. + + // See if parent association details have been specified for the thumbnail + ParentAssociationDetails assocDetails = createOptions.getParentAssociationDetails(); + if (assocDetails == null) + { + // Create the thumbnail using the thumbnails child association + thumbnail = this.nodeService.createNode( + node, + ContentModel.ASSOC_THUMBNAILS, + QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, thumbnailName), + ContentModel.TYPE_THUMBNAIL, + properties).getChildRef(); + } + else + { + // Create the thumbnail using the specified parent assoc details + thumbnail = this.nodeService.createNode( + assocDetails.getParent(), + assocDetails.getAssociationType(), + assocDetails.getAssociationName(), + ContentModel.TYPE_THUMBNAIL, + properties).getChildRef(); + + // Associate the new thumbnail to the source + this.nodeService.addChild( + node, + thumbnail, + ContentModel.ASSOC_THUMBNAILS, + QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, thumbnailName)); + } + + // TODO .. do the work of actually creating the thumbnail content ... + + // 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) + */ + public List getThumbnails(NodeRef node, QName contentProperty, AcceptOptions acceptOptions) + { + return null; + } + + /** + * @see org.alfresco.service.cmr.thumbnail.ThumbnailService#updateThumbnail(org.alfresco.service.cmr.repository.NodeRef) + */ + public void updateThumbnail(NodeRef thumbnail) + { + } + +} diff --git a/source/java/org/alfresco/repo/thumbnail/ThumbnailServiceImplTest.java b/source/java/org/alfresco/repo/thumbnail/ThumbnailServiceImplTest.java new file mode 100644 index 0000000000..dd9d5e71c4 --- /dev/null +++ b/source/java/org/alfresco/repo/thumbnail/ThumbnailServiceImplTest.java @@ -0,0 +1,60 @@ +/* + * 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.thumbnail; + +import org.alfresco.service.cmr.repository.ContentService; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.cmr.thumbnail.ThumbnailService; +import org.alfresco.util.BaseSpringTest; + +/** + * Thumbnail service implementation unit test + * + * @author Roy Wetherall + */ +public class ThumbnailServiceImplTest extends BaseSpringTest +{ + private NodeService nodeService; + private ContentService contentService; + private ThumbnailService thumbnailService; + + /** + * 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"); + + } + + public void testCreateThumbnail() throws Exception + { + + } + +} diff --git a/source/java/org/alfresco/service/cmr/repository/ContentService.java b/source/java/org/alfresco/service/cmr/repository/ContentService.java index bdfdae3a7b..0c163a6c0b 100644 --- a/source/java/org/alfresco/service/cmr/repository/ContentService.java +++ b/source/java/org/alfresco/service/cmr/repository/ContentService.java @@ -147,6 +147,7 @@ public interface ContentService /** * @see org.aflresco.service.cmr.repository.ContentService.transform(ContentReader, ContentReader) + * @see org.aflresco.service.cmr.repository.ContentService.transform(ContentReader, ContentWriter, TransformationOptions) * * A map of transform options can be provided. * @@ -156,24 +157,68 @@ public interface ContentService * @throws NoTransformerException if no transformer exists for the * given source and target mimetypes of the reader and writer * @throws ContentIOException if the transformation fails + * + * @depricated + * As of release 3.0 the TransformOptions class should be used to pass transformation options + * to a transformation execution. */ @Auditable(parameters = {"reader", "writer", "options"}) + @Deprecated public void transform(ContentReader reader, ContentWriter writer, Map options) throws NoTransformerException, ContentIOException; + /** + * @see org.aflresco.service.cmr.repository.ContentService.transform(ContentReader, ContentReader) + * + * A transformation options can be provided. + * + * @param reader the source content location and mimetype + * @param writer the target content location and mimetype + * @param options the options for the transformation + * @throws NoTransformerException if no transformer exists for the + * given source and target mimetypes of the reader and writer + * @throws ContentIOException if the transformation fails + */ + @Auditable(parameters = {"reader", "writer", "options"}) + public void transform(ContentReader reader, ContentWriter writer, TransformationOptions options) + throws NoTransformerException, ContentIOException; + /** * Fetch the transformer that is capable of transforming the content in the * given source mimetype to the given target mimetype. + *

+ * Since no transformation options are provided only the source and destination mimetypes are + * considered when getting the correct transformer. * * @param the source mimetype * @param the target mimetype * @return Returns a transformer that can be used, or null if one was not available * + * @see org.alfresco.service.cmr.respository.ContentService.getTransformer(String, String, TransformationOptions) * @see ContentAccessor#getMimetype() */ @Auditable(parameters = {"sourceMimetype", "targetMimetype"}) public ContentTransformer getTransformer(String sourceMimetype, String targetMimetype); + /** + * Fetch the transformer that is capable of transforming the content in the + * given source mimetype to the given target mimetype with the provided transformation + * options. + *

+ * The transformation options provide a finer grain way of discoving the correct transformer, + * since the values and type of the options provided are considered by the transformer when + * deciding whether it can satisfy the transformation request. + * + * @param sourceMimetype the source mimetype + * @param targetMimetype the target mimetype + * @param options the transformation options + * @return ContentTransformer a transformer that can be used, or null if one was not available + * + * @see ContentAccessor#getMimetype() + */ + @Auditable(parameters = {"sourceMimetype", "targetMimetype", "options"}) + public ContentTransformer getTransformer(String sourceMimetype, String targetMimetype, TransformationOptions options); + /** * Fetch the transformer that is capable of transforming image content. * @@ -186,6 +231,9 @@ public interface ContentService * Returns whether a transformer exists that can read the content from * the reader and write the content back out to the writer. *

+ * Since no transformation options are specified, only the source and target + * mimetypes will be considered when making this decision. + *

* The mimetypes used for the transformation must be set both on * the {@link ContentAccessor#getMimetype() reader} and on the * {@link ContentAccessor#getMimetype() writer}. @@ -194,7 +242,26 @@ public interface ContentService * @param writer the target content location and mimetype * * @return true if a transformer exists, false otherwise + * + * @see org.alfresco.service.cmr.repository.ContentService.isTransformable(ContentReader, ContentWriter, TransformationOptions) */ @Auditable(parameters = {"reader", "writer"}) public boolean isTransformable(ContentReader reader, ContentWriter writer); + + /** + * Returns whether a transformer exists that can read the content from + * the reader and write the content back out to the writer with the + * provided tranformation options. + *

+ * The mimetypes used for the transformation must be set both on + * the {@link ContentAccessor#getMimetype() reader} and on the + * {@link ContentAccessor#getMimetype() writer}. + * + * @param reader the source content location and mimetype + * @param writer the target content location and mimetype + * @param options the transformation options + * @return boolean true if a transformer exists, false otherwise + */ + @Auditable(parameters = {"reader", "writer", "options"}) + public boolean isTransformable(ContentReader reader, ContentWriter writer, TransformationOptions options); } diff --git a/source/java/org/alfresco/service/cmr/repository/TransformationOptions.java b/source/java/org/alfresco/service/cmr/repository/TransformationOptions.java new file mode 100644 index 0000000000..f95a950452 --- /dev/null +++ b/source/java/org/alfresco/service/cmr/repository/TransformationOptions.java @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2005-2008 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.service.cmr.repository; + +import java.util.HashMap; +import java.util.Map; + +import org.alfresco.service.namespace.QName; + +/** + * Tansformation options. + *

+ * Class containing values of options that are passed to content transformers. These options + * are used to determine the applicability of a content transformer and also during the + * transformation process to provide context or parameter values. + * + * @author Roy Wetherall + */ +public class TransformationOptions +{ + /** Option map names to preserve backward compatibility */ + public static final String OPT_SOURCE_NODEREF = "sourceNodeRef"; + public static final String OPT_SOURCE_CONTENT_PROPERTY = "sourceContentProperty"; + public static final String OPT_TARGET_NODEREF = "targetNodeRef"; + public static final String OPT_TARGET_CONTENT_PROPERTY = "targetContentProperty"; + + /** The source node reference */ + private NodeRef sourceNodeRef; + + /** The source content property */ + private QName sourceContentProperty; + + /** The target node reference */ + private NodeRef targetNodeRef; + + /** The target content property */ + private QName targetContentProperty; + + /** + * Default construtor + */ + public TransformationOptions() + { + } + + /** + * Constructor + * + * @param sourceNodeRef the source node reference + * @param sourceContentProperty the source content property + * @param targetNodeRef the target node reference + * @param targetContentProperty the target content property + */ + public TransformationOptions(NodeRef sourceNodeRef, QName sourceContentProperty, NodeRef targetNodeRef, QName targetContentProperty) + { + this.sourceNodeRef = sourceNodeRef; + this.sourceContentProperty = sourceContentProperty; + this.targetNodeRef = targetNodeRef; + this.targetContentProperty = targetContentProperty; + } + + /** + * Constrcutor. Creates a transformation options object from a map. + * Provided for back ward compatibility. + * + * @param optionsMap options map + */ + public TransformationOptions(Map optionsMap) + { + fromMapImpl(optionsMap); + } + + /** + * Set the source node reference + * + * @param sourceNodeRef the source node reference + */ + public void setSourceNodeRef(NodeRef sourceNodeRef) + { + this.sourceNodeRef = sourceNodeRef; + } + + /** + * Gets the source node reference + * + * @return NodeRef the source node reference + */ + public NodeRef getSourceNodeRef() + { + return sourceNodeRef; + } + + /** + * Set the source content property + * + * @param sourceContentProperty the source content property + */ + public void setSourceContentProperty(QName sourceContentProperty) + { + this.sourceContentProperty = sourceContentProperty; + } + + /** + * Get the source content property + * + * @return the source content property + */ + public QName getSourceContentProperty() + { + return sourceContentProperty; + } + + /** + * Set the taget node reference + * + * @param targetNodeRef the target node reference + */ + public void setTargetNodeRef(NodeRef targetNodeRef) + { + this.targetNodeRef = targetNodeRef; + } + + /** + * Get the target node reference + * + * @return the target node reference + */ + public NodeRef getTargetNodeRef() + { + return targetNodeRef; + } + + /** + * Set the target content property + * + * @param targetContentProperty the target content property + */ + public void setTargetContentProperty(QName targetContentProperty) + { + this.targetContentProperty = targetContentProperty; + } + + /** + * Get the target content property + * + * @return the target property + */ + public QName getTargetContentProperty() + { + return targetContentProperty; + } + + /** + * Converts the transformation options object into an equivalent map + * + * @return + */ + public Map toMap() + { + return new HashMap(10); + } + + protected void toMapImpl(Map optionsMap) + { + optionsMap.put(OPT_SOURCE_NODEREF, getSourceNodeRef()); + optionsMap.put(OPT_SOURCE_CONTENT_PROPERTY, getSourceContentProperty()); + optionsMap.put(OPT_TARGET_NODEREF, getTargetNodeRef()); + optionsMap.put(OPT_TARGET_CONTENT_PROPERTY, getTargetContentProperty()); + } + + protected void fromMapImpl(Map optionsMap) + { + this.sourceNodeRef = (NodeRef)optionsMap.get(OPT_SOURCE_NODEREF); + 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); + } + +} diff --git a/source/java/org/alfresco/service/cmr/thumbnail/AcceptOptions.java b/source/java/org/alfresco/service/cmr/thumbnail/AcceptOptions.java new file mode 100644 index 0000000000..5e8e1fd8c6 --- /dev/null +++ b/source/java/org/alfresco/service/cmr/thumbnail/AcceptOptions.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2005-2008 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.service.cmr.thumbnail; + + +/** + * @author Roy Wetherall + */ +public class AcceptOptions +{ + +} diff --git a/source/java/org/alfresco/service/cmr/thumbnail/GenerateOptions.java b/source/java/org/alfresco/service/cmr/thumbnail/GenerateOptions.java new file mode 100644 index 0000000000..3b522b9561 --- /dev/null +++ b/source/java/org/alfresco/service/cmr/thumbnail/GenerateOptions.java @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2005-2008 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.service.cmr.thumbnail; + +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.namespace.QName; +import org.alfresco.util.ParameterCheck; + +/** + * This class provides the thumbnail generate options to the thumbnail service. + * + * @author Roy Wetherall + */ +public class GenerateOptions +{ + /** Parent association details */ + private ParentAssociationDetails assocDetails; + + /** Name of the thumbnail */ + private String thumbnailName; + + /** + * Default constructor. + */ + public GenerateOptions() + { + } + + /** + * Constructor. Specify the name of the thumbnail. + * + * @param thumbnailName the name of the thumbnail, can be null + */ + public GenerateOptions(String thumbnailName) + { + this.thumbnailName= thumbnailName; + } + + /** + * Constructor. Specify the parent association details of the thumbnail. + * + * @param thumnailName the name of the thumbnail, can be null + * @param parent the parent node reference + * @param assocType the child association type + * @param asscoName the child association name + */ + public GenerateOptions(String thumbnailName, NodeRef parent, QName assocType, QName assocName) + { + this.assocDetails = new ParentAssociationDetails(parent, assocType, assocName); + this.thumbnailName = thumbnailName; + } + + /** + * Gets the name of the thumbnail + * + * @return String the name of the thumbnail, null if non specified + */ + public String getThumbnailName() + { + return thumbnailName; + } + + /** + * Get the parent association details + * + * @return ParentAssociationDetails the parent association details + */ + public ParentAssociationDetails getParentAssociationDetails() + { + return this.assocDetails; + } + + /** + * Encapsulates the details of a thumbnails parent association + */ + public class ParentAssociationDetails + { + /** The parent node reference */ + private NodeRef parent; + + /** The child association type */ + private QName assocType; + + /** The child association name */ + private QName assocName; + + /** + * Constructor. All parameters must be specified. + * + * @param parent the parent node reference + * @param assocType the child association type + * @param assocName the child association name + */ + public ParentAssociationDetails(NodeRef parent, QName assocType, QName assocName) + { + // Make sure all the details of the parent are provided + ParameterCheck.mandatory("parent", parent); + ParameterCheck.mandatory("assocType", assocType); + ParameterCheck.mandatory("assocName", assocName); + + // Set the values + this.parent = parent; + this.assocType = assocType; + this.assocName = assocName; + } + + /** + * Get the parent node reference + * + * @return NodeRef the parent node reference + */ + public NodeRef getParent() + { + return parent; + } + + /** + * Get the child association type + * + * @return QName the child association type + */ + public QName getAssociationType() + { + return assocType; + } + + /** + * Get the child association name + * + * @return QName the child association name + */ + public QName getAssociationName() + { + return assocName; + } + + } +} diff --git a/source/java/org/alfresco/service/cmr/thumbnail/ThumbnailService.java b/source/java/org/alfresco/service/cmr/thumbnail/ThumbnailService.java new file mode 100644 index 0000000000..54d38d694a --- /dev/null +++ b/source/java/org/alfresco/service/cmr/thumbnail/ThumbnailService.java @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2005-2008 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.service.cmr.thumbnail; + +import java.util.List; + +import org.alfresco.service.Auditable; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.namespace.QName; + +/** + * Thumbnail Service API + * + * @author Roy Wetherall (based on original contribution by Ray Gauss II) + */ +public interface ThumbnailService +{ + /** + * Creates a new thumbnail for the given node and content property. + * + * The passed create options specify the details of the thumbnail, including the + * mimetpye, size and location of the thumbnail. + * + * Once created the source node will have the 'tn:thumbnailed' aspect applied and an + * association to the thumbnail node (or type 'tn:thumbnail') will be created. + * + * The returned node reference is to the 'tn:thumbnail' content node that contains + * the thumnail content in the standard 'cm:content' property. + * + * @see org.alfresco.service.cmr.thumnail.GenerateOptions + * + * @param node the source content node + * @param contentProperty the content property + * @param createOptions the create options + * @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); + + /** + * Updates the content of a thumbnail. + * + * The original creation options are used when updating the thumbnail. The content of + * the associated thumbnailed node is used to update. + * + * An error is raised if the original content no longer exisits. + * + * @param thumbnail the thumbnail node + */ + @Auditable(key = Auditable.Key.ARG_0, parameters = {"thumbnail"}) + 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 + */ + @Auditable(key = Auditable.Key.ARG_0, parameters = {"node", "contentProperty", "acceptOptions"}) + List getThumbnails(NodeRef node, QName contentProperty, AcceptOptions acceptOptions); +} diff --git a/source/java/org/alfresco/util/OpenOfficeConnectionTester.java b/source/java/org/alfresco/util/OpenOfficeConnectionTester.java index 170cdd381c..932e969eee 100644 --- a/source/java/org/alfresco/util/OpenOfficeConnectionTester.java +++ b/source/java/org/alfresco/util/OpenOfficeConnectionTester.java @@ -31,7 +31,6 @@ import net.sf.jooreports.openoffice.connection.OpenOfficeConnection; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.i18n.I18NUtil; import org.alfresco.repo.content.metadata.MetadataExtracterRegistry; -import org.alfresco.repo.content.transform.ContentTransformerRegistry; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.quartz.Job; @@ -194,13 +193,7 @@ public class OpenOfficeConnectionTester extends AbstractLifecycleBean if (metadataExractorRegistryObj != null && (metadataExractorRegistryObj instanceof MetadataExtracterRegistry)) { metadataExtracterRegistry = (MetadataExtracterRegistry) metadataExractorRegistryObj; - } - Object contentTransformerRegistryObj = jobData.get("contentTransformerRegistry"); - ContentTransformerRegistry contentTransformerRegistry = null; - if (contentTransformerRegistryObj != null && (contentTransformerRegistryObj instanceof ContentTransformerRegistry)) - { - contentTransformerRegistry = (ContentTransformerRegistry) contentTransformerRegistryObj; - } + } // Now ping the connection. It doesn't matter if it fails or not. boolean connected = openOfficeConnectionTester.testAndConnect(); @@ -229,10 +222,6 @@ public class OpenOfficeConnectionTester extends AbstractLifecycleBean { metadataExtracterRegistry.resetCache(); } - if (contentTransformerRegistry != null) - { - contentTransformerRegistry.resetCache(); - } } // Record the state OpenOfficeConnectionTesterJob.wasConnected = Boolean.valueOf(connected);