Search in sources :

Example 11 with TransformationOptions

use of org.alfresco.service.cmr.repository.TransformationOptions in project alfresco-repository by Alfresco.

the class DummyAnyToPDFTestSubtransformer method testReliability.

public void testReliability() throws Exception {
    // The MIME types here are rather arbitrary
    boolean reliability = transformer.isTransformable(sourceMimeType, -1, targetMimeType, new TransformationOptions());
    assertEquals("Mimetype should be supported", true, reliability);
}
Also used : TransformationOptions(org.alfresco.service.cmr.repository.TransformationOptions)

Example 12 with TransformationOptions

use of org.alfresco.service.cmr.repository.TransformationOptions in project alfresco-repository by Alfresco.

the class TransformActionExecuter method executeImpl.

/**
 * @see org.alfresco.repo.action.executer.ActionExecuterAbstractBase#executeImpl(Action, org.alfresco.service.cmr.repository.NodeRef)
 */
@Override
protected void executeImpl(Action ruleAction, NodeRef actionedUponNodeRef) {
    if (this.nodeService.exists(actionedUponNodeRef) == false) {
        // node doesn't exist - can't do anything
        return;
    }
    // First check that the node is a sub-type of content
    QName typeQName = this.nodeService.getType(actionedUponNodeRef);
    if (this.dictionaryService.isSubClass(typeQName, ContentModel.TYPE_CONTENT) == false) {
        // it is not content, so can't transform
        return;
    }
    // Get the mime type
    String mimeType = (String) ruleAction.getParameterValue(PARAM_MIME_TYPE);
    // Get the content reader
    ContentReader contentReader = this.contentService.getReader(actionedUponNodeRef, ContentModel.PROP_CONTENT);
    if (null == contentReader || !contentReader.exists()) {
        throw new RuleServiceException(CONTENT_READER_NOT_FOUND_MESSAGE);
    }
    TransformationOptions transformationOptions = newTransformationOptions(ruleAction, actionedUponNodeRef);
    // getExecuteAsynchronously() is not true for async convert content rules, so using Thread name
    // options.setUse(ruleAction.getExecuteAsynchronously() ? "asyncRule" :"syncRule");
    transformationOptions.setUse(Thread.currentThread().getName().contains("Async") ? "asyncRule" : "syncRule");
    String sourceMimetype = contentReader.getMimetype();
    long sourceSizeInBytes = contentReader.getSize();
    String contentUrl = contentReader.getContentUrl();
    Map<String, String> options = converter.getOptions(transformationOptions, sourceMimetype, mimeType);
    if (!synchronousTransformClient.isSupported(sourceMimetype, sourceSizeInBytes, contentUrl, mimeType, options, null, actionedUponNodeRef)) {
        String optionsString = TransformerDebug.toString(options);
        throw new RuleServiceException(String.format(TRANSFORMER_NOT_EXISTS_MESSAGE_PATTERN, sourceMimetype, mimeType, optionsString));
    }
    // Get the details of the copy destination
    NodeRef destinationParent = (NodeRef) ruleAction.getParameterValue(PARAM_DESTINATION_FOLDER);
    QName destinationAssocTypeQName = (QName) ruleAction.getParameterValue(PARAM_ASSOC_TYPE_QNAME);
    QName destinationAssocQName = (QName) ruleAction.getParameterValue(PARAM_ASSOC_QNAME);
    // default the assoc params if they're not present
    if (destinationAssocTypeQName == null) {
        destinationAssocTypeQName = ContentModel.ASSOC_CONTAINS;
    }
    if (destinationAssocQName == null) {
        destinationAssocQName = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "copy");
    }
    // Get the overwirte value
    boolean overwrite = true;
    Boolean overwriteValue = (Boolean) ruleAction.getParameterValue(PARAM_OVERWRITE_COPY);
    if (overwriteValue != null) {
        overwrite = overwriteValue.booleanValue();
    }
    // Calculate the destination name
    String originalName = (String) nodeService.getProperty(actionedUponNodeRef, ContentModel.PROP_NAME);
    String newName = transformName(this.mimetypeService, originalName, mimeType, true);
    // Since we are overwriting we need to figure out whether the destination node exists
    NodeRef copyNodeRef = null;
    if (overwrite == true) {
        // Try and find copies of the actioned upon node reference.
        // Include the parent folder because that's where the copy will be if this action
        // had done the first copy.
        PagingResults<CopyInfo> copies = copyService.getCopies(actionedUponNodeRef, destinationParent, new PagingRequest(1000));
        for (CopyInfo copyInfo : copies.getPage()) {
            NodeRef copy = copyInfo.getNodeRef();
            String copyName = copyInfo.getName();
            // We know that it is in the destination parent, but avoid working copies
            if (checkOutCheckInService.isWorkingCopy(copy)) {
                // It is a working copy
                continue;
            } else if (!newName.equals(copyName)) {
                // The copy's name is not what this action would have set it to
                continue;
            }
            if (copyNodeRef == null) {
                copyNodeRef = copy;
            } else {
                throw new RuleServiceException(ERR_OVERWRITE);
            }
        }
    }
    if (copyNodeRef == null) {
        // Copy the content node
        copyNodeRef = this.copyService.copy(actionedUponNodeRef, destinationParent, destinationAssocTypeQName, QName.createQName(destinationAssocQName.getNamespaceURI(), newName));
        // Adjust the name of the copy
        nodeService.setProperty(copyNodeRef, ContentModel.PROP_NAME, newName);
        String originalTitle = (String) nodeService.getProperty(actionedUponNodeRef, ContentModel.PROP_TITLE);
        if (originalTitle != null) {
            nodeService.setProperty(copyNodeRef, ContentModel.PROP_TITLE, originalTitle);
        }
    }
    // Only do the transformation if some content is available
    if (contentReader != null) {
        // get the writer and set it up
        ContentWriter contentWriter = this.contentService.getWriter(copyNodeRef, ContentModel.PROP_CONTENT, true);
        // new mimetype
        contentWriter.setMimetype(mimeType);
        // original encoding
        contentWriter.setEncoding(contentReader.getEncoding());
        // TODO: Check failure patterns for actions.
        try {
            doTransform(ruleAction, actionedUponNodeRef, contentReader, copyNodeRef, contentWriter);
            ruleAction.setParameterValue(PARAM_RESULT, copyNodeRef);
        } catch (NoTransformerException e) {
            if (logger.isDebugEnabled()) {
                logger.debug("No transformer found to execute rule: \n" + "   reader: " + contentReader + "\n" + "   writer: " + contentWriter + "\n" + "   action: " + this);
            }
            throw new RuleServiceException(TRANSFORMING_ERROR_MESSAGE + e.getMessage());
        }
    }
}
Also used : RuleServiceException(org.alfresco.service.cmr.rule.RuleServiceException) QName(org.alfresco.service.namespace.QName) ContentReader(org.alfresco.service.cmr.repository.ContentReader) CopyInfo(org.alfresco.service.cmr.repository.CopyService.CopyInfo) PagingRequest(org.alfresco.query.PagingRequest) NoTransformerException(org.alfresco.service.cmr.repository.NoTransformerException) TransformationOptions(org.alfresco.service.cmr.repository.TransformationOptions) NodeRef(org.alfresco.service.cmr.repository.NodeRef) ContentWriter(org.alfresco.service.cmr.repository.ContentWriter)

Example 13 with TransformationOptions

use of org.alfresco.service.cmr.repository.TransformationOptions in project alfresco-repository by Alfresco.

the class AbstractContentTransformer2 method transform.

/**
 * @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 void transform(ContentReader reader, ContentWriter writer, TransformationOptions options) throws ContentIOException {
    try {
        depth.set(depth.get() + 1);
        // begin timing
        long before = System.currentTimeMillis();
        String sourceMimetype = reader.getMimetype();
        String targetMimetype = writer.getMimetype();
        // check options map
        if (options == null) {
            options = new TransformationOptions();
        }
        try {
            if (transformerDebug.isEnabled()) {
                ((LegacyTransformerDebug) transformerDebug).pushTransform(this, reader.getContentUrl(), sourceMimetype, targetMimetype, reader.getSize(), options);
            }
            // MNT-16381: check the mimetype of the file supplied by the user
            // matches the sourceMimetype of the reader. Intermediate files are
            // not checked.
            strictMimetypeCheck(reader, options, sourceMimetype);
            // Check the transformability
            checkTransformable(reader, writer, options);
            // Pass on any limits to the reader
            setReaderLimits(reader, writer, options);
            // Transform
            // MNT-12238: CLONE - CLONE - Upload of PPTX causes very high memory usage leading to system instability
            // Limiting transformation up to configured amount of milliseconds to avoid very high RAM consumption
            // and OOM during transforming problematic documents
            TransformationOptionLimits limits = getLimits(reader.getMimetype(), writer.getMimetype(), options);
            long timeoutMs = limits.getTimeoutMs();
            if (!useTimeoutThread || (null == limits) || (-1 == timeoutMs)) {
                transformInternal(reader, writer, options);
            } else {
                Future<?> submittedTask = null;
                StreamAwareContentReaderProxy proxiedReader = new StreamAwareContentReaderProxy(reader);
                StreamAwareContentWriterProxy proxiedWriter = new StreamAwareContentWriterProxy(writer);
                try {
                    submittedTask = getExecutorService().submit(new TransformInternalCallable(proxiedReader, proxiedWriter, options));
                    submittedTask.get(timeoutMs + additionalThreadTimout, TimeUnit.MILLISECONDS);
                } catch (TimeoutException e) {
                    releaseResources(submittedTask, proxiedReader, proxiedWriter);
                    throw new TimeoutException("Transformation failed due to timeout limit");
                } catch (InterruptedException e) {
                    releaseResources(submittedTask, proxiedReader, proxiedWriter);
                    throw new InterruptedException("Transformation failed, because the thread of the transformation was interrupted");
                } catch (ExecutionException e) {
                    Throwable cause = e.getCause();
                    if (cause instanceof TransformInternalCallableException) {
                        cause = ((TransformInternalCallableException) cause).getCause();
                    }
                    throw cause;
                }
            }
            // record time
            long after = System.currentTimeMillis();
            recordTime(sourceMimetype, targetMimetype, after - before);
        } catch (ContentServiceTransientException cste) {
            // update the transformer's average time.
            if (logger.isDebugEnabled()) {
                logger.debug("Transformation has been transiently declined: \n" + "   reader: " + reader + "\n" + "   writer: " + writer + "\n" + "   options: " + options + "\n" + "   transformer: " + this);
            }
            // We rethrow the exception
            throw cste;
        } catch (UnsupportedTransformationException e) {
            // Don't record an error or even the time, as this is normal in compound transformations.
            transformerDebug.debug("          Failed", e);
            throw e;
        } 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
            long after = System.currentTimeMillis();
            recordError(sourceMimetype, targetMimetype, after - before);
            // Ask Tika to detect the document, and report back on if
            // the current mime type is plausible
            String differentType = getMimetypeService().getMimetypeIfNotMatches(reader.getReader());
            // Report the error
            if (differentType == null) {
                transformerDebug.debug("          Failed", e);
                throw new ContentIOException("Content conversion failed: \n" + "   reader: " + reader + "\n" + "   writer: " + writer + "\n" + "   options: " + options.toString(false) + "\n" + "   limits: " + getLimits(reader, writer, options), e);
            } else {
                transformerDebug.debug("          Failed: Mime type was '" + differentType + "'", e);
                if (retryTransformOnDifferentMimeType) {
                    // MNT-11015 fix.
                    // Set a new reader to refresh the input stream.
                    reader = reader.getReader();
                    // set the actual file MIME type detected by Tika for content reader
                    reader.setMimetype(differentType);
                    // Get correct transformer according actual file MIME type and try to transform file with
                    // actual transformer
                    ContentTransformer transformer = this.registry.getTransformer(differentType, reader.getSize(), targetMimetype, options);
                    if (null != transformer) {
                        transformer.transform(reader, writer, options);
                    } else {
                        transformerDebug.debug("          Failed", e);
                        throw new ContentIOException("Content conversion failed: \n" + "   reader: " + reader + "\n" + "   writer: " + writer + "\n" + "   options: " + options.toString(false) + "\n" + "   limits: " + getLimits(reader, writer, options) + "\n" + "   claimed mime type: " + reader.getMimetype() + "\n" + "   detected mime type: " + differentType + "\n" + "   transformer not found" + "\n", e);
                    }
                } else {
                    throw new ContentIOException("Content conversion failed: \n" + "   reader: " + reader + "\n" + "   writer: " + writer + "\n" + "   options: " + options.toString(false) + "\n" + "   limits: " + getLimits(reader, writer, options) + "\n" + "   claimed mime type: " + reader.getMimetype() + "\n" + "   detected mime type: " + differentType, e);
                }
            }
        } finally {
            transformerDebug.popTransform();
            // 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);
            }
        }
        // done
        if (logger.isDebugEnabled()) {
            logger.debug("Completed transformation: \n" + "   reader: " + reader + "\n" + "   writer: " + writer + "\n" + "   options: " + options + "\n" + "   transformer: " + this);
        }
    } finally {
        depth.set(depth.get() - 1);
    }
}
Also used : StreamAwareContentWriterProxy(org.alfresco.repo.content.StreamAwareContentWriterProxy) ContentIOException(org.alfresco.service.cmr.repository.ContentIOException) TransformationOptions(org.alfresco.service.cmr.repository.TransformationOptions) StreamAwareContentReaderProxy(org.alfresco.repo.content.StreamAwareContentReaderProxy) TransformationOptionLimits(org.alfresco.service.cmr.repository.TransformationOptionLimits) ContentServiceTransientException(org.alfresco.service.cmr.repository.ContentServiceTransientException) ExecutionException(java.util.concurrent.ExecutionException) TimeoutException(java.util.concurrent.TimeoutException)

Example 14 with TransformationOptions

use of org.alfresco.service.cmr.repository.TransformationOptions in project alfresco-repository by Alfresco.

the class ContentServiceImplTest method testTransformAndNulls.

@Test
@Deprecated
public void testTransformAndNulls() {
    NodeRef versionableNode = createNewVersionableNode();
    ContentReader contentReader = this.contentService.getReader(versionableNode, ContentModel.PROP_CONTENT);
    ContentWriter contentWriter = this.contentService.getWriter(versionableNode, ContentModel.PROP_CONTENT, false);
    // this.nodeService.setProperty(versionableNode, ContentModel.PROP_NAME, "for debugTransformers.txt");
    try {
        this.contentService.transform(new MimetypeMapTest.DummyContentReader(MimetypeMap.MIMETYPE_TEXT_PLAIN), new MimetypeMapTest.DummyContentWriter(MimetypeMap.MIMETYPE_IMAGE_PNG), new TransformationOptions(versionableNode, ContentModel.PROP_NAME, null, null));
    } catch (NoTransformerException nte) {
        nte.getMessage().contains("No transformation exists");
    }
    try {
        this.contentService.transform(null, null, new TransformationOptions());
        fail("Should throw exception");
    } catch (AlfrescoRuntimeException are) {
        are.getMessage().contains("The content reader must be set");
    }
    ContentReader empty = new EmptyContentReader("empty.txt");
    try {
        this.contentService.transform(empty, null, new TransformationOptions());
        fail("Should throw exception");
    } catch (AlfrescoRuntimeException are) {
        are.getMessage().contains("The content reader mimetype must be set");
    }
    try {
        contentWriter.setMimetype(null);
        this.contentService.transform(contentReader, contentWriter, new TransformationOptions());
        fail("Should throw exception");
    } catch (AlfrescoRuntimeException are) {
        are.getMessage().contains("The content writer mimetype must be set");
    }
}
Also used : NodeRef(org.alfresco.service.cmr.repository.NodeRef) ContentWriter(org.alfresco.service.cmr.repository.ContentWriter) EmptyContentReader(org.alfresco.repo.content.EmptyContentReader) ContentReader(org.alfresco.service.cmr.repository.ContentReader) AlfrescoRuntimeException(org.alfresco.error.AlfrescoRuntimeException) MimetypeMapTest(org.alfresco.repo.content.MimetypeMapTest) EmptyContentReader(org.alfresco.repo.content.EmptyContentReader) NoTransformerException(org.alfresco.service.cmr.repository.NoTransformerException) TransformationOptions(org.alfresco.service.cmr.repository.TransformationOptions) MimetypeMapTest(org.alfresco.repo.content.MimetypeMapTest) Test(org.junit.Test)

Example 15 with TransformationOptions

use of org.alfresco.service.cmr.repository.TransformationOptions in project alfresco-repository by Alfresco.

the class AbstractTransformationRenderingEngine method render.

/*
     * (non-Javadoc)
     * @see org.alfresco.repo.rendition.executer.AbstractRenderingEngine#render(org.alfresco.repo.rendition.executer.AbstractRenderingEngine.RenderingContext)
     */
@Override
protected void render(RenderingContext context) {
    ContentReader contentReader = context.makeContentReader();
    // There will have been an exception if there is no content data so contentReader is not null.
    String contentUrl = contentReader.getContentUrl();
    String sourceMimeType = contentReader.getMimetype();
    String targetMimeType = getTargetMimeType(context);
    // The child NodeRef gets created here
    TransformationOptions transformationOptions = getTransformOptions(context);
    long sourceSizeInBytes = contentReader.getSize();
    Map<String, String> options = converter.getOptions(transformationOptions, sourceMimeType, targetMimeType);
    NodeRef sourceNodeRef = transformationOptions.getSourceNodeRef();
    if (!synchronousTransformClient.isSupported(sourceMimeType, sourceSizeInBytes, contentUrl, targetMimeType, options, null, sourceNodeRef)) {
        String optionsString = TransformerDebug.toString(options);
        throw new RenditionServiceException(String.format(NOT_TRANSFORMABLE_MESSAGE_PATTERN, sourceMimeType, targetMimeType, optionsString));
    }
    long startTime = new Date().getTime();
    boolean actionCancelled = false;
    boolean actionCompleted = false;
    // Cache the execution summary to get details later
    ExecutionSummary executionSummary = null;
    try {
        executionSummary = getExecutionSummary(context);
    } catch (ActionServiceException e) {
        if (logger.isInfoEnabled()) {
            logger.info("Cancelling of multiple concurrent action instances " + "currently unsupported, this action can't be cancelled");
        }
    }
    // Call the transform in a different thread so we can move on if cancelled
    FutureTask<ContentWriter> transformTask = new FutureTask<ContentWriter>(new TransformationCallable(contentReader, targetMimeType, transformationOptions, context, AuthenticationUtil.getFullyAuthenticatedUser()));
    getExecutorService().execute(transformTask);
    // Start checking for cancellation or timeout
    while (true) {
        try {
            Thread.sleep(CANCELLED_ACTION_POLLING_INTERVAL);
            if (transformTask.isDone()) {
                actionCompleted = true;
                break;
            }
            // Check timeout in case transformer doesn't obey it
            if (transformationOptions.getTimeoutMs() > 0 && new Date().getTime() - startTime > (transformationOptions.getTimeoutMs() + CANCELLED_ACTION_POLLING_INTERVAL)) {
                // We hit a timeout, let the transform thread continue but results will be ignored
                if (logger.isDebugEnabled()) {
                    logger.debug("Transformation did not obey timeout limit, " + "rendition action is moving on");
                }
                break;
            }
            if (executionSummary != null) {
                ExecutionDetails executionDetails = actionTrackingService.getExecutionDetails(executionSummary);
                if (executionDetails != null) {
                    actionCancelled = executionDetails.isCancelRequested();
                    if (actionCancelled) {
                        if (logger.isDebugEnabled()) {
                            logger.debug("Cancelling transformation");
                        }
                        transformTask.cancel(true);
                        break;
                    }
                }
            }
        } catch (InterruptedException e) {
            // entire thread was asked to stop
            actionCancelled = true;
            transformTask.cancel(true);
            break;
        }
    }
    if (actionCancelled) {
        throw new RenditionCancelledException("Rendition action cancelled");
    }
    if (!actionCompleted && !actionCancelled) {
        throw new RenditionServiceException("Transformation failed to obey timeout limit");
    }
    if (actionCompleted) {
        // Copy content from temp writer to real writer
        ContentWriter writer = context.makeContentWriter();
        try {
            // We should not need another timeout here, things should be ready for us
            ContentWriter tempTarget = transformTask.get();
            if (tempTarget == null) {
                // We should never be in this state, but just in case
                throw new RenditionServiceException("Target of transformation not present");
            }
            writer.putContent(tempTarget.getReader().getContentInputStream());
        } catch (ExecutionException e) {
            // Unwrap our cause and throw that
            Throwable transformException = e.getCause();
            if (transformException instanceof RuntimeException) {
                throw (RuntimeException) e.getCause();
            }
            throw new RenditionServiceException(TRANSFORMING_ERROR_MESSAGE + e.getCause().getMessage(), e.getCause());
        } catch (InterruptedException e) {
            // We were asked to stop
            transformTask.cancel(true);
        }
    }
}
Also used : ContentReader(org.alfresco.service.cmr.repository.ContentReader) RenditionCancelledException(org.alfresco.service.cmr.rendition.RenditionCancelledException) ExecutionDetails(org.alfresco.service.cmr.action.ExecutionDetails) RenditionServiceException(org.alfresco.service.cmr.rendition.RenditionServiceException) Date(java.util.Date) TransformationOptions(org.alfresco.service.cmr.repository.TransformationOptions) ActionServiceException(org.alfresco.service.cmr.action.ActionServiceException) NodeRef(org.alfresco.service.cmr.repository.NodeRef) ContentWriter(org.alfresco.service.cmr.repository.ContentWriter) FutureTask(java.util.concurrent.FutureTask) ExecutionSummary(org.alfresco.service.cmr.action.ExecutionSummary) ExecutionException(java.util.concurrent.ExecutionException)

Aggregations

TransformationOptions (org.alfresco.service.cmr.repository.TransformationOptions)44 ContentReader (org.alfresco.service.cmr.repository.ContentReader)10 ContentWriter (org.alfresco.service.cmr.repository.ContentWriter)8 ImageTransformationOptions (org.alfresco.repo.content.transform.magick.ImageTransformationOptions)6 SWFTransformationOptions (org.alfresco.repo.content.transform.swf.SWFTransformationOptions)6 ContentTransformer (org.alfresco.repo.content.transform.ContentTransformer)5 ArrayList (java.util.ArrayList)4 Test (org.junit.Test)4 Serializable (java.io.Serializable)3 AlfrescoRuntimeException (org.alfresco.error.AlfrescoRuntimeException)3 FileContentReader (org.alfresco.repo.content.filestore.FileContentReader)3 ContentIOException (org.alfresco.service.cmr.repository.ContentIOException)3 NodeRef (org.alfresco.service.cmr.repository.NodeRef)3 TransformationOptionLimits (org.alfresco.service.cmr.repository.TransformationOptionLimits)3 QName (org.alfresco.service.namespace.QName)3 HashMap (java.util.HashMap)2 StringJoiner (java.util.StringJoiner)2 ExecutionException (java.util.concurrent.ExecutionException)2 FileContentWriter (org.alfresco.repo.content.filestore.FileContentWriter)2 ImageResizeOptions (org.alfresco.repo.content.transform.magick.ImageResizeOptions)2