diff --git a/config/alfresco/action-services-context.xml b/config/alfresco/action-services-context.xml index 8e72b96293..eb985bbc28 100644 --- a/config/alfresco/action-services-context.xml +++ b/config/alfresco/action-services-context.xml @@ -422,6 +422,9 @@ + + + diff --git a/config/alfresco/content-services-context.xml b/config/alfresco/content-services-context.xml index c30e87e247..9da13521b0 100644 --- a/config/alfresco/content-services-context.xml +++ b/config/alfresco/content-services-context.xml @@ -328,6 +328,14 @@ class="org.alfresco.repo.content.transform.PdfBoxPdfToImageContentTransformer" parent="unregisteredBaseContentTransformer" /> + + + + + + + diff --git a/source/java/org/alfresco/cmis/mapping/AbstractVersioningProperty.java b/source/java/org/alfresco/cmis/mapping/AbstractVersioningProperty.java index e5d9b9a1b5..69a5bec3b2 100644 --- a/source/java/org/alfresco/cmis/mapping/AbstractVersioningProperty.java +++ b/source/java/org/alfresco/cmis/mapping/AbstractVersioningProperty.java @@ -69,10 +69,13 @@ public abstract class AbstractVersioningProperty extends AbstractProperty return getServiceRegistry().getCheckOutCheckInService().isWorkingCopy(nodeRef); } + public boolean isImmutable(NodeRef nodeRef) + { + return getServiceRegistry().getLockService().getLockType(nodeRef) == LockType.READ_ONLY_LOCK; + } + public boolean hasWorkingCopy(NodeRef nodeRef) { - final ServiceRegistry serviceRegistry = getServiceRegistry(); - return serviceRegistry.getLockService().getLockType(nodeRef) == LockType.READ_ONLY_LOCK - && serviceRegistry.getCheckOutCheckInService().getWorkingCopy(nodeRef) != null; + return isImmutable(nodeRef) && getServiceRegistry().getCheckOutCheckInService().getWorkingCopy(nodeRef) != null; } } diff --git a/source/java/org/alfresco/cmis/mapping/CMISPropertyServiceTest.java b/source/java/org/alfresco/cmis/mapping/CMISPropertyServiceTest.java index f1d1a874ff..c7311c8a44 100644 --- a/source/java/org/alfresco/cmis/mapping/CMISPropertyServiceTest.java +++ b/source/java/org/alfresco/cmis/mapping/CMISPropertyServiceTest.java @@ -191,13 +191,13 @@ public class CMISPropertyServiceTest extends BaseCMISTest properties = cmisService.getProperties(content); assertEquals(properties.get(CMISDictionaryModel.PROP_IS_IMMUTABLE), true); - assertEquals(properties.get(CMISDictionaryModel.PROP_IS_LATEST_VERSION), false); + assertEquals(properties.get(CMISDictionaryModel.PROP_IS_LATEST_VERSION), true); assertEquals(properties.get(CMISDictionaryModel.PROP_IS_MAJOR_VERSION), false); assertEquals(properties.get(CMISDictionaryModel.PROP_IS_LATEST_MAJOR_VERSION), false); assertNotNull(properties.get(CMISDictionaryModel.PROP_VERSION_LABEL)); assertEquals(properties.get(CMISDictionaryModel.PROP_VERSION_SERIES_ID), content.toString()); - assertEquals(properties.get(CMISDictionaryModel.PROP_IS_VERSION_SERIES_CHECKED_OUT), true); - assertEquals(properties.get(CMISDictionaryModel.PROP_VERSION_SERIES_CHECKED_OUT_BY), authenticationComponent.getCurrentUserName()); + assertEquals(properties.get(CMISDictionaryModel.PROP_IS_VERSION_SERIES_CHECKED_OUT), false); + assertEquals(properties.get(CMISDictionaryModel.PROP_VERSION_SERIES_CHECKED_OUT_BY), null); assertEquals(properties.get(CMISDictionaryModel.PROP_VERSION_SERIES_CHECKED_OUT_ID), null); assertEquals(properties.get(CMISDictionaryModel.PROP_CHECKIN_COMMENT), null); diff --git a/source/java/org/alfresco/cmis/mapping/IsImmutableProperty.java b/source/java/org/alfresco/cmis/mapping/IsImmutableProperty.java index 7bfcb9e0de..5f93e91815 100644 --- a/source/java/org/alfresco/cmis/mapping/IsImmutableProperty.java +++ b/source/java/org/alfresco/cmis/mapping/IsImmutableProperty.java @@ -53,7 +53,7 @@ public class IsImmutableProperty extends AbstractVersioningProperty } if (getVersionSeries(nodeRef).equals(nodeRef)) { - return hasWorkingCopy(nodeRef); + return isImmutable(nodeRef); } return true; } diff --git a/source/java/org/alfresco/cmis/renditions/CMISRenditionServiceTest.java b/source/java/org/alfresco/cmis/renditions/CMISRenditionServiceTest.java index 28cbc25906..bac3447020 100644 --- a/source/java/org/alfresco/cmis/renditions/CMISRenditionServiceTest.java +++ b/source/java/org/alfresco/cmis/renditions/CMISRenditionServiceTest.java @@ -34,6 +34,7 @@ import org.alfresco.repo.content.transform.magick.ImageTransformationOptions; import org.alfresco.repo.thumbnail.ThumbnailDefinition; import org.alfresco.service.cmr.repository.ContentReader; import org.alfresco.service.cmr.repository.ContentWriter; +import org.alfresco.service.cmr.repository.NoTransformerException; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.TransformationOptions; @@ -211,10 +212,14 @@ public class CMISRenditionServiceTest extends BaseCMISTest TransformationOptions options = new TransformationOptions(); options.setSourceNodeRef(textDocument); - if (contentService.isTransformable(contentReader, contentWriter, options)) + try { contentService.transform(contentReader, contentWriter, options); } + catch (NoTransformerException e) + { + // ignore + } fileFolderService.delete(textDocument); diff --git a/source/java/org/alfresco/repo/action/executer/ImageTransformActionExecuter.java b/source/java/org/alfresco/repo/action/executer/ImageTransformActionExecuter.java index 9801efe104..c54ed8c11f 100644 --- a/source/java/org/alfresco/repo/action/executer/ImageTransformActionExecuter.java +++ b/source/java/org/alfresco/repo/action/executer/ImageTransformActionExecuter.java @@ -18,10 +18,12 @@ */ package org.alfresco.repo.action.executer; +import java.util.ArrayList; import java.util.List; import org.alfresco.repo.action.ParameterDefinitionImpl; import org.alfresco.repo.content.transform.ContentTransformer; +import org.alfresco.repo.content.transform.TransformerDebug; import org.alfresco.repo.content.transform.magick.ImageTransformationOptions; import org.alfresco.service.cmr.action.Action; import org.alfresco.service.cmr.action.ParameterDefinition; @@ -38,42 +40,50 @@ import org.alfresco.service.cmr.repository.NodeRef; */ public class ImageTransformActionExecuter extends TransformActionExecuter { + private TransformerDebug transformerDebug; + /** * Action constants */ - public static final String NAME = "transform-image"; - public static final String PARAM_CONVERT_COMMAND = "convert-command"; - - private ContentTransformer imageMagickContentTransformer; - - /** - * Set the image magick content transformer - * - * @param imageMagickContentTransformer the conten transformer - */ - public void setImageMagickContentTransformer(ContentTransformer imageMagickContentTransformer) - { - this.imageMagickContentTransformer = imageMagickContentTransformer; - } - - /** - * Add parameter definitions - */ - @Override - protected void addParameterDefinitions(List paramList) - { - super.addParameterDefinitions(paramList); - paramList.add(new ParameterDefinitionImpl(PARAM_CONVERT_COMMAND, DataTypeDefinition.TEXT, false, getParamDisplayLabel(PARAM_CONVERT_COMMAND))); - } - - /** + public static final String NAME = "transform-image"; + public static final String PARAM_CONVERT_COMMAND = "convert-command"; + + private ContentTransformer imageMagickContentTransformer; + + /** + * Set the image magick content transformer + * + * @param imageMagickContentTransformer + * the conten transformer + */ + public void setImageMagickContentTransformer(ContentTransformer imageMagickContentTransformer) + { + this.imageMagickContentTransformer = imageMagickContentTransformer; + } + + /** + * Add parameter definitions + */ + @Override + protected void addParameterDefinitions(List paramList) + { + super.addParameterDefinitions(paramList); + paramList.add(new ParameterDefinitionImpl(PARAM_CONVERT_COMMAND, DataTypeDefinition.TEXT, false, getParamDisplayLabel(PARAM_CONVERT_COMMAND))); + } + + public void setTransformerDebug(TransformerDebug transformerDebug) + { + this.transformerDebug = transformerDebug; + } + + /** * @see org.alfresco.repo.action.executer.TransformActionExecuter#doTransform(org.alfresco.service.cmr.action.Action, org.alfresco.service.cmr.repository.ContentReader, org.alfresco.service.cmr.repository.ContentWriter) - */ - protected void doTransform( Action ruleAction, - NodeRef sourceNodeRef, ContentReader contentReader, + */ + protected void doTransform(Action ruleAction, + NodeRef sourceNodeRef, ContentReader contentReader, NodeRef destinationNodeRef, ContentWriter contentWriter) - { - // Try and transform the content + { + // Try and transform the content String convertCommand = (String) ruleAction.getParameterValue(PARAM_CONVERT_COMMAND); // create some options for the transform ImageTransformationOptions imageOptions = new ImageTransformationOptions(); @@ -81,12 +91,28 @@ public class ImageTransformActionExecuter extends TransformActionExecuter imageOptions.setSourceNodeRef(sourceNodeRef); // check if the transformer is going to work, i.e. is available - if (!this.imageMagickContentTransformer.isTransformable(contentReader.getMimetype(), contentReader.getSize(), contentWriter - .getMimetype(), imageOptions)) + String sourceMimetype = contentReader.getMimetype(); + String targetMimetype = contentWriter.getMimetype(); + long sourceSize = contentReader.getSize(); + try { - throw new NoTransformerException(contentReader.getMimetype(), contentWriter.getMimetype()); - } + transformerDebug.pushAvailable(contentReader.getContentUrl(), sourceMimetype, targetMimetype, imageOptions); + List transformers = new ArrayList(1); + if (imageMagickContentTransformer.isTransformable(sourceMimetype, contentReader.getSize(), targetMimetype, imageOptions)) + { + transformers.add(imageMagickContentTransformer); + } + transformerDebug.availableTransformers(transformers, sourceSize, "ImageTransformActionExecuter.doTransform(...)"); + if (transformers.size() == 0) + { + throw new NoTransformerException(sourceMimetype, targetMimetype); + } - this.imageMagickContentTransformer.transform(contentReader, contentWriter, imageOptions); - } + imageMagickContentTransformer.transform(contentReader, contentWriter, imageOptions); + } + finally + { + transformerDebug.popAvailable(); + } + } } diff --git a/source/java/org/alfresco/repo/action/executer/TransformActionExecuter.java b/source/java/org/alfresco/repo/action/executer/TransformActionExecuter.java index af566c308c..669580f5a8 100644 --- a/source/java/org/alfresco/repo/action/executer/TransformActionExecuter.java +++ b/source/java/org/alfresco/repo/action/executer/TransformActionExecuter.java @@ -310,13 +310,7 @@ public class TransformActionExecuter extends ActionExecuterAbstractBase TransformationOptions options = new TransformationOptions( sourceNodeRef, ContentModel.PROP_NAME, destinationNodeRef, ContentModel.PROP_NAME); - // try to pre-empt the lack of a transformer - if (this.contentService.isTransformable(contentReader, contentWriter, options) == false) - { - throw new NoTransformerException(contentReader.getMimetype(), contentWriter.getMimetype()); - } - - // transform + // transform - will throw NoTransformerException if there are no transformers this.contentService.transform(contentReader, contentWriter, options); } diff --git a/source/java/org/alfresco/repo/content/ContentServiceImpl.java b/source/java/org/alfresco/repo/content/ContentServiceImpl.java index b537e192a8..fc7bf530c7 100644 --- a/source/java/org/alfresco/repo/content/ContentServiceImpl.java +++ b/source/java/org/alfresco/repo/content/ContentServiceImpl.java @@ -963,9 +963,20 @@ public class ContentServiceImpl implements ContentService, ApplicationContextAwa throw new AlfrescoRuntimeException("The content writer mimetype must be set: " + writer); } - // look for a transformer - ContentTransformer transformer = transformerRegistry.getTransformer(sourceMimetype, reader.getSize(), targetMimetype, options); - return (transformer != null); + long sourceSize = reader.getSize(); + try + { + // look for a transformer + transformerDebug.pushAvailable(reader.getContentUrl(), sourceMimetype, targetMimetype, options); + List transformers = getActiveTransformers(sourceMimetype, sourceSize, targetMimetype, options); + transformerDebug.availableTransformers(transformers, sourceSize, "ContentService.isTransformable(...)"); + + return transformers.size() > 0; + } + finally + { + transformerDebug.popAvailable(); + } } /** diff --git a/source/java/org/alfresco/repo/content/transform/FailoverPdfToImageContentTransformer.java b/source/java/org/alfresco/repo/content/transform/FailoverPdfToImageContentTransformer.java new file mode 100644 index 0000000000..f39fcd10bc --- /dev/null +++ b/source/java/org/alfresco/repo/content/transform/FailoverPdfToImageContentTransformer.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2005-2012 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ +package org.alfresco.repo.content.transform; + +import org.alfresco.repo.content.MimetypeMap; +import org.alfresco.service.cmr.repository.TransformationOptions; + +/** + * ALF-14303 Only support PDF to PNG rather than all the possible transformations from transformer.worker.ImageMagick + */ +public class FailoverPdfToImageContentTransformer extends FailoverContentTransformer +{ + @Override + public boolean isTransformableMimetype(String sourceMimetype, String targetMimetype, TransformationOptions options) + { + return MimetypeMap.MIMETYPE_PDF.equals(sourceMimetype) && + MimetypeMap.MIMETYPE_IMAGE_PNG.equals(targetMimetype); + } +} diff --git a/source/java/org/alfresco/repo/content/transform/magick/AbstractImageMagickContentTransformerWorker.java b/source/java/org/alfresco/repo/content/transform/magick/AbstractImageMagickContentTransformerWorker.java index 937aee9634..aacc15036e 100644 --- a/source/java/org/alfresco/repo/content/transform/magick/AbstractImageMagickContentTransformerWorker.java +++ b/source/java/org/alfresco/repo/content/transform/magick/AbstractImageMagickContentTransformerWorker.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2010 Alfresco Software Limited. + * Copyright (C) 2005-2012 Alfresco Software Limited. * * This file is part of Alfresco * @@ -180,6 +180,14 @@ public abstract class AbstractImageMagickContentTransformerWorker extends Conten { return false; } + + // Add limited support (so lots of other transforms are not supported) for PDF to PNG. An ALF-14303 workaround. + // Will only be used as part of failover transformer.PdfToImage + if (sourceMimetype.equals(MimetypeMap.MIMETYPE_PDF) && targetMimetype.equals(MimetypeMap.MIMETYPE_IMAGE_PNG)) + { + return true; // ALF-14303 workaround + } + if (!AbstractImageMagickContentTransformerWorker.isSupported(sourceMimetype) || !AbstractImageMagickContentTransformerWorker.isSupported(targetMimetype)) { diff --git a/source/java/org/alfresco/repo/jscript/ScriptNode.java b/source/java/org/alfresco/repo/jscript/ScriptNode.java index b41b2d8b4b..547499354a 100644 --- a/source/java/org/alfresco/repo/jscript/ScriptNode.java +++ b/source/java/org/alfresco/repo/jscript/ScriptNode.java @@ -75,6 +75,7 @@ import org.alfresco.service.cmr.repository.ContentData; import org.alfresco.service.cmr.repository.ContentReader; import org.alfresco.service.cmr.repository.ContentService; import org.alfresco.service.cmr.repository.ContentWriter; +import org.alfresco.service.cmr.repository.NoTransformerException; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.Path; @@ -2472,11 +2473,15 @@ public class ScriptNode implements Scopeable, NamespacePrefixResolverProvider TransformationOptions options = new TransformationOptions(); options.setSourceNodeRef(sourceNodeRef); - if (contentService.isTransformable(reader, writer, options)) + try { contentService.transform(reader, writer, options); transformedNode = newInstance(nodeRef, services, scope); } + catch (NoTransformerException e) + { + // ignore + } return transformedNode; } }; diff --git a/source/java/org/alfresco/repo/template/BaseContentNode.java b/source/java/org/alfresco/repo/template/BaseContentNode.java index 7d714b1228..909d4a55f6 100644 --- a/source/java/org/alfresco/repo/template/BaseContentNode.java +++ b/source/java/org/alfresco/repo/template/BaseContentNode.java @@ -37,6 +37,7 @@ import org.alfresco.service.cmr.repository.ContentReader; import org.alfresco.service.cmr.repository.ContentService; import org.alfresco.service.cmr.repository.ContentWriter; import org.alfresco.service.cmr.repository.FileTypeImageSize; +import org.alfresco.service.cmr.repository.NoTransformerException; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.Path; import org.alfresco.service.cmr.repository.TemplateImageResolver; @@ -610,7 +611,7 @@ public abstract class BaseContentNode implements TemplateContent options.setSourceNodeRef(nodeRef); // try and transform the content - if (contentService.isTransformable(reader, writer, options)) + try { contentService.transform(reader, writer, options); @@ -627,6 +628,10 @@ public abstract class BaseContentNode implements TemplateContent } } } + catch (NoTransformerException e) + { + // ignore + } } return result; } diff --git a/source/java/org/alfresco/service/cmr/repository/ContentService.java b/source/java/org/alfresco/service/cmr/repository/ContentService.java index 4dba4f7fca..14063621c9 100644 --- a/source/java/org/alfresco/service/cmr/repository/ContentService.java +++ b/source/java/org/alfresco/service/cmr/repository/ContentService.java @@ -300,22 +300,7 @@ public interface ContentService public ContentTransformer getImageTransformer(); /** - * 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}. - * - * @param reader the source content location and mimetype - * @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) + * @deprecated use {@link #isTransformable(String, String, long, String, TransformationOptions). */ @Auditable(parameters = {"reader", "writer"}) public boolean isTransformable(ContentReader reader, ContentWriter writer); @@ -325,6 +310,10 @@ public interface ContentService * the reader and write the content back out to the writer with the * provided tranformation options. *

+ * If you are about to call {@link #transform(ContentReader, ContentWriter, TransformationOptions)} + * it is best NOT to call this method first as it must perform the same steps and will throw + * NoTransformerException if there are no transformers.

+ * * The mimetypes used for the transformation must be set both on * the {@link ContentAccessor#getMimetype() reader} and on the * {@link ContentAccessor#getMimetype() writer}.