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);
}
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());
}
}
}
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);
}
}
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");
}
}
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);
}
}
}
Aggregations