Reverting LocalTransformer work for the moment

Revert "Feature/repo 4331 encoding (#472)"
This reverts commit 0e5de8e774.
Revert "REPO-4319 Local Transformers (#313)"
This reverts commit 436ba847f6.
This commit is contained in:
Alan Davis
2019-06-06 06:57:38 +01:00
parent 1c0a48c08f
commit e7549e5906
61 changed files with 1030 additions and 3471 deletions

View File

@@ -59,7 +59,6 @@ import org.apache.commons.logging.LogFactory;
*
* @author Roy Wetherall
*/
@Deprecated
public class TransformActionExecuter extends ActionExecuterAbstractBase
{
/* Error messages */

View File

@@ -1,257 +0,0 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2019 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* 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 <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.content.transform;
import org.alfresco.error.AlfrescoRuntimeException;
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.NodeRef;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.util.Map;
import java.util.Set;
/**
* Abstract supper class for local transformer using flat transform options.
*/
public abstract class AbstractLocalTransformer implements LocalTransformer
{
protected static final Log log = LogFactory.getLog(LocalTransformer.class);
protected final String name;
protected final MimetypeService mimetypeService;
protected final TransformerDebug transformerDebug;
private final LocalTransformServiceRegistry localTransformServiceRegistry;
private final boolean strictMimeTypeCheck;
private final Map<String, Set<String>> strictMimetypeExceptions;
private final boolean retryTransformOnDifferentMimeType;
private final static ThreadLocal<Integer> depth = ThreadLocal.withInitial(()->0);
AbstractLocalTransformer(String name, TransformerDebug transformerDebug,
MimetypeService mimetypeService, boolean strictMimeTypeCheck,
Map<String, Set<String>> strictMimetypeExceptions, boolean retryTransformOnDifferentMimeType,
LocalTransformServiceRegistry localTransformServiceRegistry)
{
this.name = name;
this.transformerDebug = transformerDebug;
this.mimetypeService = mimetypeService;
this.strictMimeTypeCheck = strictMimeTypeCheck;
this.strictMimetypeExceptions = strictMimetypeExceptions;
this.retryTransformOnDifferentMimeType = retryTransformOnDifferentMimeType;
this.localTransformServiceRegistry = localTransformServiceRegistry;
}
public abstract boolean isAvailable();
protected abstract void transformImpl(ContentReader reader,
ContentWriter writer, Map<String, String> transformOptions,
String sourceMimetype, String targetMimetype,
String sourceExtension, String targetExtension,
String renditionName, NodeRef sourceNodeRef)
throws Exception;
@Override
public void transform(ContentReader reader, ContentWriter writer, Map<String, String> transformOptions,
String renditionName, NodeRef sourceNodeRef)
throws Exception
{
if (isAvailable())
{
String sourceMimetype = reader.getMimetype();
String targetMimetype = writer.getMimetype();
String sourceExtension = mimetypeService.getExtension(sourceMimetype);
String targetExtension = mimetypeService.getExtension(targetMimetype);
if (sourceExtension == null || targetExtension == null)
{
throw new AlfrescoRuntimeException("Unknown extensions for mimetypes: \n" +
" source mimetype: " + sourceMimetype + "\n" +
" source extension: " + sourceExtension + "\n" +
" target mimetype: " + targetMimetype + "\n" +
" target extension: " + targetExtension);
}
transformWithDebug(reader, writer, transformOptions, renditionName, sourceNodeRef, sourceMimetype,
targetMimetype, sourceExtension, targetExtension);
if (log.isDebugEnabled())
{
log.debug("Local transformation completed: \n" +
" source: " + reader + "\n" +
" target: " + writer + "\n" +
" options: " + transformOptions);
}
}
else
{
log.debug("Local transformer not available: \n" +
" source: " + reader + "\n" +
" target: " + writer + "\n" +
" options: " + transformOptions);
}
}
private void transformWithDebug(ContentReader reader, ContentWriter writer, Map<String, String> transformOptions,
String renditionName, NodeRef sourceNodeRef, String sourceMimetype, String targetMimetype,
String sourceExtension, String targetExtension) throws Exception
{
try
{
depth.set(depth.get()+1);
if (transformerDebug.isEnabled())
{
transformerDebug.pushTransform(name, reader.getContentUrl(), sourceMimetype,
targetMimetype, reader.getSize(), renditionName, sourceNodeRef);
}
strictMimetypeCheck(reader, sourceNodeRef, sourceMimetype);
transformImpl(reader, writer, transformOptions, sourceMimetype,
targetMimetype, sourceExtension, targetExtension, renditionName, sourceNodeRef);
}
catch (Throwable e)
{
retryWithDifferentMimetype(reader, writer, targetMimetype, transformOptions, renditionName, sourceNodeRef, e);
}
finally
{
transformerDebug.popTransform();
depth.set(depth.get()-1);
}
}
private void strictMimetypeCheck(ContentReader reader, NodeRef sourceNodeRef, String declaredMimetype)
throws UnsupportedTransformationException
{
if (mimetypeService != null && strictMimeTypeCheck && depth.get() == 1)
{
String detectedMimetype = mimetypeService.getMimetypeIfNotMatches(reader.getReader());
if (!strictMimetypeCheck(declaredMimetype, detectedMimetype))
{
Set<String> allowedMimetypes = strictMimetypeExceptions.get(declaredMimetype);
if (allowedMimetypes != null && allowedMimetypes.contains(detectedMimetype))
{
String fileName = transformerDebug.getFileName(sourceNodeRef, true, 0);
String readerSourceMimetype = reader.getMimetype();
String message = "Transformation of ("+fileName+
") has not taken place because the declared mimetype ("+
readerSourceMimetype+") does not match the detected mimetype ("+
detectedMimetype+").";
log.warn(message);
throw new UnsupportedTransformationException(message);
}
}
}
}
/**
* When strict mimetype checking is performed before a transformation, this method is called.
* There are a few issues with the Tika mimetype detection. As a result we still allow some
* transformations to take place even if there is a discrepancy between the detected and
* declared mimetypes.
* @param declaredMimetype the mimetype on the source node
* @param detectedMimetype returned by Tika having looked at the content.
* @return true if the transformation should take place. This includes the case where the
* detectedMimetype is null (returned by Tika when the mimetypes are the same), or
* the supplied pair of mimetypes have been added to the
* {@code}transformer.strict.mimetype.check.whitelist{@code}.
*/
private boolean strictMimetypeCheck(String declaredMimetype, String detectedMimetype)
{
if (detectedMimetype == null)
{
return true;
}
Set<String> detectedMimetypes = strictMimetypeExceptions.get(declaredMimetype);
return detectedMimetypes != null && detectedMimetypes.contains(detectedMimetype);
}
private void retryWithDifferentMimetype(ContentReader reader, ContentWriter writer, String targetMimetype,
Map<String, String> transformOptions, String renditionName,
NodeRef sourceNodeRef, Throwable e) throws Exception
{
if (mimetypeService != null && localTransformServiceRegistry != null)
{
String differentType = mimetypeService.getMimetypeIfNotMatches(reader.getReader());
if (differentType == null)
{
transformerDebug.debug(" Failed", e);
throw new ContentIOException("Content conversion failed: \n" +
" reader: " + reader + "\n" +
" writer: " + writer + "\n" +
" options: " + transformOptions,
e);
}
else
{
transformerDebug.debug(" Failed: Mime type was '" + differentType + "'", e);
String claimedMimetype = reader.getMimetype();
if (retryTransformOnDifferentMimeType)
{
reader = reader.getReader();
reader.setMimetype(differentType);
long sourceSizeInBytes = reader.getSize();
LocalTransformer localTransformer = localTransformServiceRegistry.getLocalTransformer(
transformOptions, renditionName, differentType, targetMimetype, sourceSizeInBytes);
if (localTransformer == null)
{
transformerDebug.debug(" Failed", e);
throw new ContentIOException("Content conversion failed: \n" +
" reader: " + reader + "\n" +
" writer: " + writer + "\n" +
" options: " + transformOptions + "\n" +
" claimed mime type: " + claimedMimetype + "\n" +
" detected mime type: " + differentType + "\n" +
" transformer not found" + "\n",
e
);
}
localTransformer.transform(reader, writer, transformOptions, renditionName, sourceNodeRef);
}
else
{
throw new ContentIOException("Content conversion failed: \n" +
" reader: " + reader + "\n" +
" writer: " + writer + "\n" +
" options: " + transformOptions + "\n" +
" claimed mime type: " + claimedMimetype + "\n" +
" detected mime type: " + differentType,
e
);
}
}
}
}
}

View File

@@ -42,17 +42,10 @@ import org.apache.commons.logging.Log;
@Deprecated
public abstract class AbstractRemoteContentTransformer extends AbstractContentTransformer2
{
private boolean enabled = true;
private RemoteTransformerClient remoteTransformerClient;
private boolean available = false;
public void setEnabled(boolean enabled)
{
this.enabled = enabled;
}
/**
* Sets the optional remote transformer client which will be used in preference to a local command if available.
*
@@ -82,50 +75,47 @@ public abstract class AbstractRemoteContentTransformer extends AbstractContentTr
public void afterPropertiesSet()
{
if (enabled)
// check availability
if (remoteTransformerClientConfigured())
{
// check availability
if (remoteTransformerClientConfigured())
Log logger = getLogger();
try
{
Log logger = getLogger();
try
Pair<Boolean, String> result = remoteTransformerClient.check(logger);
Boolean isAvailable = result.getFirst();
String msg = result.getSecond() == null ? "" : result.getSecond();
if (isAvailable != null && isAvailable)
{
Pair<Boolean, String> result = remoteTransformerClient.check(logger);
Boolean isAvailable = result.getFirst();
String msg = result.getSecond() == null ? "" : result.getSecond();
if (isAvailable != null && isAvailable)
String versionString = msg;
setAvailable(true);
logger.info("Using remote " + getName() + ": " + versionString);
}
else
{
setAvailable(false);
String message = "Remote " + getName() + " is not available for transformations. " + msg;
if (isAvailable == null)
{
String versionString = msg;
setAvailable(true);
logger.info("Using legacy local " + getName() + ": " + versionString);
logger.debug(message);
}
else
{
setAvailable(false);
String message = "Legacy local " + getName() + " is not available for transformations. " + msg;
if (isAvailable == null)
{
logger.debug(message);
}
else
{
logger.error(message);
}
logger.error(message);
}
}
catch (Throwable e)
{
setAvailable(false);
logger.error("Remote " + getName() + " is not available: " + (e.getMessage() != null ? e.getMessage() : ""));
// debug so that we can trace the issue if required
logger.debug(e);
}
}
else
catch (Throwable e)
{
available = true;
setAvailable(false);
logger.error("Remote " + getName() + " is not available: " + (e.getMessage() != null ? e.getMessage() : ""));
// debug so that we can trace the issue if required
logger.debug(e);
}
}
else
{
available = true;
}
}
public boolean isAvailable()

View File

@@ -197,7 +197,7 @@ public class ContentTransformerRegistry
if (firstTime)
{
firstTime = false;
transformerDebug.debug("Legacy transforms are " + (enabled ? "enabled" : "disabled"));
transformerDebug.debug("Local legacy transformers are " + (enabled ? "enabled" : "disabled"));
}
// Get the list of transformers

View File

@@ -48,15 +48,8 @@ public class JodContentTransformer extends OOoContentTransformerHelper implement
{
private static Log logger = LogFactory.getLog(JodContentTransformer.class);
private boolean enabled = true;
private JodConverter jodconverter;
public void setEnabled(boolean enabled)
{
this.enabled = enabled;
}
public void setJodConverter(JodConverter jodc)
{
this.jodconverter = jodc;
@@ -90,29 +83,26 @@ public class JodContentTransformer extends OOoContentTransformerHelper implement
@Override
public void afterPropertiesSet()
{
if (enabled)
super.afterPropertiesSet();
if (remoteTransformerClientConfigured())
{
super.afterPropertiesSet();
if (remoteTransformerClientConfigured())
Pair<Boolean, String> result = remoteTransformerClient.check(logger);
Boolean isAvailable = result.getFirst();
if (isAvailable != null && isAvailable)
{
Pair<Boolean, String> result = remoteTransformerClient.check(logger);
Boolean isAvailable = result.getFirst();
if (isAvailable != null && isAvailable)
String versionString = result.getSecond().trim();
logger.info("Using remote JodCoverter: "+versionString);
}
else
{
String message = "Remote JodConverter is not available for transformations. " + result.getSecond();
if (isAvailable == null)
{
String versionString = result.getSecond().trim();
logger.info("Using legacy local JodCoverter: " + versionString);
logger.debug(message);
}
else
{
String message = "Legacy local JodConverter is not available for transformations. " + result.getSecond();
if (isAvailable == null)
{
logger.debug(message);
}
else
{
logger.error(message);
}
logger.error(message);
}
}
}

View File

@@ -1,128 +0,0 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2019 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* 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 <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.content.transform;
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.NodeRef;
import org.alfresco.util.TempFileProvider;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Transformer that passes a document through a pipeline of transformations to arrive at an target mimetype.
*
* Instances are automatically created for transformers identified by alfresco/transform json files and returned from
* T-Engines which are themselves identified by global properties the match the pattern localTransformer.&lt;name>.url.
* The transforms take place in a separate process (typically a Docker container).
*/
public class LocalPipelineTransformer extends AbstractLocalTransformer
{
private final List<IntermediateTransformer> transformers = new ArrayList<>();
private class IntermediateTransformer
{
LocalTransformer intermediateTransformer;
String targetMimetype;
}
public LocalPipelineTransformer(String name, TransformerDebug transformerDebug,
MimetypeService mimetypeService, boolean strictMimeTypeCheck,
Map<String, Set<String>> strictMimetypeExceptions,
boolean retryTransformOnDifferentMimeType,
LocalTransformServiceRegistry localTransformServiceRegistry)
{
super(name, transformerDebug, mimetypeService, strictMimeTypeCheck, strictMimetypeExceptions,
retryTransformOnDifferentMimeType, localTransformServiceRegistry);
}
@Override
public boolean isAvailable()
{
return true;
}
public void addIntermediateTransformer(LocalTransformer intermediateTransformer, String targetMimetype)
{
IntermediateTransformer transformer = new IntermediateTransformer();
transformer.intermediateTransformer = intermediateTransformer;
transformer.targetMimetype = targetMimetype;
transformers.add(transformer);
}
@Override
protected void transformImpl(ContentReader reader,
ContentWriter writer, Map<String, String> transformOptions,
String sourceMimetype, String targetMimetype,
String sourceExtension, String targetExtension,
String renditionName, NodeRef sourceNodeRef) throws Exception
{
ContentReader currentReader = reader;
int lastI = transformers.size() - 1;
for (int i = 0; i <= lastI; i++)
{
IntermediateTransformer transformer = transformers.get(i);
ContentWriter currentWriter;
if (i == lastI)
{
currentWriter = writer;
}
else
{
// make a temp file writer with the correct extension
String sourceExt = mimetypeService.getExtension(currentReader.getMimetype());
String targetExt = mimetypeService.getExtension(transformer.targetMimetype);
File tempFile = TempFileProvider.createTempFile(
"LocalPipelineTransformer_intermediate_" + sourceExt + "_",
"." + targetExt);
currentWriter = new FileContentWriter(tempFile);
currentWriter.setMimetype(transformer.targetMimetype);
}
transformer.intermediateTransformer.transform(currentReader, currentWriter, transformOptions, renditionName, sourceNodeRef);
// Clear the sourceNodeRef after the first transformation to avoid later transformers thinking the
// intermediate file is the original node.
if (i == 0)
{
sourceNodeRef = null;
}
// Pass the output to the next transformer
if (i < lastI)
{
currentReader = currentWriter.getReader();
}
}
}
}

View File

@@ -1,398 +0,0 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2019 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* 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 <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.content.transform;
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.NodeRef;
import org.alfresco.transform.client.model.config.TransformServiceRegistry;
import org.alfresco.transform.client.model.config.TransformServiceRegistryImpl;
import org.alfresco.transform.client.model.config.TransformStep;
import org.alfresco.transform.client.model.config.Transformer;
import org.alfresco.util.PropertyCheck;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
/**
* Implements {@link TransformServiceRegistry} providing a mechanism of validating if a local transformation
* (based on {@link LocalTransformer} request is supported. It also extends this interface to provide a
* {@link #transform} method.
* @author adavis
*/
public class LocalTransformServiceRegistry extends TransformServiceRegistryImpl implements InitializingBean
{
private static final Log log = LogFactory.getLog(LocalTransformer.class);
private static final String LOCAL_TRANSFORMER = "localTransformer.";
private static final String URL = ".url";
static final String STRICT_MIMETYPE_CHECK_WHITELIST_MIMETYPES = "transformer.strict.mimetype.check.whitelist.mimetypes";
private String pipelineConfigFolder;
private boolean enabled = true;
private boolean firstTime = true;
private Properties properties;
private MimetypeService mimetypeService;
private TransformerDebug transformerDebug;
private boolean strictMimeTypeCheck;
private Map<String, Set<String>> strictMimetypeExceptions;
private boolean retryTransformOnDifferentMimeType;
private Map<String, LocalTransformer> transformers = new HashMap<>();
public void setPipelineConfigFolder(String pipelineConfigFolder)
{
this.pipelineConfigFolder = pipelineConfigFolder;
}
public void setEnabled(boolean enabled)
{
this.enabled = enabled;
firstTime = true;
}
/**
* The Alfresco global properties.
*/
public void setProperties(Properties properties)
{
this.properties = properties;
}
public void setMimetypeService(MimetypeService mimetypeService)
{
this.mimetypeService = mimetypeService;
}
public void setTransformerDebug(TransformerDebug transformerDebug)
{
this.transformerDebug = transformerDebug;
}
public void setStrictMimeTypeCheck(boolean strictMimeTypeCheck)
{
this.strictMimeTypeCheck = strictMimeTypeCheck;
}
public void setRetryTransformOnDifferentMimeType(boolean retryTransformOnDifferentMimeType)
{
this.retryTransformOnDifferentMimeType = retryTransformOnDifferentMimeType;
}
@Override
public void afterPropertiesSet() throws Exception
{
PropertyCheck.mandatory(this, "mimetypeService", mimetypeService);
PropertyCheck.mandatory(this, "pipelineConfigFolder", pipelineConfigFolder);
PropertyCheck.mandatory(this, "properties", properties);
PropertyCheck.mandatory(this, "transformerDebug", transformerDebug);
super.afterPropertiesSet();
transformers.clear();
strictMimetypeExceptions = getStrictMimetypeExceptions();
// TODO read json from the T-Engines. Need to find urls to these by looking for a-g.p or system props that match "localTransformer.*.url"
// Do before reading local files, so the files can override T-Engine values.
List<String> urls = getTEngineUrls();
// Reads files alfresco/transformers from resource path
register(pipelineConfigFolder);
}
@Override
public void register(Transformer transformer)
{
super.register(transformer);
try
{
String name = transformer.getTransformerName();
if (name == null || transformers.get(name) != null)
{
throw new IllegalArgumentException("Local transformer names must exist and be unique (" + name + ").");
}
List<TransformStep> transformerPipeline = transformer.getTransformerPipeline();
LocalTransformer localTransformer;
if (transformerPipeline == null)
{
String baseUrl = getBaseUrl(name);
int startupRetryPeriodSeconds = getStartupRetryPeriodSeconds(name);
localTransformer = new LocalTransformerImpl(name, transformerDebug, mimetypeService,
strictMimeTypeCheck, strictMimetypeExceptions, retryTransformOnDifferentMimeType,
this, baseUrl, startupRetryPeriodSeconds);
}
else
{
int transformerCount = transformerPipeline.size();
if (transformerCount <= 1)
{
throw new IllegalArgumentException("Local pipeline transformer " + name +
" must have more than one intermediate transformer defined.");
}
localTransformer = new LocalPipelineTransformer(name, transformerDebug, mimetypeService,
strictMimeTypeCheck, strictMimetypeExceptions, retryTransformOnDifferentMimeType,
this);
for (int i=0; i < transformerCount; i++)
{
TransformStep intermediateTransformerStep = transformerPipeline.get(i);
String intermediateTransformerName = intermediateTransformerStep.getTransformerName();
if (name == null || transformers.get(name) != null)
{
throw new IllegalArgumentException("Local pipeline transformer " + name +
" did not specified an intermediate transformer name.");
}
LocalTransformer intermediateTransformer = transformers.get(intermediateTransformerName);
if (intermediateTransformer == null)
{
throw new IllegalArgumentException("Local pipeline transformer " + name +
" specified an intermediate transformer (" +
intermediateTransformerName + " that has not previously been defined.");
}
String targetMimetype = intermediateTransformerStep.getTargetMediaType();
if (i == transformerCount-1)
{
if (targetMimetype != null)
{
throw new IllegalArgumentException("Local pipeline transformer " + name +
" must not specify targetExt for the final intermediate transformer, " +
"as this is defined via the supportedSourceAndTargetList.");
}
}
else
{
if (targetMimetype == null)
{
throw new IllegalArgumentException("Local pipeline transformer " + name +
" must specify targetExt for all intermediate transformers except for the final one.");
}
}
((LocalPipelineTransformer)localTransformer).addIntermediateTransformer(intermediateTransformer, targetMimetype);
}
}
transformers.put(name, localTransformer);
}
catch (IllegalArgumentException e)
{
String msg = e.getMessage();
getLog().error(msg);
}
}
@Override
protected Log getLog()
{
return log;
}
private List<String> getTEngineUrls()
{
List<String> urls = new ArrayList<>();
for (Object o : getKeySet())
{
if (o instanceof String)
{
String key = (String)o;
if (key.startsWith(LOCAL_TRANSFORMER) && key.endsWith(URL))
{
Object url = getProperty(key, null);
if (url instanceof String)
{
String urlStr = ((String)url).trim();
if (!urlStr.isEmpty())
{
urls.add((String) url);
getLog().debug("T-Engine "+key+"="+url);
}
}
}
}
}
return urls;
}
private String getBaseUrl(String name)
{
String baseUrlName = LOCAL_TRANSFORMER + name + URL;
String baseUrl = getProperty(baseUrlName, null);
if (baseUrl == null)
{
throw new IllegalArgumentException("Local transformer property " + baseUrlName + " was not set");
}
return baseUrl;
}
private int getStartupRetryPeriodSeconds(String name)
{
String startupRetryPeriodSecondsName = LOCAL_TRANSFORMER + name + ".startupRetryPeriodSeconds";
String property = getProperty(startupRetryPeriodSecondsName, "60");
int startupRetryPeriodSeconds;
try
{
startupRetryPeriodSeconds = Integer.parseInt(property);
}
catch (NumberFormatException e)
{
throw new IllegalArgumentException("Local transformer property " + startupRetryPeriodSecondsName +
" should be an integer");
}
return startupRetryPeriodSeconds;
}
private Map<String, Set<String>> getStrictMimetypeExceptions()
{
Map<String, Set<String>> strictMimetypeExceptions = new HashMap<>();
String whitelist = getProperty(STRICT_MIMETYPE_CHECK_WHITELIST_MIMETYPES, "").trim();
if (!whitelist.isEmpty())
{
String[] mimetypes = whitelist.split(";");
if (mimetypes.length % 2 != 0)
{
getLog().error(STRICT_MIMETYPE_CHECK_WHITELIST_MIMETYPES+" should have an even number of mimetypes as a ; separated list.");
}
else
{
Set<String> detectedMimetypes = null;
for (String mimetype: mimetypes)
{
mimetype = mimetype.trim();
if (mimetype.isEmpty())
{
getLog().error(STRICT_MIMETYPE_CHECK_WHITELIST_MIMETYPES+" contains a blank mimetype.");
// Still okay to use it in the map though, but it will be ignored.
}
if (detectedMimetypes == null)
{
detectedMimetypes = strictMimetypeExceptions.get(mimetype);
if (detectedMimetypes == null)
{
detectedMimetypes = new HashSet<>();
strictMimetypeExceptions.put(mimetype, detectedMimetypes);
}
}
else
{
detectedMimetypes.add(mimetype);
detectedMimetypes = null;
}
}
}
}
return strictMimetypeExceptions;
}
/**
* @return the set of property keys and System keys.
*/
private Set<String> getKeySet()
{
Set<Object> systemKeys = System.getProperties().keySet();
Set<Object> alfrescoGlobalKeys = this.properties.keySet();
Set<String> keys = new HashSet<>(systemKeys.size()+alfrescoGlobalKeys.size());
addStrings(keys, systemKeys);
addStrings(keys, alfrescoGlobalKeys);
return keys;
}
private void addStrings(Set<String> setOfStrings, Set<Object> objects)
{
objects.forEach(object->{
if (object instanceof String)
{
setOfStrings.add((String)object);
}
});
}
/**
* Gets a property from an alfresco global property but falls back to a System property with the same name to
* allow dynamic creation of transformers without having to have an AMP to add the alfresco global property.
*/
private String getProperty(String name, String defaultValue)
{
String value = properties.getProperty(name);
if (value == null || value.isEmpty())
{
value = System.getProperty(name);
if (value != null && value.isEmpty())
{
value = null;
}
}
return value == null ? defaultValue : value;
}
@Override
public long getMaxSize(String sourceMimetype, String targetMimetype, Map<String, String> options, String renditionName)
{
// This message is not logged if placed in afterPropertiesSet
if (firstTime)
{
firstTime = false;
transformerDebug.debug("Local transforms are " + (enabled ? "enabled" : "disabled"));
}
return enabled
? super.getMaxSize(sourceMimetype, targetMimetype, options, renditionName)
: 0;
}
public void transform(ContentReader reader, ContentWriter writer, Map<String, String> actualOptions,
String renditionName, NodeRef sourceNodeRef) throws Exception
{
String sourceMimetype = reader.getMimetype();
String targetMimetype = writer.getMimetype();
long sourceSizeInBytes = reader.getSize();
LocalTransformer localTransformer = getLocalTransformer(actualOptions, renditionName, sourceMimetype, targetMimetype, sourceSizeInBytes);
localTransformer.transform(reader, writer, actualOptions, renditionName, sourceNodeRef);
}
public LocalTransformer getLocalTransformer(Map<String, String> actualOptions, String renditionName,
String sourceMimetype, String targetMimetype, long sourceSizeInBytes)
{
String name = getTransformerName(sourceMimetype, sourceSizeInBytes, targetMimetype, actualOptions, renditionName);
return transformers.get(name);
}
}

View File

@@ -1,42 +0,0 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2019 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* 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 <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.content.transform;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.NodeRef;
import java.util.Map;
/**
* Interface of a local transformer using flat transform options.
*/
public interface LocalTransformer
{
void transform(ContentReader reader, ContentWriter writer, Map<String, String> transformOptions,
String renditionName, NodeRef sourceNodeRef)
throws Exception;
}

View File

@@ -1,194 +0,0 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2019 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* 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 <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.content.transform;
import org.alfresco.repo.rendition2.RenditionDefinition2;
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.NodeRef;
import org.alfresco.util.Pair;
import java.util.Map;
import java.util.Set;
/**
* A local transformer using flat transform options.
*
* Instances are automatically created for transformers identified by alfresco/transform json files and returned from
* T-Engines which are themselves identified by global properties or system properties the match the pattern
* localTransformer.&lt;name>.url. The transforms take place in a separate process (typically a Docker container).
*/
public class LocalTransformerImpl extends AbstractLocalTransformer
{
private RemoteTransformerClient remoteTransformerClient;
private boolean available = false;
public LocalTransformerImpl(String name, TransformerDebug transformerDebug,
MimetypeService mimetypeService, boolean strictMimeTypeCheck,
Map<String, Set<String>> strictMimetypeExceptions,
boolean retryTransformOnDifferentMimeType,
LocalTransformServiceRegistry localTransformServiceRegistry, String baseUrl,
int startupRetryPeriodSeconds)
{
super(name, transformerDebug, mimetypeService, strictMimeTypeCheck, strictMimetypeExceptions,
retryTransformOnDifferentMimeType, localTransformServiceRegistry);
remoteTransformerClient = new RemoteTransformerClient(name, baseUrl);
remoteTransformerClient.setStartupRetryPeriodSeconds(startupRetryPeriodSeconds);
checkAvailability();
}
private boolean remoteTransformerClientConfigured()
{
return remoteTransformerClient.getBaseUrl() != null;
}
@Override
public boolean isAvailable()
{
if (remoteTransformerClientConfigured() && !remoteTransformerClient.isAvailable())
{
checkAvailability();
}
return available;
}
private void setAvailable(boolean available)
{
this.available = available;
}
private void checkAvailability()
{
// check availability
if (remoteTransformerClientConfigured())
{
try
{
Pair<Boolean, String> result = remoteTransformerClient.check(log);
Boolean isAvailable = result.getFirst();
String msg = result.getSecond() == null ? "" : result.getSecond();
if (isAvailable != null && isAvailable)
{
setAvailable(true);
log.info("Using local transformer " + name + ": " + msg);
}
else
{
setAvailable(false);
String message = "Local transformer " + name + " is not available. " + msg;
if (isAvailable == null)
{
log.debug(message);
}
else
{
log.error(message);
}
}
}
catch (Throwable e)
{
setAvailable(false);
log.error("Local transformer " + name + " is not available: " + (e.getMessage() != null ? e.getMessage() : ""));
log.debug(e);
}
}
else
{
setAvailable(false);
}
}
@Override
protected void transformImpl(ContentReader reader,
ContentWriter writer, Map<String, String> transformOptions,
String sourceMimetype, String targetMimetype,
String sourceExtension, String targetExtension,
String renditionName, NodeRef sourceNodeRef) throws Exception
{
boolean removeSourceEncoding = false;
try
{
// At some point in the future, we may decide to only pass the sourceEncoding and other dynamic values like
// it if they were supplied in the rendition definition without a value. The sourceEncoding value is also
// supplied in the TransformRequest (message to the T-Router).
if (transformOptions.get("sourceEncoding") == null)
{
String sourceEncoding = reader.getEncoding();
transformOptions.put("sourceEncoding", sourceEncoding);
removeSourceEncoding = true;
}
// Build an array of option names and values and extract the timeout.
long timeoutMs = 0;
int nonOptions = transformOptions.containsKey(RenditionDefinition2.TIMEOUT) ? 1 : 0;
int size = (transformOptions.size() - nonOptions + 3) * 2;
String[] args = new String[size];
int i = 0;
for (Map.Entry<String, String> option : transformOptions.entrySet())
{
String name = option.getKey();
String value = option.getValue();
if (RenditionDefinition2.TIMEOUT.equals(name))
{
if (value != null)
{
timeoutMs = Long.parseLong(value);
}
}
else
{
args[i++] = name;
args[i++] = value;
}
}
// These 3 values are commonly needed and are always supplied in the TransformRequest (message to the T-Router).
// The targetExtension is also supplied in the TransformRequest, but in the case of local and legacy transformers
// is added by the remoteTransformerClient.request call for historic reasons, so does not need to be added here.
args[i++] = "sourceMimetype";
args[i++] = sourceMimetype;
args[i++] = "sourceExtension";
args[i++] = sourceExtension;
args[i++] = "targetMimetype";
args[i++] = targetMimetype;
remoteTransformerClient.request(reader, writer, sourceMimetype, sourceExtension, targetExtension,
timeoutMs, log, args);
}
finally
{
if (removeSourceEncoding)
{
transformOptions.remove("sourceEncoding");
}
}
}
}

View File

@@ -53,7 +53,10 @@ import java.util.StringJoiner;
* saved in a ContentWriter. In the event of an error an Exception is thrown.
*
* @since 6.0
*
* @deprecated The transformations code is being moved out of the codebase and replaced by the new async RenditionService2 or other external libraries.
*/
@Deprecated
public class RemoteTransformerClient
{
private final String name;
@@ -134,7 +137,7 @@ public class RemoteTransformerClient
if (logger.isDebugEnabled())
{
logger.debug(name+' '+sourceExtension+' '+targetExtension+' '+url+' '+args);
logger.debug("Remote "+name+' '+sourceExtension+' '+targetExtension+' '+url+' '+args);
}
try
@@ -146,7 +149,7 @@ public class RemoteTransformerClient
StatusLine statusLine = response.getStatusLine();
if (statusLine == null)
{
throw new AlfrescoRuntimeException(name+" returned no status " + url + ' ' + args);
throw new AlfrescoRuntimeException("Remote "+name+" returned no status " + url + ' ' + args);
}
HttpEntity resEntity = response.getEntity();
if (resEntity != null)
@@ -161,7 +164,7 @@ public class RemoteTransformerClient
long responseContentLength = resEntity.getContentLength();
Header responseContentEncoding = resEntity.getContentEncoding();
Header responseContentType = resEntity.getContentType();
logger.debug(name + ' ' + sourceExtension + ' ' + targetExtension +
logger.debug("Remote " + name + ' ' + sourceExtension + ' ' + targetExtension +
" returned. length=" + responseContentLength +
" type=" + responseContentType +
" encoding=" + responseContentEncoding);
@@ -172,13 +175,13 @@ public class RemoteTransformerClient
}
catch (IOException e)
{
throw new AlfrescoRuntimeException(name + " failed to read the returned content", e);
throw new AlfrescoRuntimeException("Remote " + name + " failed to read the returned content", e);
}
}
else
{
String message = getErrorMessage(resEntity);
String msg = (name + " returned a " + statusCode + " status " + message +
String msg = ("Remote " + name + " returned a " + statusCode + " status " + message +
' ' + url + ' ' + args).trim();
if (statusCode == 401)
{
@@ -196,7 +199,7 @@ public class RemoteTransformerClient
}
else
{
throw new AlfrescoRuntimeException(name + " did not return an entity " + url);
throw new AlfrescoRuntimeException("Remote " + name + " did not return an entity " + url);
}
}
catch (IOException e)
@@ -204,12 +207,12 @@ public class RemoteTransformerClient
// In the case of transform requests, unlike version checks, it is only the failure to connect that
// forces a wait before trying again.
connectionFailed();
throw new AlfrescoRuntimeException(name + " failed to connect or to read the response", e);
throw new AlfrescoRuntimeException("Remote " + name + " failed to connect or to read the response", e);
}
}
catch (IOException e)
{
throw new AlfrescoRuntimeException(name + " failed to create an HttpClient", e);
throw new AlfrescoRuntimeException("Remote " + name + " failed to create an HttpClient", e);
}
}
catch (AlfrescoRuntimeException e)
@@ -232,7 +235,7 @@ public class RemoteTransformerClient
{
if (!isTimeToCheckAvailability())
{
logger.debug(name+' '+" too early to check availability");
logger.debug("Remote "+name+' '+" too early to check availability");
Pair<Boolean, String> result = getCheckResult();
return result;
}
@@ -242,7 +245,7 @@ public class RemoteTransformerClient
if (logger.isDebugEnabled())
{
logger.debug(name+' '+" check" +url);
logger.debug("Remote "+name+' '+" check" +url);
}
try
@@ -254,7 +257,7 @@ public class RemoteTransformerClient
StatusLine statusLine = response.getStatusLine();
if (statusLine == null)
{
throw new AlfrescoRuntimeException(name+" check returned no status " + url);
throw new AlfrescoRuntimeException("Remote "+name+" check returned no status " + url);
}
HttpEntity resEntity = response.getEntity();
if (resEntity != null)
@@ -271,7 +274,7 @@ public class RemoteTransformerClient
long responseContentLength = resEntity.getContentLength();
Header responseContentType = resEntity.getContentType();
Header responseContentEncoding = resEntity.getContentEncoding();
logger.debug(name +
logger.debug("Remote " + name +
" check returned. length=" + responseContentLength +
" type=" + responseContentType +
" encoding=" + responseContentEncoding+
@@ -286,28 +289,28 @@ public class RemoteTransformerClient
}
catch (IOException e)
{
throw new AlfrescoRuntimeException(name + " check failed to read the returned content", e);
throw new AlfrescoRuntimeException("Remote " + name + " check failed to read the returned content", e);
}
}
else
{
String message = getErrorMessage(resEntity);
throw new AlfrescoRuntimeException(name + " check returned a " + statusCode + " status " + message + ' ' + url);
throw new AlfrescoRuntimeException("Remote " + name + " check returned a " + statusCode + " status " + message + ' ' + url);
}
}
else
{
throw new AlfrescoRuntimeException(name + " check did not return an entity " + url);
throw new AlfrescoRuntimeException("Remote " + name + " check did not return an entity " + url);
}
}
catch (IOException e)
{
throw new AlfrescoRuntimeException(name + " check failed to connect or to read the response", e);
throw new AlfrescoRuntimeException("Remote " + name + " check failed to connect or to read the response", e);
}
}
catch (IOException e)
{
throw new AlfrescoRuntimeException(name + " check failed to create an HttpClient", e);
throw new AlfrescoRuntimeException("Remote " + name + " check failed to create an HttpClient", e);
}
}
catch (AlfrescoRuntimeException e)

View File

@@ -25,37 +25,8 @@
*/
package org.alfresco.repo.content.transform;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.content.filestore.FileContentWriter;
import org.alfresco.repo.model.Repository;
import org.alfresco.repo.rendition2.RenditionDefinition2;
import org.alfresco.repo.rendition2.RenditionDefinition2Impl;
import org.alfresco.repo.rendition2.RenditionDefinitionRegistry2Impl;
import org.alfresco.repo.rendition2.TransformClient;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.MimetypeService;
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.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.util.EqualsHelper;
import org.alfresco.util.LogTee;
import org.alfresco.util.PropertyCheck;
import org.alfresco.util.TempFileProvider;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import java.io.File;
import java.io.Serializable;
import java.net.URI;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayDeque;
import java.util.ArrayList;
@@ -63,11 +34,8 @@ import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Deque;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
@@ -75,7 +43,24 @@ import java.util.TreeSet;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Pattern;
import static org.alfresco.repo.rendition2.RenditionService2Impl.SOURCE_HAS_NO_CONTENT;
import org.alfresco.api.AlfrescoPublicApi;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel;
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.ContentService;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.MimetypeService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.TransformationOptions;
import org.alfresco.util.EqualsHelper;
import org.alfresco.util.LogTee;
import org.alfresco.util.TempFileProvider;
import org.apache.commons.io.FileUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Debugs transformers selection and activity.<p>
@@ -94,26 +79,21 @@ import static org.alfresco.repo.rendition2.RenditionService2Impl.SOURCE_HAS_NO_C
* transformers) and {@link #popAvailable} are called.<p>
*
* @author Alan Davis
*
* @deprecated The transformations code is being moved out of the codebase and replaced by the new async RenditionService2 or other external libraries.
*/
public class TransformerDebug implements ApplicationContextAware
@Deprecated
@AlfrescoPublicApi
public class TransformerDebug
{
private static final String FINISHED_IN = "Finished in ";
private static final String NO_TRANSFORMERS = "No transformers";
private Log info;
private Log logger;
private NodeService nodeService;
private MimetypeService mimetypeService;
private ContentTransformerRegistry transformerRegistry;
private TransformerConfig transformerConfig;
private ApplicationContext applicationContext;
private ContentService contentService;
private TransformClient transformClient;
private Repository repositoryHelper;
private TransactionService transactionService;
private RenditionDefinitionRegistry2Impl renditionDefinitionRegistry2;
private final Log logger;
private final Log info;
@Deprecated
@AlfrescoPublicApi
private enum Call
{
AVAILABLE,
@@ -121,6 +101,8 @@ public class TransformerDebug implements ApplicationContextAware
AVAILABLE_AND_TRANSFORM
};
@Deprecated
@AlfrescoPublicApi
private static class ThreadInfo
{
private static final ThreadLocal<ThreadInfo> threadInfo = new ThreadLocal<ThreadInfo>()
@@ -171,6 +153,8 @@ public class TransformerDebug implements ApplicationContextAware
}
}
@Deprecated
@AlfrescoPublicApi
private static class Frame
{
private static final AtomicInteger uniqueId = new AtomicInteger(0);
@@ -179,8 +163,7 @@ public class TransformerDebug implements ApplicationContextAware
private final String fromUrl;
private final String sourceMimetype;
private final String targetMimetype;
private final NodeRef sourceNodeRef;
private final String renditionName;
private final TransformationOptions options;
private final boolean origDebugOutput;
private long start;
@@ -193,7 +176,7 @@ public class TransformerDebug implements ApplicationContextAware
private String transformerName;
private Frame(Frame parent, String transformerName, String fromUrl, String sourceMimetype, String targetMimetype,
long sourceSize, String renditionName, NodeRef sourceNodeRef, Call pushCall, boolean origDebugOutput)
long sourceSize, TransformationOptions options, Call pushCall, boolean origDebugOutput)
{
this.id = -1;
this.parent = parent;
@@ -202,8 +185,7 @@ public class TransformerDebug implements ApplicationContextAware
this.sourceMimetype = sourceMimetype;
this.targetMimetype = targetMimetype;
this.sourceSize = sourceSize;
this.renditionName = renditionName;
this.sourceNodeRef = sourceNodeRef;
this.options = options;
this.callType = pushCall;
this.origDebugOutput = origDebugOutput;
start = System.currentTimeMillis();
@@ -250,6 +232,7 @@ public class TransformerDebug implements ApplicationContextAware
}
@Deprecated
@AlfrescoPublicApi
private class UnavailableTransformer implements Comparable<UnavailableTransformer>
{
private final String name;
@@ -300,49 +283,26 @@ public class TransformerDebug implements ApplicationContextAware
}
}
public void setTransformerLog(Log transformerLog)
{
info = new LogTee(LogFactory.getLog(TransformerLog.class), transformerLog);
}
private final NodeService nodeService;
private final MimetypeService mimetypeService;
private final ContentTransformerRegistry transformerRegistry;
private final TransformerConfig transformerConfig;
private ContentService contentService;
public void setTransformerDebugLog(Log transformerDebugLog)
{
logger = new LogTee(LogFactory.getLog(TransformerDebug.class), transformerDebugLog);
}
public void setNodeService(NodeService nodeService)
/**
* Constructor
*/
public TransformerDebug(NodeService nodeService, MimetypeService mimetypeService,
ContentTransformerRegistry transformerRegistry, TransformerConfig transformerConfig,
Log transformerLog, Log transformerDebugLog)
{
this.nodeService = nodeService;
}
public void setMimetypeService(MimetypeService mimetypeService)
{
this.mimetypeService = mimetypeService;
}
public void setTransformerRegistry(ContentTransformerRegistry transformerRegistry)
{
this.transformerRegistry = transformerRegistry;
}
public void setTransformerConfig(TransformerConfig transformerConfig)
{
this.transformerConfig = transformerConfig;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
{
this.applicationContext = applicationContext;
}
private ContentService getContentService()
{
if (contentService == null)
{
contentService = (ContentService) applicationContext.getBean("contentService");
}
return contentService;
logger = new LogTee(LogFactory.getLog(TransformerDebug.class), transformerDebugLog);
info = new LogTee(LogFactory.getLog(TransformerLog.class), transformerLog);
}
public void setContentService(ContentService contentService)
@@ -350,135 +310,37 @@ public class TransformerDebug implements ApplicationContextAware
this.contentService = contentService;
}
private TransformClient getTransformClient()
{
if (transformClient == null)
{
transformClient = (TransformClient) applicationContext.getBean("transformClient");
}
return transformClient;
}
public void setTransformClient(TransformClient transformClient)
{
this.transformClient = transformClient;
}
public Repository getRepositoryHelper()
{
if (repositoryHelper == null)
{
repositoryHelper = (Repository) applicationContext.getBean("repositoryHelper");
}
return repositoryHelper;
}
public void setRepositoryHelper(Repository repositoryHelper)
{
this.repositoryHelper = repositoryHelper;
}
public TransactionService getTransactionService()
{
if (transactionService == null)
{
transactionService = (TransactionService) applicationContext.getBean("transactionService");
}
return transactionService;
}
public void setTransactionService(TransactionService transactionService)
{
this.transactionService = transactionService;
}
public RenditionDefinitionRegistry2Impl getRenditionDefinitionRegistry2Impl()
{
if (renditionDefinitionRegistry2 == null)
{
renditionDefinitionRegistry2 = (RenditionDefinitionRegistry2Impl) applicationContext.getBean("renditionDefinitionRegistry2");
}
return renditionDefinitionRegistry2;
}
public void setRenditionDefinitionRegistry2(RenditionDefinitionRegistry2Impl renditionDefinitionRegistry2)
{
this.renditionDefinitionRegistry2 = renditionDefinitionRegistry2;
}
public void afterPropertiesSet() throws Exception
{
PropertyCheck.mandatory(this, "transformerLog", info);
PropertyCheck.mandatory(this, "transformerDebugLog", logger);
PropertyCheck.mandatory(this, "nodeService", nodeService);
PropertyCheck.mandatory(this, "mimetypeService", mimetypeService);
PropertyCheck.mandatory(this, "transformerRegistry", transformerRegistry);
PropertyCheck.mandatory(this, "transformerConfig", transformerConfig);
}
@Deprecated
public void pushAvailable(String fromUrl, String sourceMimetype, String targetMimetype,
TransformationOptions options)
{
String renditionName = options == null ? null : options.getUse();
NodeRef sourceNodeRef = options == null ? null : options.getSourceNodeRef();
pushAvailable(fromUrl, sourceMimetype, targetMimetype, renditionName, sourceNodeRef);
}
/**
* Called prior to working out what transformers are available.
*/
@Deprecated
public void pushAvailable(String fromUrl, String sourceMimetype, String targetMimetype,
String renditionName, NodeRef sourceNodeRef)
TransformationOptions options)
{
if (isEnabled())
{
push(null, fromUrl, sourceMimetype, targetMimetype, -1, renditionName,
sourceNodeRef, Call.AVAILABLE);
push(null, fromUrl, sourceMimetype, targetMimetype, -1, options, Call.AVAILABLE);
}
}
/**
* Called when a transformer has been ignored because of a blacklist entry.
*/
@Deprecated
public void blacklistTransform(ContentTransformer transformer, String sourceMimetype,
String targetMimetype, TransformationOptions options)
{
log("Blacklist "+getName(transformer)+" "+getMimetypeExt(sourceMimetype)+getMimetypeExt(targetMimetype));
}
@Deprecated
public void pushTransform(ContentTransformer transformer, String fromUrl, String sourceMimetype,
String targetMimetype, long sourceSize, TransformationOptions options)
{
String renditionName = options == null ? null : options.getUse();
NodeRef sourceNodeRef = options == null ? null : options.getSourceNodeRef();
pushTransform(transformer, fromUrl, sourceMimetype, targetMimetype, sourceSize, renditionName, sourceNodeRef);
}
/**
* Called prior to performing a transform.
*/
@Deprecated
public void pushTransform(ContentTransformer transformer, String fromUrl, String sourceMimetype,
String targetMimetype, long sourceSize, String renditionName, NodeRef sourceNodeRef)
String targetMimetype, long sourceSize, TransformationOptions options)
{
if (isEnabled())
{
push(getName(transformer), fromUrl, sourceMimetype, targetMimetype, sourceSize,
renditionName, sourceNodeRef, Call.TRANSFORM);
}
}
public void pushTransform(String transformerName, String fromUrl, String sourceMimetype,
String targetMimetype, long sourceSize, String renditionName, NodeRef sourceNodeRef)
{
if (isEnabled())
{
push(transformerName, fromUrl, sourceMimetype, targetMimetype, sourceSize,
renditionName, sourceNodeRef, Call.TRANSFORM);
options, Call.TRANSFORM);
}
}
@@ -491,14 +353,13 @@ public class TransformerDebug implements ApplicationContextAware
{
if (isEnabled())
{
push(null, null, null, null, -1, null, null, Call.AVAILABLE);
push(null, null, null, null, -1, null, Call.AVAILABLE);
}
}
/**
* Called prior to calling a nested isTransformable.
*/
@Deprecated
public void pushIsTransformableSize(ContentTransformer transformer)
{
if (isEnabled())
@@ -508,7 +369,7 @@ public class TransformerDebug implements ApplicationContextAware
}
private void push(String transformerName, String fromUrl, String sourceMimetype, String targetMimetype,
long sourceSize, String renditionName, NodeRef sourceNodeRef, Call callType)
long sourceSize, TransformationOptions options, Call callType)
{
Deque<Frame> ourStack = ThreadInfo.getStack();
Frame frame = ourStack.peek();
@@ -522,14 +383,13 @@ public class TransformerDebug implements ApplicationContextAware
// Create a new frame. Logging level is set to trace if the file size is 0
boolean origDebugOutput = ThreadInfo.setDebugOutput(ThreadInfo.getDebugOutput() && sourceSize != 0);
frame = new Frame(frame, transformerName, fromUrl, sourceMimetype, targetMimetype, sourceSize, renditionName,
sourceNodeRef, callType, origDebugOutput);
frame = new Frame(frame, transformerName, fromUrl, sourceMimetype, targetMimetype, sourceSize, options, callType, origDebugOutput);
ourStack.push(frame);
if (callType == Call.TRANSFORM)
{
// Log the basic info about this transformation
logBasicDetails(frame, sourceSize, renditionName, transformerName, (ourStack.size() == 1));
logBasicDetails(frame, sourceSize, options.getUse(), transformerName, (ourStack.size() == 1));
}
}
@@ -537,7 +397,6 @@ public class TransformerDebug implements ApplicationContextAware
* Called to identify a transformer that cannot be used during working out
* available transformers.
*/
@Deprecated
public void unavailableTransformer(ContentTransformer transformer, String sourceMimetype, String targetMimetype, long maxSourceSizeKBytes)
{
if (isEnabled())
@@ -562,21 +421,11 @@ public class TransformerDebug implements ApplicationContextAware
}
}
@Deprecated
public void availableTransformers(List<ContentTransformer> transformers, long sourceSize,
TransformationOptions options, String calledFrom)
{
String renditionName = options == null ? null : options.getUse();
NodeRef sourceNodeRef = options == null ? null : options.getSourceNodeRef();
availableTransformers(transformers, sourceSize, renditionName, sourceNodeRef, calledFrom);
}
/**
* Called once all available transformers have been identified.
*/
@Deprecated
public void availableTransformers(List<ContentTransformer> transformers, long sourceSize,
String renditionName, NodeRef sourceNodeRef, String calledFrom)
TransformationOptions options, String calledFrom)
{
if (isEnabled())
{
@@ -598,7 +447,7 @@ public class TransformerDebug implements ApplicationContextAware
frame.setSourceSize(sourceSize);
// Log the basic info about this transformation
logBasicDetails(frame, sourceSize, renditionName,
logBasicDetails(frame, sourceSize, options.getUse(),
calledFrom + ((transformers.size() == 0) ? " NO transformers" : ""), firstLevel);
// Report available and unavailable transformers
@@ -608,11 +457,7 @@ public class TransformerDebug implements ApplicationContextAware
{
String name = getName(trans);
int padName = longestNameLength - name.length() + 1;
// TODO replace with call to RenditionService2 or leave as a deprecated method using ContentService.
TransformationOptions options = new TransformationOptions();
options.setUse(frame.renditionName);
options.setSourceNodeRef(frame.sourceNodeRef);
long maxSourceSizeKBytes = trans.getMaxSourceSizeKBytes(frame.sourceMimetype, frame.targetMimetype, options);
long maxSourceSizeKBytes = trans.getMaxSourceSizeKBytes(frame.sourceMimetype, frame.targetMimetype, frame.options);
String size = maxSourceSizeKBytes > 0 ? "< "+fileSize(maxSourceSizeKBytes*1024) : "";
int padSize = 10 - size.length();
String priority = gePriority(trans, frame.sourceMimetype, frame.targetMimetype);
@@ -646,13 +491,11 @@ public class TransformerDebug implements ApplicationContextAware
return priority;
}
@Deprecated
public void inactiveTransformer(ContentTransformer transformer)
{
log(getName(transformer)+' '+ms(transformer.getTransformationTime(null, null))+" INACTIVE");
}
@Deprecated
public void activeTransformer(int mimetypePairCount, ContentTransformer transformer, String sourceMimetype,
String targetMimetype, long maxSourceSizeKBytes, boolean firstMimetypePair)
{
@@ -668,7 +511,6 @@ public class TransformerDebug implements ApplicationContextAware
(maxSourceSizeKBytes == 0 ? " disabled" : ""));
}
@Deprecated
public void activeTransformer(String sourceMimetype, String targetMimetype,
int transformerCount, ContentTransformer transformer, long maxSourceSizeKBytes,
boolean firstTransformer)
@@ -706,7 +548,7 @@ public class TransformerDebug implements ApplicationContextAware
return longestNameLength;
}
private void logBasicDetails(Frame frame, long sourceSize, String renditionName, String message, boolean firstLevel)
private void logBasicDetails(Frame frame, long sourceSize, String use, String message, boolean firstLevel)
{
// Log the source URL, but there is no point if the parent has logged it
if (frame.fromUrl != null && (firstLevel || frame.id != 1))
@@ -715,14 +557,14 @@ public class TransformerDebug implements ApplicationContextAware
}
log(frame.sourceMimetype+' '+frame.targetMimetype, false);
String fileName = getFileName(frame.sourceNodeRef, firstLevel, sourceSize);
String fileName = getFileName(frame.options, firstLevel, sourceSize);
log(getMimetypeExt(frame.sourceMimetype)+getMimetypeExt(frame.targetMimetype) +
((fileName != null) ? fileName+' ' : "")+
((sourceSize >= 0) ? fileSize(sourceSize)+' ' : "") +
(firstLevel && renditionName != null ? "-- "+renditionName+" -- " : "") + message);
(firstLevel && use != null ? "-- "+use+" -- " : "") + message);
if (firstLevel)
{
String nodeRef = getNodeRef(frame.sourceNodeRef, firstLevel, sourceSize);
String nodeRef = getNodeRef(frame.options, firstLevel, sourceSize);
if (!nodeRef.isEmpty())
{
log(nodeRef);
@@ -817,7 +659,7 @@ public class TransformerDebug implements ApplicationContextAware
boolean firstLevel = size == 1;
String sourceExt = getMimetypeExt(frame.sourceMimetype);
String targetExt = getMimetypeExt(frame.targetMimetype);
String fileName = getFileName(frame.sourceNodeRef, firstLevel, frame.sourceSize);
String fileName = getFileName(frame.options, firstLevel, frame.sourceSize);
long sourceSize = frame.getSourceSize();
String transformerName = frame.getTransformerName();
String level = null;
@@ -1051,11 +893,9 @@ public class TransformerDebug implements ApplicationContextAware
* @param toString indicates that a String value should be returned in addition to any debug.
* @param format42 indicates the old 4.1.4 format should be used which did not order the transformers
* and only included top level transformers.
* @param renditionName to which the transformation will be put (such as "Index", "Preview", null).
* @deprecated The transformations code is being moved out of the codebase and replaced by the new async RenditionService2 or other external libraries.
* @param use to which the transformation will be put (such as "Index", "Preview", null).
*/
@Deprecated
public String transformationsByTransformer(String transformerName, boolean toString, boolean format42, String renditionName)
public String transformationsByTransformer(String transformerName, boolean toString, boolean format42, String use)
{
// Do not generate this type of debug if already generating other debug to a StringBuilder
// (for example a test transform).
@@ -1075,7 +915,7 @@ public class TransformerDebug implements ApplicationContextAware
: mimetypeService.getMimetypes();
TransformationOptions options = new TransformationOptions();
options.setUse(renditionName);
options.setUse(use);
StringBuilder sb = null;
try
{
@@ -1137,12 +977,10 @@ public class TransformerDebug implements ApplicationContextAware
* level transformers.
* @param onlyNonDeterministic if true only report transformations where there is more than
* one transformer available with the same priority.
* @param renditionName to which the transformation will be put (such as "Index", "Preview", null).
* @deprecated The transformations code is being moved out of the codebase and replaced by the new async RenditionService2 or other external libraries.
* @param use to which the transformation will be put (such as "Index", "Preview", null).
*/
@Deprecated
public String transformationsByExtension(String sourceExtension, String targetExtension, boolean toString,
boolean format42, boolean onlyNonDeterministic, String renditionName)
boolean format42, boolean onlyNonDeterministic, String use)
{
// Do not generate this type of debug if already generating other debug to a StringBuilder
// (for example a test transform).
@@ -1162,7 +1000,7 @@ public class TransformerDebug implements ApplicationContextAware
: mimetypeService.getMimetypes();
TransformationOptions options = new TransformationOptions();
options.setUse(renditionName);
options.setUse(use);
StringBuilder sb = null;
try
{
@@ -1410,30 +1248,24 @@ public class TransformerDebug implements ApplicationContextAware
return !transformerRegistry.getTransformers().contains(transformer);
}
@Deprecated
public String getFileName(TransformationOptions options, boolean firstLevel, long sourceSize)
{
NodeRef sourceNodeRef = options == null ? null : options.getSourceNodeRef();
return getFileName(sourceNodeRef, firstLevel, sourceSize);
return getFileNameOrNodeRef(options, firstLevel, sourceSize, true);
}
public String getFileName(NodeRef sourceNodeRef, boolean firstLevel, long sourceSize)
private String getNodeRef(TransformationOptions options, boolean firstLevel, long sourceSize)
{
return getFileNameOrNodeRef(sourceNodeRef, firstLevel, sourceSize, true);
return getFileNameOrNodeRef(options, firstLevel, sourceSize, false);
}
private String getNodeRef(NodeRef sourceNodeRef, boolean firstLevel, long sourceSize)
{
return getFileNameOrNodeRef(sourceNodeRef, firstLevel, sourceSize, false);
}
private String getFileNameOrNodeRef(NodeRef sourceNodeRef, boolean firstLevel, long sourceSize, boolean getName)
private String getFileNameOrNodeRef(TransformationOptions options, boolean firstLevel, long sourceSize, boolean getName)
{
String result = getName ? null : "";
if (sourceNodeRef != null)
if (options != null)
{
try
{
NodeRef sourceNodeRef = options.getSourceNodeRef();
result = getName
? (String)nodeService.getProperty(sourceNodeRef, ContentModel.PROP_NAME)
: sourceNodeRef.toString()+" ";
@@ -1536,9 +1368,7 @@ public class TransformerDebug implements ApplicationContextAware
* @param transformerName to restrict the collection to one entry
* @return a new Collection of sorted transformers
* @throws IllegalArgumentException if transformerName is not found.
* @deprecated The transformations code is being moved out of the codebase and replaced by the new async RenditionService2 or other external libraries.
*/
@Deprecated
public Collection<ContentTransformer> sortTransformersByName(String transformerName)
{
Collection<ContentTransformer> transformers = (transformerName != null)
@@ -1559,14 +1389,13 @@ public class TransformerDebug implements ApplicationContextAware
* Debugs a request to the Transform Service
*/
public int debugTransformServiceRequest(String sourceMimetype, long sourceSize, NodeRef sourceNodeRef,
int contentHashcode, String fileName, String targetMimetype,
String renditionName)
int contentHashcode, String fileName, String targetMimetype, String use)
{
pushMisc();
debug(getMimetypeExt(sourceMimetype)+getMimetypeExt(targetMimetype) +
((fileName != null) ? fileName+' ' : "")+
((sourceSize >= 0) ? fileSize(sourceSize)+' ' : "") +
(renditionName != null ? "-- "+renditionName+" -- " : "") + " RenditionService2");
(use != null ? "-- "+use+" -- " : "") + " RenditionService2");
debug(sourceNodeRef.toString() + ' ' +contentHashcode);
debug(" **a) [01] TransformService");
return pop(Call.AVAILABLE, true, false);
@@ -1597,19 +1426,35 @@ public class TransformerDebug implements ApplicationContextAware
pop(Call.AVAILABLE, suppressFinish, true);
}
public String testTransform(String sourceExtension, String targetExtension, String renditionName)
public String testTransform(String sourceExtension, String targetExtension, String use)
{
return new TestTransform().run(sourceExtension, targetExtension, renditionName);
return new TestTransform()
{
protected void transform(ContentReader reader, ContentWriter writer, TransformationOptions options)
{
contentService.transform(reader, writer, options);
}
}.run(sourceExtension, targetExtension, use);
}
/**
* @deprecated The transformations code is being moved out of the codebase and replaced by the new async RenditionService2 or other external libraries.
*/
@Deprecated
public String testTransform(final String transformerName, String sourceExtension,
String targetExtension, String renditionName)
String targetExtension, String use)
{
return "The testTransform operation for a specific transformer is no longer supported.";
final ContentTransformer transformer = transformerRegistry.getTransformer(transformerName);
return new TestTransform()
{
protected String isTransformable(String sourceMimetype, long sourceSize, String targetMimetype, TransformationOptions options)
{
return transformer.isTransformable(sourceMimetype, sourceSize, targetMimetype, options)
? null
: transformerName+" does not support this transformation.";
}
protected void transform(ContentReader reader, ContentWriter writer, TransformationOptions options)
{
transformer.transform(reader, writer, options);
}
}.run(sourceExtension, targetExtension, use);
}
public String[] getTestFileExtensionsAndMimetypes()
@@ -1654,58 +1499,68 @@ public class TransformerDebug implements ApplicationContextAware
}
@Deprecated
private class TestTransform
@AlfrescoPublicApi
private abstract class TestTransform
{
protected LinkedList<NodeRef> nodesToDeleteAfterTest = new LinkedList<NodeRef>();
String run(String sourceExtension, String targetExtension, String renditionName)
String run(String sourceExtension, String targetExtension, String use)
{
RenditionDefinitionRegistry2Impl renditionDefinitionRegistry2 = getRenditionDefinitionRegistry2Impl();
String debug;
String targetMimetype = getMimetype(targetExtension, false);
String sourceMimetype = getMimetype(sourceExtension, true);
URL sourceURL = loadQuickTestFile(sourceExtension);
if (sourceURL == null)
{
throw new IllegalArgumentException("There is no test file with a "+sourceExtension+" extension.");
}
// This URL may point to a file on the filesystem or to an entry in a jar.
// To use the transform method below, we need the content to be accessible from a ContentReader.
// This is possible for a File but not a (non-file) URL.
//
// Therefore, we'll always copy the URL content to a temporary local file.
final File sourceFile = TempFileProvider.createTempFile(TransformerDebug.class.getSimpleName() + "-tmp-", "");
try { FileUtils.copyURLToFile(sourceURL, sourceFile); }
catch (IOException shouldNeverHappen)
{
// The sourceURL should always be readable as we're reading data that Alfresco is distributing.
// But just in case...
throw new IllegalArgumentException("Cannot read content of test file with a " +
sourceExtension + " extension.", shouldNeverHappen);
}
ContentReader reader = new FileContentReader(sourceFile);
reader.setMimetype(sourceMimetype);
File tempFile = TempFileProvider.createTempFile(
"TestTransform_" + sourceExtension + "_", "." + targetExtension);
ContentWriter writer = new FileContentWriter(tempFile);
writer.setMimetype(targetMimetype);
String testRenditionName = "testTransform"+System.currentTimeMillis();
NodeRef sourceNodeRef = null;
StringBuilder sb = new StringBuilder();
try
{
setStringBuilder(sb);
RenditionDefinition2 renditionDefinition = new RenditionDefinition2Impl(testRenditionName, targetMimetype,
Collections.emptyMap(), renditionDefinitionRegistry2);
long sourceSize = reader.getSize();
TransformationOptions options = new TransformationOptions();
options.setUse(use);
sourceNodeRef = createSourceNode(sourceExtension, sourceMimetype);
ContentData contentData = (ContentData) nodeService.getProperty(sourceNodeRef, ContentModel.PROP_CONTENT);
if (contentData != null)
debug = isTransformable(sourceMimetype, sourceSize, targetMimetype, options);
if (debug == null)
{
StringBuilder sb = new StringBuilder();
try
{
String contentUrl = contentData.getContentUrl();
if (contentUrl != null)
{
long size = contentData.getSize();
int sourceContentHashCode = SOURCE_HAS_NO_CONTENT;
String contentString = contentData.getContentUrl()+contentData.getMimetype();
if (contentString != null)
{
sourceContentHashCode = contentString.hashCode();
}
TransformClient transformClient = getTransformClient();
transformClient.checkSupported(sourceNodeRef, renditionDefinition, sourceMimetype, size, contentUrl);
transformClient.transform(sourceNodeRef, renditionDefinition, "testTransform", sourceContentHashCode);
}
setStringBuilder(sb);
transform(reader, writer, options);
}
catch (AlfrescoRuntimeException e)
{
sb.append(e.getMessage());
}
finally
{
setStringBuilder(null);
}
debug = sb.toString();
}
finally
{
setStringBuilder(null);
renditionDefinitionRegistry2.unregister(testRenditionName);
deleteSourceNode(sourceNodeRef);
}
return sb.toString();
return debug;
}
private String getMimetype(String extension, boolean isSource)
@@ -1726,57 +1581,11 @@ public class TransformerDebug implements ApplicationContextAware
return mimetype;
}
public NodeRef createSourceNode(String extension, String sourceMimetype)
protected String isTransformable(String sourceMimetype, long sourceSize, String targetMimetype, TransformationOptions options)
{
// Create a content node which will serve as test data for our transformations.
RetryingTransactionHelper.RetryingTransactionCallback<NodeRef> makeNodeCallback = new RetryingTransactionHelper.RetryingTransactionCallback<NodeRef>()
{
public NodeRef execute() throws Throwable
{
// Create a source node loaded with a quick file.
URL url = loadQuickTestFile(extension);
URI uri = url.toURI();
File sourceFile = new File(uri);
final NodeRef companyHome = getRepositoryHelper().getCompanyHome();
Map<QName, Serializable> props = new HashMap<QName, Serializable>();
String localName = "TestTransform." + extension;
props.put(ContentModel.PROP_NAME, localName);
NodeRef node = nodeService.createNode(
companyHome,
ContentModel.ASSOC_CONTAINS,
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, localName),
ContentModel.TYPE_CONTENT,
props).getChildRef();
ContentWriter writer = getContentService().getWriter(node, ContentModel.PROP_CONTENT, true);
writer.setMimetype(sourceMimetype);
writer.setEncoding("UTF-8");
writer.putContent(sourceFile);
return node;
}
};
NodeRef contentNodeRef = getTransactionService().getRetryingTransactionHelper().doInTransaction(makeNodeCallback);
this.nodesToDeleteAfterTest.add(contentNodeRef);
return contentNodeRef;
return null;
}
public void deleteSourceNode(NodeRef sourceNodeRef)
{
if (sourceNodeRef != null)
{
getTransactionService().getRetryingTransactionHelper().doInTransaction(
(RetryingTransactionHelper.RetryingTransactionCallback<Void>) () ->
{
if (nodeService.exists(sourceNodeRef))
{
nodeService.deleteNode(sourceNodeRef);
}
return null;
});
}
}
protected abstract void transform(ContentReader reader, ContentWriter writer, TransformationOptions options);
}
}

View File

@@ -30,12 +30,16 @@ import org.alfresco.error.AlfrescoRuntimeException;
/**
* Exception indicates that a transformer is unable to transform a requested
* transformation. Normally the transformer is a component of a pipeline transformer
* and has been asked to transform a file that is too large as the
* transformation. Normally the transformer is a component of a complex (compound) transformer
* and has been asked to transform a file that is too large (see transformation limits) as the
* size of the intermediate file is unknown at the start.
*
* @author Alan Davis
*
* @deprecated The transformations code is being moved out of the codebase and replaced by the new async RenditionService2 or other external libraries.
*/
@Deprecated
@AlfrescoPublicApi
public class UnsupportedTransformationException extends AlfrescoRuntimeException
{
private static final long serialVersionUID = 9039331287661301086L;

View File

@@ -81,8 +81,6 @@ public class ImageMagickContentTransformerWorker extends AbstractImageMagickCont
/** the system command executer */
private RuntimeExec executer;
private boolean enabled = true;
/** the check command executer */
private RuntimeExec checkCommand;
@@ -118,11 +116,6 @@ public class ImageMagickContentTransformerWorker extends AbstractImageMagickCont
this.executer = executer;
}
public void setEnabled(boolean enabled)
{
this.enabled = enabled;
}
/**
* Sets the command that must be executed in order to retrieve version information from the converting executable
* and thus test that the executable itself is present.
@@ -153,57 +146,54 @@ public class ImageMagickContentTransformerWorker extends AbstractImageMagickCont
@Override
public void afterPropertiesSet()
{
if (enabled)
if (!remoteTransformerClientConfigured() && executer == null)
{
if (!remoteTransformerClientConfigured() && executer == null)
throw new AlfrescoRuntimeException("System runtime executer not set");
}
super.afterPropertiesSet();
if (!remoteTransformerClientConfigured())
{
if (isAvailable())
{
throw new AlfrescoRuntimeException("System runtime executer not set");
}
super.afterPropertiesSet();
if (!remoteTransformerClientConfigured())
{
if (isAvailable())
try
{
try
{
// On some platforms / versions, the -version command seems to return an error code whilst still
// returning output, so let's not worry about the exit code!
ExecutionResult result = this.checkCommand.execute();
this.versionString = result.getStdOut().trim();
}
catch (Throwable e)
{
setAvailable(false);
logger.error(getClass().getSimpleName() + " not available: "
+ (e.getMessage() != null ? e.getMessage() : ""));
// debug so that we can trace the issue if required
logger.debug(e);
}
// On some platforms / versions, the -version command seems to return an error code whilst still
// returning output, so let's not worry about the exit code!
ExecutionResult result = this.checkCommand.execute();
this.versionString = result.getStdOut().trim();
}
catch (Throwable e)
{
setAvailable(false);
logger.error(getClass().getSimpleName() + " not available: "
+ (e.getMessage() != null ? e.getMessage() : ""));
// debug so that we can trace the issue if required
logger.debug(e);
}
}
}
else
{
Pair<Boolean, String> result = remoteTransformerClient.check(logger);
Boolean isAvailable = result.getFirst();
if (isAvailable != null && isAvailable)
{
setAvailable(true);
versionString = result.getSecond().trim();
logger.info("Using remote ImageMagick: "+versionString);
}
else
{
Pair<Boolean, String> result = remoteTransformerClient.check(logger);
Boolean isAvailable = result.getFirst();
if (isAvailable != null && isAvailable)
setAvailable(false);
versionString = "unknown";
String message = "Remote ImageMagick is not available for transformations. " + result.getSecond();
if (isAvailable == null)
{
setAvailable(true);
versionString = result.getSecond().trim();
logger.info("Using legacy local ImageMagick: " + versionString);
logger.debug(message);
}
else
{
setAvailable(false);
versionString = "unknown";
String message = "Leacy remote ImageMagick is not available for transformations. " + result.getSecond();
if (isAvailable == null)
{
logger.debug(message);
}
else
{
logger.error(message);
}
logger.error(message);
}
}
}

View File

@@ -77,8 +77,6 @@ public class AlfrescoPdfRendererContentTransformerWorker extends ContentTransfor
/** the system command executer */
private RuntimeExec executer;
private boolean enabled = true;
/** the check command executer */
private RuntimeExec checkCommand;
@@ -112,11 +110,6 @@ public class AlfrescoPdfRendererContentTransformerWorker extends ContentTransfor
this.executer = executer;
}
public void setEnabled(boolean enabled)
{
this.enabled = enabled;
}
/**
* Sets the optional remote transformer client which will be used in preference to a local command if available.
*
@@ -148,44 +141,41 @@ public class AlfrescoPdfRendererContentTransformerWorker extends ContentTransfor
@Override
public void afterPropertiesSet()
{
if (enabled)
PropertyCheck.mandatory(this, "executer", executer);
PropertyCheck.mandatory(this, "isAvailable", checkCommand);
// check availability
try
{
PropertyCheck.mandatory(this, "executer", executer);
PropertyCheck.mandatory(this, "isAvailable", checkCommand);
// check availability
try
Pair<Boolean, String> result = remoteTransformerClientConfigured()
? remoteTransformerClient.check(logger)
: remoteTransformerClient.check(checkCommand);
Boolean isAvailable = result.getFirst();
if (isAvailable != null && isAvailable)
{
Pair<Boolean, String> result = remoteTransformerClientConfigured()
? remoteTransformerClient.check(logger)
: remoteTransformerClient.check(checkCommand);
Boolean isAvailable = result.getFirst();
if (isAvailable != null && isAvailable)
versionString = result.getSecond();
setAvailable(true);
logger.info("Using remote Alfresco PDF Renderer: "+versionString);
}
else
{
setAvailable(false);
String message = "Remote Alfresco PDF Renderer is not available for transformations. " + result.getSecond();
if (isAvailable == null)
{
versionString = result.getSecond();
setAvailable(true);
logger.info("Using legacy local Alfresco PDF Renderer: " + versionString);
logger.debug(message);
}
else
{
setAvailable(false);
String message = "Legacy local Alfresco PDF Renderer is not available for transformations. " + result.getSecond();
if (isAvailable == null)
{
logger.debug(message);
}
else
{
logger.error(message);
}
logger.error(message);
}
}
catch (Throwable e)
{
setAvailable(false);
logger.error("Remote Alfresco PDF Renderer is not available: " + (e.getMessage() != null ? e.getMessage() : ""));
// debug so that we can trace the issue if required
logger.debug(e);
}
}
catch (Throwable e)
{
setAvailable(false);
logger.error("Remote Alfresco PDF Renderer is not available: " + (e.getMessage() != null ? e.getMessage() : ""));
// debug so that we can trace the issue if required
logger.debug(e);
}
}

View File

@@ -25,28 +25,30 @@
*/
package org.alfresco.repo.rendition2;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.util.PropertyCheck;
import org.springframework.beans.factory.InitializingBean;
/**
* Repeats quick file rendition tests with local transforms disabled but legacy transformers enabled.
* The Transform Service does not exist for the Community edition.
* Should be the same result as with local transforms.
* Contains common code used in TransformClients.
*
* @author adavis
*/
public class LegacyRenditionTest extends AbstractRenditionTest
public abstract class AbstractTransformClient implements InitializingBean
{
@BeforeClass
public static void before()
protected NodeService nodeService;
public void setNodeService(NodeService nodeService)
{
AbstractRenditionIntegrationTest.before();
legacy();
this.nodeService = nodeService;
}
@AfterClass
public static void after()
@Override
public void afterPropertiesSet() throws Exception
{
AbstractRenditionIntegrationTest.after();
PropertyCheck.mandatory(this, "nodeService", nodeService);
}
}

View File

@@ -37,7 +37,6 @@ import org.alfresco.service.transaction.TransactionService;
import org.alfresco.util.PropertyCheck;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import java.io.InputStream;
import java.util.Map;
@@ -53,9 +52,9 @@ import java.util.concurrent.Executors;
* @author adavis
*/
@Deprecated
public class LegacyTransformClient implements TransformClient, InitializingBean
public class LegacyLocalTransformClient extends AbstractTransformClient implements TransformClient
{
private static Log logger = LogFactory.getLog(LegacyTransformClient.class);
private static Log logger = LogFactory.getLog(LegacyLocalTransformClient.class);
private TransactionService transactionService;
@@ -95,7 +94,7 @@ public class LegacyTransformClient implements TransformClient, InitializingBean
@Override
public void afterPropertiesSet() throws Exception
{
PropertyCheck.mandatory(this, "transactionService", transactionService);
super.afterPropertiesSet();
PropertyCheck.mandatory(this, "contentService", contentService);
PropertyCheck.mandatory(this, "renditionService2", renditionService2);
PropertyCheck.mandatory(this, "converter", converter);
@@ -118,13 +117,13 @@ public class LegacyTransformClient implements TransformClient, InitializingBean
ContentTransformer transformer = contentService.getTransformer(contentUrl, sourceMimetype, size, targetMimetype, transformationOptions);
if (transformer == null)
{
String message = "Unsupported rendition " + renditionName + " from " + sourceMimetype + " size: " + size + " using legacy transform";
String message = "Unsupported rendition " + renditionName + " from " + sourceMimetype + " size: " + size;
logger.debug(message);
throw new UnsupportedOperationException(message);
}
if (logger.isDebugEnabled())
{
logger.debug("Rendition of " + renditionName + " from " + sourceMimetype + " will use legacy transform " + transformer.getName());
logger.debug("Rendition of " + renditionName + " from " + sourceMimetype + " will use " + transformer.getName());
}
}
@@ -145,7 +144,7 @@ public class LegacyTransformClient implements TransformClient, InitializingBean
TransformationOptions transformationOptions = converter.getTransformationOptions(renditionName, options);
transformationOptions.setSourceNodeRef(sourceNodeRef);
ContentReader reader = LegacyTransformClient.this.contentService.getReader(sourceNodeRef, ContentModel.PROP_CONTENT);
ContentReader reader = LegacyLocalTransformClient.this.contentService.getReader(sourceNodeRef, ContentModel.PROP_CONTENT);
if (null == reader || !reader.exists())
{
throw new IllegalArgumentException("The supplied sourceNodeRef "+sourceNodeRef+" has no content.");

View File

@@ -41,7 +41,7 @@ import java.util.Map;
* @author adavis
*/
@Deprecated
public class LegacyTransformServiceRegistry extends AbstractTransformServiceRegistry implements InitializingBean
public class LegacyLocalTransformServiceRegistry extends AbstractTransformServiceRegistry implements InitializingBean
{
private ContentService contentService;
private TransformationOptionsConverter converter;
@@ -85,21 +85,14 @@ public class LegacyTransformServiceRegistry extends AbstractTransformServiceRegi
if (firstTime)
{
firstTime = false;
transformerDebug.debug("Legacy transforms are " + (enabled ? "enabled" : "disabled"));
transformerDebug.debug("Local legacy transformers are " + (enabled ? "enabled" : "disabled"));
}
long maxSize = 0;
if (enabled)
{
try
{
TransformationOptions transformationOptions = converter.getTransformationOptions(renditionName, options);
maxSize = contentService.getMaxSourceSizeBytes(sourceMimetype, targetMimetype, transformationOptions);
}
catch (IllegalArgumentException ignore)
{
// Typically if the mimetype is invalid.
}
TransformationOptions transformationOptions = converter.getTransformationOptions(renditionName, options);
maxSize = contentService.getMaxSourceSizeBytes(sourceMimetype, targetMimetype, transformationOptions);
}
return maxSize;
}

View File

@@ -1,177 +0,0 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2019 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* 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 <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.rendition2;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.content.transform.LocalTransformer;
import org.alfresco.repo.content.transform.LocalTransformServiceRegistry;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
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.NodeRef;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.util.PropertyCheck;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import java.io.InputStream;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Requests rendition transforms take place using transforms available on the local machine (based on
* {@link LocalTransformer}. The transform and consumption of the
* resulting content is linked into a single operation that will take place at some point in the future on the local
* machine.
*
* @author adavis
*/
public class LocalTransformClient implements TransformClient, InitializingBean
{
private static Log logger = LogFactory.getLog(LocalTransformClient.class);
private LocalTransformServiceRegistry localTransformServiceRegistry;
private TransactionService transactionService;
private ContentService contentService;
private RenditionService2Impl renditionService2;
private ExecutorService executorService;
public void setLocalTransformServiceRegistry(LocalTransformServiceRegistry localTransformServiceRegistry)
{
this.localTransformServiceRegistry = localTransformServiceRegistry;
}
public void setTransactionService(TransactionService transactionService)
{
this.transactionService = transactionService;
}
public void setContentService(ContentService contentService)
{
this.contentService = contentService;
}
public void setRenditionService2(RenditionService2Impl renditionService2)
{
this.renditionService2 = renditionService2;
}
public void setExecutorService(ExecutorService executorService)
{
this.executorService = executorService;
}
@Override
public void afterPropertiesSet() throws Exception
{
PropertyCheck.mandatory(this, "localTransformServiceRegistry", localTransformServiceRegistry);
PropertyCheck.mandatory(this, "transactionService", transactionService);
PropertyCheck.mandatory(this, "contentService", contentService);
PropertyCheck.mandatory(this, "renditionService2", renditionService2);
if (executorService == null)
{
executorService = Executors.newCachedThreadPool();
}
}
@Override
public void checkSupported(NodeRef sourceNodeRef, RenditionDefinition2 renditionDefinition, String sourceMimetype, long size, String contentUrl)
{
String targetMimetype = renditionDefinition.getTargetMimetype();
String renditionName = renditionDefinition.getRenditionName();
Map<String, String> options = renditionDefinition.getTransformOptions();
if (!localTransformServiceRegistry.isSupported(sourceMimetype, size, targetMimetype, options, renditionName))
{
String message = "Unsupported rendition " + renditionName + " from " + sourceMimetype + " size: " + size + " using local transforms";
logger.debug(message);
throw new UnsupportedOperationException(message);
}
if (logger.isDebugEnabled())
{
logger.debug("Rendition of " + renditionName + " from " + sourceMimetype + " will use local transforms");
}
}
@Override
public void transform(NodeRef sourceNodeRef, RenditionDefinition2 renditionDefinition, String user, int sourceContentHashCode)
{
executorService.submit(() ->
{
AuthenticationUtil.runAs((AuthenticationUtil.RunAsWork<Void>) () ->
transactionService.getRetryingTransactionHelper().doInTransaction(() ->
{
try
{
String targetMimetype = renditionDefinition.getTargetMimetype();
String renditionName = renditionDefinition.getRenditionName();
Map<String, String> options = renditionDefinition.getTransformOptions();
ContentReader reader = contentService.getReader(sourceNodeRef, ContentModel.PROP_CONTENT);
if (null == reader || !reader.exists())
{
throw new IllegalArgumentException("The supplied sourceNodeRef "+sourceNodeRef+" has no content.");
}
ContentWriter writer = contentService.getTempWriter();
writer.setMimetype(targetMimetype);
if (logger.isDebugEnabled())
{
logger.debug("Local transform requested for rendition of " + renditionDefinition.getRenditionName());
}
localTransformServiceRegistry.transform(reader, writer, options, renditionName, sourceNodeRef);
InputStream inputStream = writer.getReader().getContentInputStream();
if (logger.isDebugEnabled())
{
logger.debug("Local transform to be consumed for rendition of " + renditionDefinition.getRenditionName());
}
renditionService2.consume(sourceNodeRef, inputStream, renditionDefinition, sourceContentHashCode);
if (logger.isDebugEnabled())
{
logger.debug("Local transform consumed for rendition of " + renditionDefinition.getRenditionName());
}
}
catch (Exception e)
{
if (logger.isDebugEnabled())
{
String renditionName = renditionDefinition.getRenditionName();
logger.error("Rendition of "+renditionName+" failed", e);
}
renditionService2.failure(sourceNodeRef, renditionDefinition, sourceContentHashCode);
throw e;
}
return null;
}), user);
});
}
}

View File

@@ -49,18 +49,16 @@ public class RenditionDefinitionRegistry2Impl implements RenditionDefinitionRegi
public void setTransformServiceRegistry(TransformServiceRegistry transformServiceRegistry)
{
this.transformServiceRegistry = transformServiceRegistry;
renditionsFor.clear();
}
/**
* Obtains a {@link RenditionDefinition2} by name.
* @param renditionName to be returned
* @return the {@link RenditionDefinition2} or null if not registered.
* @deprecated use {@link #getRenditionDefinition(String)}
*/
public RenditionDefinition2 getDefinition(String renditionName)
{
return getRenditionDefinition(renditionName);
return renditionDefinitions.get(renditionName);
}
public void register(RenditionDefinition2 renditionDefinition)

View File

@@ -38,7 +38,7 @@ public class SwitchingTransformClient implements TransformClient
{
private final TransformClient primary;
private final TransformClient secondary;
private ThreadLocal<Boolean> usePrimary = ThreadLocal.withInitial(()->Boolean.FALSE);
private ThreadLocal<Boolean> usePrimary = new ThreadLocal<>();
public SwitchingTransformClient(TransformClient primary, TransformClient secondary)
{

View File

@@ -166,7 +166,6 @@ public class ThumbnailRegistry implements ApplicationContextAware, ApplicationLi
public void setTransformServiceRegistry(TransformServiceRegistry transformServiceRegistry)
{
this.transformServiceRegistry = transformServiceRegistry;
mimetypeMap.clear();
}
public void setRenditionDefinitionRegistry2(RenditionDefinitionRegistry2 renditionDefinitionRegistry2)

View File

@@ -2,7 +2,7 @@
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2019 Alfresco Software Limited
* Copyright (C) 2005 - 2018 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
@@ -26,21 +26,10 @@
package org.alfresco.transform.client.model.config;
/**
* Abstract implementation of TransformOption.
* Helper class to be supplied by the client to map file extensions to mimetypes, so the json description of what
* is supported by the Transform Service includes file extensions rather than mmetypes, so is more readable.
*/
public abstract class AbstractTransformOption implements TransformOption
public interface ExtensionMap
{
private boolean required;
@Override
public boolean isRequired()
{
return required;
}
@Override
public void setRequired(boolean required)
{
this.required = required;
}
String toMimetype(String extension);
}

View File

@@ -1,273 +0,0 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2019 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* 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 <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.transform.client.model.config;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.apache.commons.logging.Log;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
/**
* This class recreates the json format used in ACS 6.1 where we just had an array of transformers and each
* transformer has a list of transform options. The idea of this code is that it replaces the references with the
* actual transform options that have been separated out into their own section.<p>
*
* The T-Router and T-Engines return the format with the transform option separated into their own section. Pipeline
* definitions used by the LocalTransformServiceRegistry may use transform reference options defined in the json
* returned by T-Engines. with the actual definitions from the transform options
* reference section. It also combines multiple json sources into a single jsonNode structure that can be parsed as
* before.
*/
public class JsonConverter
{
public static final String NAME = "name";
private final Log log;
private static final String TRANSFORM_OPTIONS = "transformOptions";
private static final String GROUP = "group";
private static final String TRANSFORMERS = "transformers";
private Map<String, ArrayNode> allTransformOptions = new HashMap<>();
private List<ObjectNode> allTransforms = new ArrayList<>();
private ObjectMapper jsonObjectMapper = new ObjectMapper();
JsonConverter(Log log)
{
this.log = log;
}
void addJsonSource(String path) throws IOException
{
final File jarFile = new File(getClass().getProtectionDomain().getCodeSource().getLocation().getPath());
if (jarFile.isFile())
{
JarFile jar = new JarFile(jarFile);
Enumeration<JarEntry> entries = jar.entries(); //gives ALL entries in jar
String prefix = path + "/";
List<String> names = new ArrayList<>();
while (entries.hasMoreElements())
{
final String name = entries.nextElement().getName();
if (name.startsWith(prefix) && name.length() > prefix.length())
{
names.add(name);
}
}
Collections.sort(names);
for (String name : names)
{
log.debug("Reading resource "+name);
addJsonSource(new InputStreamReader(getResourceAsStream(name)));
}
jar.close();
}
else
{
URL url = getClass().getClassLoader().getResource(path);
if (url != null)
{
File root = new File(url.getPath());
if (root.isDirectory())
{
File[] files = root.listFiles();
Arrays.sort(files, (file1, file2) -> file1.getName().compareTo(file2.getName()));
for (File file: files)
{
log.debug("Reading dir file "+file.getPath());
addJsonSource(new FileReader(file));
}
}
else
{
log.debug("Reading file "+root.getPath());
addJsonSource(new FileReader(root));
}
}
}
}
private InputStream getResourceAsStream(String resource)
{
final InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(resource);
return in == null ? getClass().getResourceAsStream(resource) : in;
}
private void addJsonSource(Reader reader) throws IOException
{
JsonNode jsonNode = jsonObjectMapper.readValue(reader, new TypeReference<JsonNode>() {});
JsonNode transformOptions = jsonNode.get(TRANSFORM_OPTIONS);
if (transformOptions != null && transformOptions.isObject())
{
Iterator<Map.Entry<String, JsonNode>> iterator = transformOptions.fields();
while (iterator.hasNext())
{
Map.Entry<String, JsonNode> entry = iterator.next();
JsonNode options = entry.getValue();
if (options.isArray())
{
String optionsName = entry.getKey();
allTransformOptions.put(optionsName, (ArrayNode)options);
}
}
}
JsonNode transformers = jsonNode.get(TRANSFORMERS);
if (transformers != null && transformers.isArray())
{
for (JsonNode transformer : transformers)
{
if (transformer.isObject())
{
allTransforms.add((ObjectNode)transformer);
}
}
}
}
public List<Transformer> getTransformers() throws IOException
{
List<Transformer> transformers = new ArrayList<>();
// After all json input has been loaded build the output with the options in place.
ArrayNode transformersNode = jsonObjectMapper.createArrayNode();
for (ObjectNode transform : allTransforms)
{
try
{
ArrayNode transformOptions = (ArrayNode) transform.get(TRANSFORM_OPTIONS);
if (transformOptions != null)
{
ArrayNode options;
int size = transformOptions.size();
if (size == 1)
{
// If there is a single transform option reference, we can just use it.
int i = 0;
options = getTransformOptions(transformOptions, i, transform);
}
else
{
// If there are many transform option references (typically in a pipeline), then each element
// has a group for each set of transform options.
options = jsonObjectMapper.createArrayNode();
for (int i = size - 1; i >= 0; i--)
{
JsonNode referencedTransformOptions = getTransformOptions(transformOptions, i, transform);
if (referencedTransformOptions != null)
{
ObjectNode element = jsonObjectMapper.createObjectNode();
options.add(element);
ObjectNode group = jsonObjectMapper.createObjectNode();
group.set(TRANSFORM_OPTIONS, referencedTransformOptions);
element.set(GROUP, group);
}
}
}
if (options == null || options.size() == 0)
{
transform.remove(TRANSFORM_OPTIONS);
}
else
{
transform.set(TRANSFORM_OPTIONS, options);
}
}
try
{
Transformer transformer = jsonObjectMapper.convertValue(transform, Transformer.class);
transformers.add(transformer);
}
catch (IllegalArgumentException e)
{
log.error("Invalid transformer "+getTransformName(transform)+" "+e.getMessage());
}
transformersNode.add(transform);
}
catch (IllegalArgumentException e)
{
String transformString = jsonObjectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(transform);
log.error(e.getMessage()+"\n"+ transformString);
}
}
return transformers;
}
private ArrayNode getTransformOptions(ArrayNode transformOptions, int i, ObjectNode transform)
{
ArrayNode options = null;
JsonNode optionName = transformOptions.get(i);
if (optionName.isTextual())
{
String name = optionName.asText();
options = allTransformOptions.get(name);
if (options == null)
{
String message = "Reference to \"transformOptions\": \"" + name + "\" not found. Transformer " +
getTransformName(transform) + " ignored.";
throw new IllegalArgumentException(message);
}
}
return options;
}
private String getTransformName(ObjectNode transform)
{
String name = "Unknown";
JsonNode nameNode = transform.get(NAME);
if (nameNode.isTextual())
{
name = '"'+nameNode.asText()+'"';
}
return name;
}
}

View File

@@ -2,7 +2,7 @@
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2019 Alfresco Software Limited
* Copyright (C) 2005 - 2018 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
@@ -31,36 +31,29 @@ package org.alfresco.transform.client.model.config;
*/
public class SupportedSourceAndTarget
{
private String sourceMediaType;
private String sourceExt;
private long maxSourceSizeBytes = -1;
private String targetMediaType;
private int priority = 50;
private String targetExt;
public SupportedSourceAndTarget()
{
}
public SupportedSourceAndTarget(String sourceMediaType, String targetMediaType, long maxSourceSizeBytes)
public SupportedSourceAndTarget(String sourceExt, String targetExt, long maxSourceSizeBytes)
{
this(sourceMediaType, targetMediaType, maxSourceSizeBytes, 50);
}
public SupportedSourceAndTarget(String sourceMediaType, String targetMediaType, long maxSourceSizeBytes, int priority)
{
setSourceMediaType(sourceMediaType);
setSourceExt(sourceExt);
setMaxSourceSizeBytes(maxSourceSizeBytes);
setTargetMediaType(targetMediaType);
setPriority(priority);
setTargetExt(targetExt);
}
public String getSourceMediaType()
public String getSourceExt()
{
return sourceMediaType;
return sourceExt;
}
public void setSourceMediaType(String sourceMediaType)
public void setSourceExt(String sourceExt)
{
this.sourceMediaType = sourceMediaType;
this.sourceExt = sourceExt;
}
public long getMaxSourceSizeBytes()
@@ -73,23 +66,13 @@ public class SupportedSourceAndTarget
this.maxSourceSizeBytes = maxSourceSizeBytes;
}
public String getTargetMediaType()
public String getTargetExt()
{
return targetMediaType;
return targetExt;
}
public void setTargetMediaType(String targetMediaType)
public void setTargetExt(String targetExt)
{
this.targetMediaType = targetMediaType;
}
public int getPriority()
{
return priority;
}
public void setPriority(int priority)
{
this.priority = priority;
this.targetExt = targetExt;
}
}

View File

@@ -29,12 +29,12 @@ import java.util.ArrayList;
import java.util.List;
/**
* Helper class that builds a {@link Transformer} given the source and target types and a pipeline of Transformers
* for creating intermediary content.
* Helper class that builds a {@link Transformer} given the source and target extensions and a pipeline of Transformers
* for creating intermediary content, or a set of failover transformers.
*/
public class TransformBuilder
{
public Transformer buildPipeLine(String name, List<SupportedSourceAndTarget> sourceAndTargetList,
public Transformer buildPipeLine(String name, String version, List<SupportedSourceAndTarget> sourceAndTargetList,
List<ChildTransformer> transformerList)
{
List<TransformOption> options = new ArrayList<>(transformerList.size());
@@ -47,6 +47,13 @@ public class TransformBuilder
options.add(new TransformOptionGroup(t.isRequired(), t.getTransformer().getTransformOptions()));
}
});
return new Transformer(name, options, sourceAndTargetList);
return new Transformer(name, version, options, sourceAndTargetList);
}
// TODO Commented out for now as it is unclear what the Transform service will support in terms of failover transformations.
// Note: The use of a list of Transformers rather than ChildTransformers, as the supplied actual options would have
// to match one or more of the transformer's options. Matching one or more options is not currently
// implemented by the TransformServiceRegistry
// public Transformer buildFailover(String name, String version, List<SupportedSourceAndTarget> sourceAndTargetList,
// List<Transformer> transformerList)
}

View File

@@ -2,7 +2,7 @@
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2019 Alfresco Software Limited
* Copyright (C) 2005 - 2018 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of

View File

@@ -30,12 +30,11 @@ import java.util.List;
/**
* Represents a group of one or more options. If the group is optional, child options that are marked as required are
* only required if any child in the group is supplied by the client. If the group is required, child options are
* optional or required based on their own setting alone.
*
* In a pipeline transformation, a group of options
* optional or required based on their own setting alone. The top
*/
public class TransformOptionGroup extends AbstractTransformOption
public class TransformOptionGroup implements TransformOption
{
private boolean required;
List<TransformOption> transformOptions;
public TransformOptionGroup()
@@ -48,6 +47,18 @@ public class TransformOptionGroup extends AbstractTransformOption
setTransformOptions(transformOptions);
}
@Override
public boolean isRequired()
{
return required;
}
@Override
public void setRequired(boolean required)
{
this.required = required;
}
public List<TransformOption> getTransformOptions()
{
return transformOptions;

View File

@@ -28,8 +28,9 @@ package org.alfresco.transform.client.model.config;
/**
* Represents a single transformation option.
*/
public class TransformOptionValue extends AbstractTransformOption
public class TransformOptionValue implements TransformOption
{
private boolean required;
private String name;
public TransformOptionValue()
@@ -42,6 +43,18 @@ public class TransformOptionValue extends AbstractTransformOption
setName(name);
}
@Override
public boolean isRequired()
{
return required;
}
@Override
public void setRequired(boolean required)
{
this.required = required;
}
public String getName()
{
return name;

View File

@@ -27,7 +27,6 @@ package org.alfresco.transform.client.model.config;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.logging.Log;
import org.springframework.beans.factory.InitializingBean;
import java.io.IOException;
@@ -45,36 +44,38 @@ import static org.alfresco.repo.rendition2.RenditionDefinition2.TIMEOUT;
/**
* Used by clients to work out if a transformation is supported by the Transform Service.
*/
public abstract class TransformServiceRegistryImpl implements TransformServiceRegistry, InitializingBean
public class TransformServiceRegistryImpl implements TransformServiceRegistry, InitializingBean
{
class SupportedTransform
{
TransformOptionGroup transformOptions;
long maxSourceSizeBytes;
private String name;
private int priority;
private long maxSourceSizeBytes;
public SupportedTransform(String name, List<TransformOption> transformOptions, long maxSourceSizeBytes, int priority)
public SupportedTransform(List<TransformOption> transformOptions, long maxSourceSizeBytes)
{
// Logically the top level TransformOptionGroup is required, so that child options are optional or required
// based on their own setting.
this.transformOptions = new TransformOptionGroup(true, transformOptions);
this.maxSourceSizeBytes = maxSourceSizeBytes;
this.name = name;
this.priority = priority;
}
}
private ObjectMapper jsonObjectMapper;
private ExtensionMap extensionMap;
ConcurrentMap<String, ConcurrentMap<String, List<SupportedTransform>>> transformers = new ConcurrentHashMap<>();
ConcurrentMap<String, ConcurrentMap<String, List<SupportedTransform>>> cachedSupportedTransformList = new ConcurrentHashMap<>();
ConcurrentMap<String, ConcurrentMap<String, Long>> cachedMaxSizes = new ConcurrentHashMap<>();
public void setJsonObjectMapper(ObjectMapper jsonObjectMapper)
{
this.jsonObjectMapper = jsonObjectMapper;
}
public void setExtensionMap(ExtensionMap extensionMap)
{
this.extensionMap = extensionMap;
}
@Override
public void afterPropertiesSet() throws Exception
{
@@ -82,21 +83,30 @@ public abstract class TransformServiceRegistryImpl implements TransformServiceRe
{
throw new IllegalStateException("jsonObjectMapper has not been set");
}
cachedSupportedTransformList.clear();
transformers.clear();
if (extensionMap == null)
{
throw new IllegalStateException("extensionMap has not been set");
}
}
protected abstract Log getLog();
public void register(String path) throws IOException
private String toMimetype(String ext)
{
JsonConverter jsonConverter = new JsonConverter(getLog());
jsonConverter.addJsonSource(path);
List<Transformer> transformers = jsonConverter.getTransformers();
for (Transformer transformer : transformers)
String mimetype = extensionMap.toMimetype(ext);
if (mimetype == null)
{
register(transformer);
throw new IllegalArgumentException("The mimetype for the file extension "+ext+" cannot be looked up by: "+
extensionMap.getClass().getName());
}
return mimetype;
}
public void register(Transformer transformer)
{
transformer.getSupportedSourceAndTargetList().forEach(
e -> transformers.computeIfAbsent(toMimetype(e.getSourceExt()),
k -> new ConcurrentHashMap<>()).computeIfAbsent(toMimetype(e.getTargetExt()),
k -> new ArrayList<>()).add(
new SupportedTransform(transformer.getTransformOptions(), e.getMaxSourceSizeBytes())));
}
public void register(Reader reader) throws IOException
@@ -105,78 +115,31 @@ public abstract class TransformServiceRegistryImpl implements TransformServiceRe
transformers.forEach(t -> register(t));
}
public void register(Transformer transformer)
{
transformer.getSupportedSourceAndTargetList().forEach(
e -> transformers.computeIfAbsent(e.getSourceMediaType(),
k -> new ConcurrentHashMap<>()).computeIfAbsent(e.getTargetMediaType(),
k -> new ArrayList<>()).add(
new SupportedTransform(transformer.getTransformerName(),
transformer.getTransformOptions(), e.getMaxSourceSizeBytes(), e.getPriority())));
}
@Override
public boolean isSupported(String sourceMimetype, long sourceSizeInBytes, String targetMimetype,
Map<String, String> actualOptions, String renditionName)
Map<String, String> actualOptions, String transformName)
{
long maxSize = getMaxSize(sourceMimetype, targetMimetype, actualOptions, renditionName);
long maxSize = getMaxSize(sourceMimetype, targetMimetype, actualOptions, transformName);
return maxSize != 0 && (maxSize == -1L || maxSize >= sourceSizeInBytes);
}
/**
* Works out the name of the transformer (might not map to an actual transformer) that will be used to transform
* content of a given source mimetype and size into a target mimetype given a list of actual transform option names
* and values (Strings) plus the data contained in the {@Transform} objects registered with this class.
* @param sourceMimetype the mimetype of the source content
* @param sourceSizeInBytes the size in bytes of the source content. Ignored if negative.
* @param targetMimetype the mimetype of the target
* @param actualOptions the actual name value pairs available that could be passed to the Transform Service.
* @param renditionName (optional) name for the set of options and target mimetype. If supplied is used to cache
* results to avoid having to work out if a given transformation is supported a second time.
* The sourceMimetype and sourceSizeInBytes may still change. In the case of ACS this is the
* rendition name.
*/
protected String getTransformerName(String sourceMimetype, long sourceSizeInBytes, String targetMimetype, Map<String, String> actualOptions, String renditionName)
{
List<SupportedTransform> supportedTransforms = getTransformListBySize(sourceMimetype, targetMimetype, actualOptions, renditionName);
for (SupportedTransform supportedTransform : supportedTransforms)
{
if (supportedTransform.maxSourceSizeBytes == -1 || supportedTransform.maxSourceSizeBytes >= sourceSizeInBytes)
{
return supportedTransform.name;
}
}
return null;
}
@Override
public long getMaxSize(String sourceMimetype, String targetMimetype,
Map<String, String> actualOptions, String renditionName)
{
List<SupportedTransform> supportedTransforms = getTransformListBySize(sourceMimetype, targetMimetype, actualOptions, renditionName);
return supportedTransforms.isEmpty() ? 0 : supportedTransforms.get(supportedTransforms.size()-1).maxSourceSizeBytes;
}
// Returns transformers in increasing supported size order, where lower priority transformers for the same size have
// been discarded.
private List<SupportedTransform> getTransformListBySize(String sourceMimetype, String targetMimetype,
Map<String, String> actualOptions, String renditionName)
Map<String, String> actualOptions, String transformName)
{
if (actualOptions == null)
{
actualOptions = Collections.EMPTY_MAP;
}
if (renditionName != null && renditionName.trim().isEmpty())
if (transformName != null && transformName.trim().isEmpty())
{
renditionName = null;
transformName = null;
}
List<SupportedTransform> transformListBySize = renditionName == null ? null
: cachedSupportedTransformList.computeIfAbsent(renditionName, k -> new ConcurrentHashMap<>()).get(sourceMimetype);
if (transformListBySize != null)
Long maxSize = transformName == null ? null : cachedMaxSizes.computeIfAbsent(transformName, k -> new ConcurrentHashMap<>()).get(sourceMimetype);
if (maxSize != null)
{
return transformListBySize;
return maxSize.longValue();
}
// Remove the "timeout" property from the actualOptions as it is not used to select a transformer.
@@ -186,7 +149,7 @@ public abstract class TransformServiceRegistryImpl implements TransformServiceRe
actualOptions.remove(TIMEOUT);
}
transformListBySize = new ArrayList<>();
long calculatedMaxSize = 0;
ConcurrentMap<String, List<SupportedTransform>> targetMap = transformers.get(sourceMimetype);
if (targetMap != null)
{
@@ -200,66 +163,24 @@ public abstract class TransformServiceRegistryImpl implements TransformServiceRe
addToPossibleTransformOptions(possibleTransformOptions, transformOptions, true, actualOptions);
if (isSupported(possibleTransformOptions, actualOptions))
{
addToSupportedTransformList(transformListBySize, supportedTransform);
if (supportedTransform.maxSourceSizeBytes < 0)
{
calculatedMaxSize = -1;
break;
}
calculatedMaxSize = Math.max(calculatedMaxSize, supportedTransform.maxSourceSizeBytes);
}
}
}
}
if (renditionName != null)
if (transformName != null)
{
cachedSupportedTransformList.get(renditionName).put(sourceMimetype, transformListBySize);
cachedMaxSizes.get(transformName).put(sourceMimetype, calculatedMaxSize);
}
return transformListBySize;
}
// Add newTransform to the transformListBySize in increasing size order and discards lower priority (numerically
// higher) transforms with a smaller or equal size.
private void addToSupportedTransformList(List<SupportedTransform> transformListBySize, SupportedTransform newTransform)
{
for (int i=0; i < transformListBySize.size(); i++)
{
SupportedTransform existingTransform = transformListBySize.get(i);
int added = -1;
int compare = compare(newTransform.maxSourceSizeBytes, existingTransform.maxSourceSizeBytes);
if (compare < 0)
{
transformListBySize.add(i, newTransform);
added = i;
}
else if (compare == 0)
{
if (newTransform.priority < existingTransform.priority)
{
transformListBySize.set(i, newTransform);
added = i;
}
}
if (added == i)
{
for (i--; i >= 0; i--)
{
existingTransform = transformListBySize.get(i);
if (newTransform.priority <= existingTransform.priority)
{
transformListBySize.remove(i);
}
}
return;
}
}
transformListBySize.add(newTransform);
}
// compare where -1 is unlimited.
private int compare(long a, long b)
{
return a == -1
? b == -1 ? 0 : 1
: b == -1 ? -1
: a == b ? 0
: a > b ? 1 : -1;
return calculatedMaxSize;
}
/**

View File

@@ -1,66 +0,0 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2019 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* 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 <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.transform.client.model.config;
/**
* Represents a single transform step in a transform pipeline. The last step in the pipeline does not specify the
* target type as that is based on the supported types and what has been requested.
*/
public class TransformStep
{
private String transformerName;
private String targetMediaType;
public TransformStep()
{
}
public TransformStep(String transformerName, String targetMediaType)
{
setTransformerName(transformerName);
setTargetMediaType(targetMediaType);
}
public String getTransformerName()
{
return transformerName;
}
public void setTransformerName(String transformerName)
{
this.transformerName = transformerName;
}
public String getTargetMediaType()
{
return targetMediaType;
}
public void setTargetMediaType(String targetMediaType)
{
this.targetMediaType = targetMediaType;
}
}

View File

@@ -2,7 +2,7 @@
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2019 Alfresco Software Limited
* Copyright (C) 2005 - 2018 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
@@ -26,34 +26,28 @@
package org.alfresco.transform.client.model.config;
import java.util.List;
import org.alfresco.transform.client.model.config.TransformServiceRegistry;
import java.util.Objects;
/**
* Represents a set of transformations supported by the Transform Service or Local Transform Service Registry that
* share the same transform options. Each may be an actual transformer or a pipeline of multiple transformers. It is
* possible that more than one transformer may able to perform a transformation from one mimetype to another. The actual
* selection of transformer is up to the Transform Service or Local Transform Service Registry to decide. Clients may
* use {@link TransformServiceRegistry#isSupported(String, long, String, java.util.Map, String)} to decide
* Represents a set of transformations supported by the Transform Service that share the same transform options. Each
* may be an actual transformer or the amalgamation of multiple transformers. It is possible that more than one
* transformer may able to perform a transformation from one mimetype to another. The actual selection of transformer
* is up to the Transform Service to decide. Clients may use {@link TransformServiceRegistry#isSupported} to decide
* if they should send a request to the Transform Service. As a result clients have a simple generic view of
* transformations which allows new transformations to be added without the need to change client data structures other
* transformations which allows new transformations to be added without the need change client data structures other
* than to define new name value pairs. For this to work the Transform Service defines unique names for each option.
* <ul>
* <li>transformerName - is optional but if supplied should be unique. The client should infer nothing from the name
* as it is simply a label, but the Local Transform Service Registry will use the name in pipelines.</lI>
* <lI>name - is unique. The client should infer nothing from the name as it is simply a label.</lI>
* <li>version - of the transformer. The client should infer nothing from the value and should only use it
* in messages. There should only be one version supplied to the client for each name.</li>
* <li>transformOptions - a grouping of individual transformer transformOptions. The group may be optional and may
* contain nested transformOptions.</li>
* </ul>
* For local transforms, this structure is extended when defining a pipeline transform.
* <ul>
* <li>transformerPipeline - an array of pairs of transformer name and target extension for each transformer in the
* pipeline. The last one should not have an extension as that is defined by the request and should be in the
* supported list.</li>
* </ul>
*/
public class Transformer
{
private String transformerName;
private List<TransformStep> transformerPipeline;
private String name;
private String version;
private List<TransformOption> transformOptions;
private List<SupportedSourceAndTarget> supportedSourceAndTargetList;
@@ -61,37 +55,32 @@ public class Transformer
{
}
public Transformer(String transformerName, List<TransformOption> transformOptions, List<SupportedSourceAndTarget> supportedSourceAndTargetList)
public Transformer(String name, String version, List<TransformOption> transformOptions, List<SupportedSourceAndTarget> supportedSourceAndTargetList)
{
setTransformerName(transformerName);
setName(name);
setVersion(version);
setTransformOptions(transformOptions);
setSupportedSourceAndTargetList(supportedSourceAndTargetList);
}
public Transformer(String transformerName, List<TransformStep> transformerPipeline, List<TransformOption> transformOptions, List<SupportedSourceAndTarget> supportedSourceAndTargetList)
public String getName()
{
this(transformerName, transformOptions, supportedSourceAndTargetList);
setTransformerPipeline(transformerPipeline);
return name;
}
public String getTransformerName()
public void setName(String name)
{
return transformerName;
this.name = name;
}
public void setTransformerName(String transformerName)
public String getVersion()
{
this.transformerName = transformerName;
return version;
}
public List<TransformStep> getTransformerPipeline()
public void setVersion(String version)
{
return transformerPipeline;
}
public void setTransformerPipeline(List<TransformStep> transformerPipeline)
{
this.transformerPipeline = transformerPipeline;
this.version = version;
}
public List<TransformOption> getTransformOptions()

View File

@@ -328,18 +328,33 @@
<constructor-arg>
<ref bean="transformerSelector"/>
</constructor-arg>
<property name="enabled" value="${legacy.transform.service.enabled}" />
<property name="enabled" value="${local.transform.service.enabled}" />
<property name="transformerDebug" ref="transformerDebug" />
</bean>
<!-- Transformation Debug -->
<bean id="transformerDebug" class="org.alfresco.repo.content.transform.TransformerDebug">
<property name="nodeService" ref="nodeService" />
<property name="mimetypeService" ref="mimetypeService" />
<property name="transformerRegistry" ref="contentTransformerRegistry" />
<property name="transformerConfig" ref="transformerConfig" />
<property name="transformerLog" ref="transformerLog" />
<property name="transformerDebugLog" ref="transformerDebugLog" />
<bean id="transformerDebug" class="org.alfresco.repo.content.transform.TransformerDebug">
<constructor-arg>
<ref bean="nodeService"/>
</constructor-arg>
<constructor-arg>
<ref bean="mimetypeService"/>
</constructor-arg>
<constructor-arg>
<ref bean="contentTransformerRegistry"/>
</constructor-arg>
<constructor-arg>
<ref bean="transformerConfig"/>
</constructor-arg>
<constructor-arg>
<ref bean="transformerLog" />
</constructor-arg>
<constructor-arg>
<ref bean="transformerDebugLog" />
</constructor-arg>
<property name="contentService">
<ref bean="contentService" />
</property>
</bean>
<!-- Import the transformer configuration from the transformers subsystem -->
@@ -474,7 +489,6 @@
class="org.alfresco.repo.content.transform.TikaPoweredContentTransformer"
abstract="true"
parent="baseContentTransformer">
<property name="enabled" value="${legacy.transform.service.enabled}" />
<property name="remoteTransformerClient">
<ref bean="tikaRemoteTransformerClient" />
</property>

View File

@@ -71,20 +71,9 @@
<!-- Replaced in the enterprise edition -->
<bean id="transformClient" parent="localTransformClient"/>
<bean id="localTransformClient" class="org.alfresco.repo.rendition2.SwitchingTransformClient">
<constructor-arg name="primary" ref="localTransformClientImpl" />
<constructor-arg name="secondary" ref="legacyTransformClient" />
</bean>
<bean id="localTransformClientImpl" class="org.alfresco.repo.rendition2.LocalTransformClient">
<property name="localTransformServiceRegistry" ref="localTransformServiceRegistryImpl" />
<property name="transactionService" ref="transactionService" />
<property name="contentService" ref="contentService" />
<property name="renditionService2" ref="renditionService2" />
</bean>
<bean id="legacyTransformClient" class="org.alfresco.repo.rendition2.LegacyTransformClient">
<bean id="localTransformClient" class="org.alfresco.repo.rendition2.LegacyLocalTransformClient">
<property name="transactionService" ref="transactionService" />
<property name="nodeService" ref="NodeService" />
<property name="contentService" ref="ContentService" />
<property name="renditionService2" ref="renditionService2" />
<property name="converter" ref="transformOptionsConverter" />
@@ -102,28 +91,10 @@
<!-- Replaced in the enterprise edition -->
<bean id="transformServiceRegistry" parent="localTransformServiceRegistry"/>
<bean id="localTransformServiceRegistry" class="org.alfresco.repo.rendition2.SwitchingTransformServiceRegistry">
<constructor-arg name="primary" ref="localTransformServiceRegistryImpl" />
<constructor-arg name="secondary" ref="legacyTransformServiceRegistry" />
</bean>
<bean id="localTransformServiceRegistryImpl" class="org.alfresco.repo.content.transform.LocalTransformServiceRegistry" >
<property name="jsonObjectMapper" ref="localTransformServiceRegistryJsonObjectMapper" />
<property name="pipelineConfigFolder" value="alfresco/transformers" />
<property name="enabled" value="${local.transform.service.enabled}" />
<property name="properties" ref="global-properties" />
<property name="transformerDebug" ref="transformerDebug" />
<property name="mimetypeService" ref="MimetypeService" />
<property name="strictMimeTypeCheck" value="${transformer.strict.mimetype.check}"/>
<property name="retryTransformOnDifferentMimeType" value="${content.transformer.retryOn.different.mimetype}"/>
</bean>
<bean id="localTransformServiceRegistryJsonObjectMapper" class="com.fasterxml.jackson.databind.ObjectMapper" />
<bean id="legacyTransformServiceRegistry" class="org.alfresco.repo.rendition2.LegacyTransformServiceRegistry" >
<bean id="localTransformServiceRegistry" class="org.alfresco.repo.rendition2.LegacyLocalTransformServiceRegistry" >
<property name="contentService" ref="contentService" />
<property name="converter" ref="transformOptionsConverter" />
<property name="enabled" value="${legacy.transform.service.enabled}" />
<property name="enabled" value="${local.transform.service.enabled}" />
<property name="transformerDebug" ref="transformerDebug" />
</bean>

View File

@@ -562,7 +562,7 @@ img.root=./ImageMagick
img.dyn=${img.root}/lib
img.exe=${img.root}/bin/convert
# Legacy imageMagick transformer url to T-Engine to service transform requests via http. Disabled by default.
# Remote server (or docker container) url used to service imagemagick requests.
img.url=
# When img.url is set, this value indicates the amount of time to wait after a connection failure
@@ -611,26 +611,13 @@ system.thumbnail.redeployStaticDefsOnStartup=true
# The default timeout for metadata mapping extracters
content.metadataExtracter.default.timeoutMs=20000
# Legacy tika transformer url to T-Engines to service transform requests via http. Disabled by default.
# Remote server (or docker container) url used to service tika requests.
tika.url=
# When the legacy tika transformer .url is set, this value indicates the amount of time to wait after a connection failure
# When tika.url is set, this value indicates the amount of time to wait after a connection failure
# before retrying the connection to allow a docker container to (re)start.
tika.startupRetryPeriodSeconds=60
# Local transformer urls to T-engines to service transform requests via http. Enabled by default.
localTransformer.pdfrenderer.url=http://localhost:8090/
localTransformer.imagemagick.url=http://localhost:8091/
localTransformer.libreoffice.url=http://localhost:8092/
localTransformer.tika.url=http://localhost:8093/
# When a local transformer .url is set, this value indicates the amount of time to wait after a connection failure
# before retrying the connection to allow a docker container to (re)start.
localTransformer.pdfrenderer.startupRetryPeriodSeconds=60
localTransformer.imagemagick.startupRetryPeriodSeconds=60
localTransformer.libreoffice.startupRetryPeriodSeconds=60
localTransformer.tika.startupRetryPeriodSeconds=60
#
content.metadataExtracter.pdf.maxDocumentSizeMB=10
content.metadataExtracter.pdf.maxConcurrentExtractionsCount=5
@@ -1078,9 +1065,6 @@ system.cronJob.startDelayMilliseconds=60000
# Used to disable transforms locally.
local.transform.service.enabled=true
# Used to disable transforms that extend AbstractContentTransformer2
legacy.transform.service.enabled=true
#
# Check that the declared mimetype (of the Node) is the same as the derived
# mimetype of the content (via Tika) before a transformation takes place.
@@ -1090,15 +1074,13 @@ legacy.transform.service.enabled=true
#
# There are a few issues with the Tika mimetype detection. So that transformations
# still take place where the detected mimetype is not the same as the declared mimetype,
# another property (transformer.strict.mimetype.check.whitelist.mimetypes) contains pairs
# of declared and detected mimetypes that should be allowed. This parameter value is a
# sequence of ; separated pairs. The declared and derived mimetypes are also ; separated.
# another property (transformer.strict.mimetype.check.whitelist.mimetypes in transformers.properties
# so can be changed via JMX) contains pairs of declared and detected mimetypes that should
# be allowed. This parameter value is a sequence of ; separated pairs. The declared and
# derived mimetypes are also ; separated.
#
transformer.strict.mimetype.check=true
# A white list of declared and detected mimetypes, that don't match, but should still be transformed.
transformer.strict.mimetype.check.whitelist.mimetypes=application/eps;application/postscript;application/illustrator;application/pdf;application/x-tar;application/x-gtar;application/acp;application/zip;application/vnd.stardivision.math;application/x-tika-msoffice
#
# Enable transformation retrying if the file has MIME type differ than file extension.
# Ignored if transformer.strict.mimetype.check is true as these transformations
@@ -1276,3 +1258,4 @@ messaging.subsystem.autoStart=true
# Raw events
acs.repo.rendition.events.endpoint=jms:acs-repo-rendition-events?jmsMessageType=Text

View File

@@ -53,7 +53,6 @@
<property name="mimetypeService">
<ref bean="mimetypeService" />
</property>
<property name="enabled" value="${legacy.transform.service.enabled}" />
<property name="jodConverter">
<ref bean="jodconverter.shared.instance" />
</property>

View File

@@ -61,7 +61,6 @@
</property>
</bean>
</property>
<property name="enabled" value="${legacy.transform.service.enabled}" />
</bean>
<bean id="transformer.worker.ImageMagick.processPropertiesWindows" class="org.springframework.beans.factory.config.MapFactoryBean">

View File

@@ -1,20 +1,58 @@
{
"transformOptions": {
"tikaOptions": [
[
{
"name": "libreOffice",
"version": "1",
"supportedSourceAndTargetList": [
{"sourceExt": "doc", "targetExt": "doc" },
{"sourceExt": "docx", "targetExt": "doc" },
{"sourceExt": "doc", "maxSourceSizeBytes": 10485760, "targetExt": "pdf" },
{"sourceExt": "xls", "maxSourceSizeBytes": 10485760, "targetExt": "pdf"},
{"sourceExt": "ppt", "maxSourceSizeBytes": 6291456, "targetExt": "pdf" },
{"sourceExt": "docx", "maxSourceSizeBytes": 786432, "targetExt": "pdf" },
{"sourceExt": "xlsx", "maxSourceSizeBytes": 1572864, "targetExt": "pdf"},
{"sourceExt": "pptx", "maxSourceSizeBytes": 4194304, "targetExt": "pdf" },
{"sourceExt": "msg", "targetExt": "pdf"}
]
},
{
"name": "tika",
"version": "1",
"transformOptions": [
{"value": {"name": "transform"}},
{"value": {"name": "includeContents"}},
{"value": {"name": "notExtractBookmarksText"}},
{"value": {"name": "targetMimetype"}},
{"value": {"name": "targetEncoding"}}
],
"pdfrendererOptions": [
"supportedSourceAndTargetList": [
{"sourceExt": "pdf", "maxSourceSizeBytes": 26214400, "targetExt": "txt" },
{"sourceExt": "doc", "targetExt": "txt"},
{"sourceExt": "xls", "targetExt": "txt" },
{"sourceExt": "ppt", "targetExt": "txt" },
{"sourceExt": "docx", "targetExt": "txt"},
{"sourceExt": "xlsx", "targetExt": "txt" },
{"sourceExt": "pptx", "targetExt": "txt" },
{"sourceExt": "msg", "targetExt": "txt"}
]
},
{
"name": "pdfRenderer",
"version": "1",
"transformOptions": [
{"value": {"name": "page"}},
{"value": {"name": "width"}},
{"value": {"name": "height"}},
{"value": {"name": "allowPdfEnlargement"}},
{"value": {"name": "maintainPdfAspectRatio"}}
],
"imagemagickOptions": [
"supportedSourceAndTargetList": [
{"sourceExt": "pdf", "targetExt": "png" }
]
},
{
"name": "imageMagick",
"version": "1",
"transformOptions": [
{"value": {"name": "alphaRemove"}},
{"value": {"name": "autoOrient"}},
{"value": {"name": "startPage"}},
@@ -35,110 +73,103 @@
{"value": {"name": "allowEnlargement"}},
{"value": {"name": "maintainAspectRatio"}}
]}}
],
"supportedSourceAndTargetList": [
{"sourceExt": "gif", "targetExt": "gif" },
{"sourceExt": "gif", "targetExt": "jpeg"},
{"sourceExt": "gif", "targetExt": "png" },
{"sourceExt": "gif", "targetExt": "tiff"},
{"sourceExt": "jpeg", "targetExt": "gif" },
{"sourceExt": "jpeg", "targetExt": "jpeg"},
{"sourceExt": "jpeg", "targetExt": "png" },
{"sourceExt": "jpeg", "targetExt": "tiff"},
{"sourceExt": "png", "targetExt": "gif" },
{"sourceExt": "png", "targetExt": "jpeg"},
{"sourceExt": "png", "targetExt": "png" },
{"sourceExt": "png", "targetExt": "tiff"},
{"sourceExt": "tiff", "targetExt": "gif" },
{"sourceExt": "tiff", "targetExt": "tiff"}
]
},
"transformers": [
{
"supportedSourceAndTargetList": [
{"sourceMediaType": "application/msword", "targetMediaType": "application/msword" },
{"sourceMediaType": "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "targetMediaType": "application/msword" },
{"sourceMediaType": "application/msword", "maxSourceSizeBytes": 10485760, "targetMediaType": "application/pdf" },
{"sourceMediaType": "application/vnd.ms-excel", "maxSourceSizeBytes": 10485760, "targetMediaType": "application/pdf"},
{"sourceMediaType": "application/vnd.ms-powerpoint", "maxSourceSizeBytes": 6291456, "targetMediaType": "application/pdf" },
{"sourceMediaType": "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "maxSourceSizeBytes": 786432, "targetMediaType": "application/pdf" },
{"sourceMediaType": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "maxSourceSizeBytes": 1572864, "targetMediaType": "application/pdf"},
{"sourceMediaType": "application/vnd.openxmlformats-officedocument.presentationml.presentation", "maxSourceSizeBytes": 4194304, "targetMediaType": "application/pdf" },
{"sourceMediaType": "application/vnd.ms-outlook", "targetMediaType": "application/pdf"}
]
},
{
"supportedSourceAndTargetList": [
{"sourceMediaType": "application/pdf", "maxSourceSizeBytes": 26214400, "targetMediaType": "text/plain" },
{"sourceMediaType": "application/msword", "targetMediaType": "text/plain"},
{"sourceMediaType": "application/vnd.ms-excel", "targetMediaType": "text/plain" },
{"sourceMediaType": "application/vnd.ms-powerpoint", "targetMediaType": "text/plain" },
{"sourceMediaType": "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "targetMediaType": "text/plain"},
{"sourceMediaType": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "targetMediaType": "text/plain" },
{"sourceMediaType": "application/vnd.openxmlformats-officedocument.presentationml.presentation", "targetMediaType": "text/plain" },
{"sourceMediaType": "application/vnd.ms-outlook", "targetMediaType": "text/plain"}
],
"transformOptions": [
"tikaOptions"
]
},
{
"supportedSourceAndTargetList": [
{"sourceMediaType": "application/pdf", "targetMediaType": "image/png" }
],
"transformOptions": [
"pdfrendererOptions"
]
},
{
"supportedSourceAndTargetList": [
{"sourceMediaType": "image/gif", "targetMediaType": "image/gif" },
{"sourceMediaType": "image/gif", "targetMediaType": "image/jpeg"},
{"sourceMediaType": "image/gif", "targetMediaType": "image/png" },
{"sourceMediaType": "image/gif", "targetMediaType": "image/tiff"},
{
"name": "officeToImageViaPdf",
"version": "1",
"transformOptions": [
{
"group": {
"required": true,
"transformOptions": [
{"value": {"name": "alphaRemove"}},
{"value": {"name": "autoOrient"}},
{"value": {"name": "startPage"}},
{"value": {"name": "endPage"}},
{"group": {"transformOptions": [
{"value": {"name": "cropGravity"}},
{"value": {"name": "cropWidth"}},
{"value": {"name": "cropHeight"}},
{"value": {"name": "cropPercentage"}},
{"value": {"name": "cropXOffset"}},
{"value": {"name": "cropYOffset"}}
]}},
{"group": {"transformOptions": [
{"value": {"name": "thumbnail"}},
{"value": {"name": "resizeHeight"}},
{"value": {"name": "resizeWidth"}},
{"value": {"name": "resizePercentage"}},
{"value": {"name": "allowEnlargement"}},
{"value": {"name": "maintainAspectRatio"}}
]}}
]}},{
"group": {
"required": false,
"transformOptions": [
{"value": {"name": "page"}},
{"value": {"name": "width"}},
{"value": {"name": "height"}},
{"value": {"name": "allowPdfEnlargement"}},
{"value": {"name": "maintainPdfAspectRatio"}}
]
}
}
],
"supportedSourceAndTargetList": [
{"sourceExt": "doc", "targetExt": "gif" },
{"sourceExt": "doc", "targetExt": "jpeg"},
{"sourceExt": "doc", "targetExt": "png" },
{"sourceExt": "doc", "targetExt": "tiff"},
{"sourceMediaType": "image/jpeg", "targetMediaType": "image/gif" },
{"sourceMediaType": "image/jpeg", "targetMediaType": "image/jpeg"},
{"sourceMediaType": "image/jpeg", "targetMediaType": "image/png" },
{"sourceMediaType": "image/jpeg", "targetMediaType": "image/tiff"},
{"sourceExt": "xls", "targetExt": "gif" },
{"sourceExt": "xls", "targetExt": "jpeg"},
{"sourceExt": "xls", "targetExt": "png" },
{"sourceExt": "xls", "targetExt": "tiff"},
{"sourceMediaType": "image/png", "targetMediaType": "image/gif" },
{"sourceMediaType": "image/png", "targetMediaType": "image/jpeg"},
{"sourceMediaType": "image/png", "targetMediaType": "image/png" },
{"sourceMediaType": "image/png", "targetMediaType": "image/tiff"},
{"sourceExt": "ppt", "targetExt": "gif" },
{"sourceExt": "ppt", "targetExt": "jpeg"},
{"sourceExt": "ppt", "targetExt": "png" },
{"sourceExt": "ppt", "targetExt": "tiff"},
{"sourceMediaType": "image/tiff", "targetMediaType": "image/gif" },
{"sourceMediaType": "image/tiff", "targetMediaType": "image/tiff"}
],
"transformOptions": [
"imagemagickOptions"
]
},
{
"supportedSourceAndTargetList": [
{"sourceMediaType": "application/msword", "targetMediaType": "image/gif" },
{"sourceMediaType": "application/msword", "targetMediaType": "image/jpeg"},
{"sourceMediaType": "application/msword", "targetMediaType": "image/png" },
{"sourceMediaType": "application/msword", "targetMediaType": "image/tiff"},
{"sourceExt": "docx", "targetExt": "gif" },
{"sourceExt": "docx", "targetExt": "jpeg"},
{"sourceExt": "docx", "targetExt": "png" },
{"sourceExt": "docx", "targetExt": "tiff"},
{"sourceMediaType": "application/vnd.ms-excel", "targetMediaType": "image/gif" },
{"sourceMediaType": "application/vnd.ms-excel", "targetMediaType": "image/jpeg"},
{"sourceMediaType": "application/vnd.ms-excel", "targetMediaType": "image/png" },
{"sourceMediaType": "application/vnd.ms-excel", "targetMediaType": "image/tiff"},
{"sourceExt": "xlsx", "targetExt": "gif" },
{"sourceExt": "xlsx", "targetExt": "jpeg"},
{"sourceExt": "xlsx", "targetExt": "png" },
{"sourceExt": "xlsx", "targetExt": "tiff"},
{"sourceMediaType": "application/vnd.ms-powerpoint", "targetMediaType": "image/gif" },
{"sourceMediaType": "application/vnd.ms-powerpoint", "targetMediaType": "image/jpeg"},
{"sourceMediaType": "application/vnd.ms-powerpoint", "targetMediaType": "image/png" },
{"sourceMediaType": "application/vnd.ms-powerpoint", "targetMediaType": "image/tiff"},
{"sourceExt": "pptx", "targetExt": "gif" },
{"sourceExt": "pptx", "targetExt": "jpeg"},
{"sourceExt": "pptx", "targetExt": "png" },
{"sourceExt": "pptx", "targetExt": "tiff"},
{"sourceMediaType": "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "targetMediaType": "image/gif" },
{"sourceMediaType": "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "targetMediaType": "image/jpeg"},
{"sourceMediaType": "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "targetMediaType": "image/png" },
{"sourceMediaType": "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "targetMediaType": "image/tiff"},
{"sourceMediaType": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "targetMediaType": "image/gif" },
{"sourceMediaType": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "targetMediaType": "image/jpeg"},
{"sourceMediaType": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "targetMediaType": "image/png" },
{"sourceMediaType": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "targetMediaType": "image/tiff"},
{"sourceMediaType": "application/vnd.openxmlformats-officedocument.presentationml.presentation", "targetMediaType": "image/gif" },
{"sourceMediaType": "application/vnd.openxmlformats-officedocument.presentationml.presentation", "targetMediaType": "image/jpeg"},
{"sourceMediaType": "application/vnd.openxmlformats-officedocument.presentationml.presentation", "targetMediaType": "image/png" },
{"sourceMediaType": "application/vnd.openxmlformats-officedocument.presentationml.presentation", "targetMediaType": "image/tiff"},
{"sourceMediaType": "application/vnd.ms-outlook", "targetMediaType": "image/gif" },
{"sourceMediaType": "application/vnd.ms-outlook", "targetMediaType": "image/jpeg"},
{"sourceMediaType": "application/vnd.ms-outlook", "targetMediaType": "image/png" },
{"sourceMediaType": "application/vnd.ms-outlook", "targetMediaType": "image/tiff"}
],
"transformOptions": [
"pdfrendererOptions",
"imagemagickOptions"
]
}
]
}
{"sourceExt": "msg", "targetExt": "gif" },
{"sourceExt": "msg", "targetExt": "jpeg"},
{"sourceExt": "msg", "targetExt": "png" },
{"sourceExt": "msg", "targetExt": "tiff"}
]
}
]

View File

@@ -1,53 +0,0 @@
{
"transformOptions": {
"imagemagickOptions": [
{"value": {"name": "alphaRemove"}},
{"value": {"name": "autoOrient"}},
{"value": {"name": "startPage"}},
{"value": {"name": "endPage"}},
{"group": {"transformOptions": [
{"value": {"name": "cropGravity"}},
{"value": {"name": "cropWidth"}},
{"value": {"name": "cropHeight"}},
{"value": {"name": "cropPercentage"}},
{"value": {"name": "cropXOffset"}},
{"value": {"name": "cropYOffset"}}
]}},
{"group": {"transformOptions": [
{"value": {"name": "thumbnail"}},
{"value": {"name": "resizeHeight"}},
{"value": {"name": "resizeWidth"}},
{"value": {"name": "resizePercentage"}},
{"value": {"name": "allowEnlargement"}},
{"value": {"name": "maintainAspectRatio"}}
]}}
]
},
"transformers": [
{
"transformerName": "imagemagick",
"supportedSourceAndTargetList": [
{"sourceMediaType": "image/gif", "targetMediaType": "image/gif" },
{"sourceMediaType": "image/gif", "targetMediaType": "image/jpeg"},
{"sourceMediaType": "image/gif", "targetMediaType": "image/png" },
{"sourceMediaType": "image/gif", "targetMediaType": "image/tiff"},
{"sourceMediaType": "image/jpeg", "targetMediaType": "image/gif" },
{"sourceMediaType": "image/jpeg", "targetMediaType": "image/jpeg"},
{"sourceMediaType": "image/jpeg", "targetMediaType": "image/png" },
{"sourceMediaType": "image/jpeg", "targetMediaType": "image/tiff"},
{"sourceMediaType": "image/png", "targetMediaType": "image/gif" },
{"sourceMediaType": "image/png", "targetMediaType": "image/jpeg"},
{"sourceMediaType": "image/png", "targetMediaType": "image/png" },
{"sourceMediaType": "image/png", "targetMediaType": "image/tiff"},
{"sourceMediaType": "image/tiff", "targetMediaType": "image/gif" },
{"sourceMediaType": "image/tiff", "targetMediaType": "image/tiff"}
],
"transformOptions": [
"imagemagickOptions"
]
}
]
}

View File

@@ -1,29 +0,0 @@
{
"transformOptions": {
"tikaOptions": [
{"value": {"name": "transform"}},
{"value": {"name": "includeContents"}},
{"value": {"name": "notExtractBookmarksText"}},
{"value": {"name": "targetMimetype"}},
{"value": {"name": "targetEncoding"}}
]
},
"transformers": [
{
"transformerName": "tika",
"supportedSourceAndTargetList": [
{"sourceMediaType": "application/pdf", "maxSourceSizeBytes": 26214400, "targetMediaType": "text/plain" },
{"sourceMediaType": "application/msword", "targetMediaType": "text/plain"},
{"sourceMediaType": "application/vnd.ms-excel", "targetMediaType": "text/plain" },
{"sourceMediaType": "application/vnd.ms-powerpoint", "targetMediaType": "text/plain" },
{"sourceMediaType": "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "targetMediaType": "text/plain"},
{"sourceMediaType": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "targetMediaType": "text/plain" },
{"sourceMediaType": "application/vnd.openxmlformats-officedocument.presentationml.presentation", "targetMediaType": "text/plain" },
{"sourceMediaType": "application/vnd.ms-outlook", "targetMediaType": "text/plain"}
],
"transformOptions": [
"tikaOptions"
]
}
]
}

View File

@@ -1,22 +0,0 @@
{
"transformOptions": {
"pdfrendererOptions": [
{"value": {"name": "page"}},
{"value": {"name": "width"}},
{"value": {"name": "height"}},
{"value": {"name": "allowPdfEnlargement"}},
{"value": {"name": "maintainPdfAspectRatio"}}
]
},
"transformers": [
{
"transformerName": "pdfrenderer",
"supportedSourceAndTargetList": [
{"sourceMediaType": "application/pdf", "targetMediaType": "image/png" }
],
"transformOptions": [
"pdfrendererOptions"
]
}
]
}

View File

@@ -1,18 +0,0 @@
{
"transformers": [
{
"transformerName": "libreoffice",
"supportedSourceAndTargetList": [
{"sourceMediaType": "application/msword", "targetMediaType": "application/msword" },
{"sourceMediaType": "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "targetMediaType": "application/msword" },
{"sourceMediaType": "application/msword", "maxSourceSizeBytes": 10485760, "targetMediaType": "application/pdf" },
{"sourceMediaType": "application/vnd.ms-excel", "maxSourceSizeBytes": 10485760, "targetMediaType": "application/pdf"},
{"sourceMediaType": "application/vnd.ms-powerpoint", "maxSourceSizeBytes": 6291456, "targetMediaType": "application/pdf" },
{"sourceMediaType": "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "maxSourceSizeBytes": 786432, "targetMediaType": "application/pdf" },
{"sourceMediaType": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "maxSourceSizeBytes": 1572864, "targetMediaType": "application/pdf"},
{"sourceMediaType": "application/vnd.openxmlformats-officedocument.presentationml.presentation", "maxSourceSizeBytes": 4194304, "targetMediaType": "application/pdf" },
{"sourceMediaType": "application/vnd.ms-outlook", "targetMediaType": "application/pdf"}
]
}
]
}

View File

@@ -1,52 +0,0 @@
{
"transformers": [
{
"transformerName": "officeToImageViaPdf",
"transformerPipeline" : [
{"transformerName": "libreoffice", "targetMediaType": "application/pdf"},
{"transformerName": "pdfrenderer", "targetMediaType": "image/png"},
{"transformerName": "imagemagick"}
],
"supportedSourceAndTargetList": [
{"sourceMediaType": "application/msword", "targetMediaType": "image/gif" },
{"sourceMediaType": "application/msword", "targetMediaType": "image/jpeg"},
{"sourceMediaType": "application/msword", "targetMediaType": "image/png" },
{"sourceMediaType": "application/msword", "targetMediaType": "image/tiff"},
{"sourceMediaType": "application/vnd.ms-excel", "targetMediaType": "image/gif" },
{"sourceMediaType": "application/vnd.ms-excel", "targetMediaType": "image/jpeg"},
{"sourceMediaType": "application/vnd.ms-excel", "targetMediaType": "image/png" },
{"sourceMediaType": "application/vnd.ms-excel", "targetMediaType": "image/tiff"},
{"sourceMediaType": "application/vnd.ms-powerpoint", "targetMediaType": "image/gif" },
{"sourceMediaType": "application/vnd.ms-powerpoint", "targetMediaType": "image/jpeg"},
{"sourceMediaType": "application/vnd.ms-powerpoint", "targetMediaType": "image/png" },
{"sourceMediaType": "application/vnd.ms-powerpoint", "targetMediaType": "image/tiff"},
{"sourceMediaType": "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "targetMediaType": "image/gif" },
{"sourceMediaType": "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "targetMediaType": "image/jpeg"},
{"sourceMediaType": "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "targetMediaType": "image/png" },
{"sourceMediaType": "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "targetMediaType": "image/tiff"},
{"sourceMediaType": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "targetMediaType": "image/gif" },
{"sourceMediaType": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "targetMediaType": "image/jpeg"},
{"sourceMediaType": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "targetMediaType": "image/png" },
{"sourceMediaType": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "targetMediaType": "image/tiff"},
{"sourceMediaType": "application/vnd.openxmlformats-officedocument.presentationml.presentation", "targetMediaType": "image/gif" },
{"sourceMediaType": "application/vnd.openxmlformats-officedocument.presentationml.presentation", "targetMediaType": "image/jpeg"},
{"sourceMediaType": "application/vnd.openxmlformats-officedocument.presentationml.presentation", "targetMediaType": "image/png" },
{"sourceMediaType": "application/vnd.openxmlformats-officedocument.presentationml.presentation", "targetMediaType": "image/tiff"},
{"sourceMediaType": "application/vnd.ms-outlook", "targetMediaType": "image/gif" },
{"sourceMediaType": "application/vnd.ms-outlook", "targetMediaType": "image/jpeg"},
{"sourceMediaType": "application/vnd.ms-outlook", "targetMediaType": "image/png" },
{"sourceMediaType": "application/vnd.ms-outlook", "targetMediaType": "image/tiff"}
],
"transformOptions": [
"pdfrendererOptions",
"imagemagickOptions"
]
}
]
}

View File

@@ -200,8 +200,7 @@ import org.junit.runners.Suite;
org.alfresco.util.bean.HierarchicalBeanLoaderTest.class,
org.alfresco.util.resource.HierarchicalResourceLoaderTest.class,
org.alfresco.repo.events.ClientUtilTest.class,
org.alfresco.repo.rendition2.RenditionService2Test.class,
org.alfresco.transform.client.model.config.TransformServiceRegistryImplTest.class
org.alfresco.repo.rendition2.RenditionService2Test.class
})
public class AllUnitTestsSuite
{

View File

@@ -47,18 +47,11 @@ import org.junit.runners.Suite;
// Requires a running ActiveMQ
org.alfresco.repo.rawevents.EventBehaviourTest.class,
org.alfresco.repo.rawevents.TransactionAwareEventProducerTest.class,
// Requires running transformers
org.alfresco.repo.rendition2.RenditionService2IntegrationTest.class,
org.alfresco.repo.rendition2.LocalTransformServiceRegistryTest.class,
org.alfresco.repo.rendition2.LocalTransformClientIntegrationTest.class,
org.alfresco.repo.rendition2.LegacyTransformServiceRegistryTest.class,
org.alfresco.repo.rendition2.LegacyTransformClientIntegrationTest.class,
org.alfresco.repo.rendition2.LocalRenditionTest.class,
org.alfresco.repo.rendition2.LegacyRenditionTest.class,
org.alfresco.repo.rendition2.LegacyLocalRenditionTest.class,
org.alfresco.repo.rendition2.NoneRenditionTest.class,
org.alfresco.repo.rendition2.LegacyLocalTransformClientIntegrationTest.class,
org.alfresco.repo.rendition2.LegacyLocalTransformServiceRegistryTest.class,
org.alfresco.repo.rendition2.RenditionTest.class,
org.alfresco.repo.solr.SOLRTrackingComponentTest.class,
org.alfresco.repo.tagging.TaggingServiceImplTest.class,
org.alfresco.repo.transaction.AlfrescoTransactionSupportTest.class,
@@ -71,7 +64,6 @@ import org.junit.runners.Suite;
org.alfresco.repo.tenant.MultiTServiceImplTest.class,
org.alfresco.repo.search.SearcherComponentTest.class,
org.alfresco.repo.action.scheduled.ScheduledPersistedActionServiceTest.class,
org.alfresco.repo.rendition2.RenditionDefinitionTest.class
})
public class AppContext06TestSuite

View File

@@ -41,7 +41,10 @@ import org.mockito.MockitoAnnotations;
* Test class for TransformerDebugLog.
*
* @author Alan Davis
*
* @deprecated The transformations code is being moved out of the codebase and replaced by the new async RenditionService2 or other external libraries.
*/
@Deprecated
public class TransformerDebugLogTest
{
@Mock

View File

@@ -25,9 +25,9 @@
*/
package org.alfresco.repo.content.transform;
import org.alfresco.repo.rendition2.TransformClient;
import org.alfresco.service.cmr.repository.MimetypeService;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.TransformationOptions;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
@@ -49,7 +49,10 @@ import static org.mockito.Mockito.when;
* Test class for TransformerDebug.
*
* @author Alan Davis
*
* @deprecated The transformations code is being moved out of the codebase and replaced by the new async RenditionService2 or other external libraries.
*/
@Deprecated
public class TransformerDebugTest
{
@Mock
@@ -65,7 +68,7 @@ public class TransformerDebugTest
private TransformerConfig transformerConfig;
@Mock
private TransformClient transformClient;
private TransformationOptions options;
@Mock
private AbstractContentTransformerLimits transformer1;
@@ -105,14 +108,7 @@ public class TransformerDebugTest
when(transformer3.getName()).thenReturn("transformer3");
when(transformer4.getName()).thenReturn("transformer4");
transformerDebug = new TransformerDebug();
transformerDebug.setNodeService(nodeService);
transformerDebug.setMimetypeService(mimetypeService);
transformerDebug.setTransformerRegistry(transformerRegistry);
transformerDebug.setTransformerConfig(transformerConfig);
transformerDebug.setTransformerLog(log);
transformerDebug.setTransformerDebugLog(debug);
transformerDebug.setTransformClient(transformClient);
transformerDebug = new TransformerDebug(nodeService, mimetypeService, transformerRegistry, transformerConfig, log, debug);
log.setTransformerDebug(transformerDebug);
log.setTransformerConfig(transformerConfig);
@@ -155,7 +151,7 @@ public class TransformerDebugTest
{
long sourceSize = 1024*1024*3/2;
transformerDebug.pushAvailable("sourceUrl", "application/pdf", "text/plain", null, null);
transformerDebug.pushAvailable("sourceUrl", "application/pdf", "text/plain", options);
transformerDebug.unavailableTransformer(transformer1, "application/pdf", "text/plain", 50);
transformerDebug.unavailableTransformer(transformer2, "application/pdf", "text/plain", 0);
@@ -164,7 +160,7 @@ public class TransformerDebugTest
List<ContentTransformer> transformers = Arrays.asList(new ContentTransformer[] {});
transformerDebug.availableTransformers(transformers, sourceSize, null, null, "ContentService.transform(...)");
transformerDebug.availableTransformers(transformers, sourceSize, options, "ContentService.transform(...)");
transformerDebug.popAvailable();

View File

@@ -39,7 +39,10 @@ import org.mockito.MockitoAnnotations;
* Test class for TransformerLog.
*
* @author Alan Davis
*
* @deprecated The transformations code is being moved out of the codebase and replaced by the new async RenditionService2 or other external libraries.
*/
@Deprecated
public class TransformerLogTest
{
@Mock

View File

@@ -36,7 +36,6 @@ import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Qualifier;
/**
* Provides a base set of tests for {@link TransactionAwareEventProducer}
@@ -52,7 +51,6 @@ public class TransactionAwareEventProducerTest extends BaseSpringTest
@Autowired
private TransactionAwareEventProducer eventProducer;
@Autowired
@Qualifier("alfrescoEventObjectMapper")
private ObjectMapper messagingObjectMapper;
@Test

View File

@@ -28,7 +28,6 @@ package org.alfresco.repo.rendition2;
import junit.framework.AssertionFailedError;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.content.transform.LocalTransformServiceRegistry;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.thumbnail.ThumbnailRegistry;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
@@ -45,7 +44,7 @@ import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.transform.client.model.config.TransformServiceRegistry;
import org.alfresco.util.ApplicationContextHelper;
import org.alfresco.util.BaseSpringTest;
import org.alfresco.util.GUID;
import org.alfresco.util.PropertyMap;
@@ -73,7 +72,10 @@ public abstract class AbstractRenditionIntegrationTest extends BaseSpringTest
protected RenditionService2Impl renditionService2;
@Autowired
protected RenditionDefinitionRegistry2Impl renditionDefinitionRegistry2;
protected RenditionDefinitionRegistry2 renditionDefinitionRegistry2;
@Autowired
protected TransformClient transformClient;
@Autowired
protected RenditionService renditionService;
@@ -105,15 +107,6 @@ public abstract class AbstractRenditionIntegrationTest extends BaseSpringTest
@Autowired
protected PermissionService permissionService;
@Autowired
protected TransformServiceRegistry transformServiceRegistry;
@Autowired
protected LocalTransformServiceRegistry localTransformServiceRegistry;
@Autowired
protected LegacyTransformServiceRegistry legacyTransformServiceRegistry;
static String PASSWORD = "password";
protected static final String ADMIN = "admin";
@@ -122,74 +115,17 @@ public abstract class AbstractRenditionIntegrationTest extends BaseSpringTest
@BeforeClass
public static void before()
{
// Use the docker images for transforms (legacy)
// Use the docker images for transforms
System.setProperty("alfresco-pdf-renderer.url", "http://localhost:8090/");
System.setProperty("img.url", "http://localhost:8091");
System.setProperty("jodconverter.url", "http://localhost:8092/");
System.setProperty("tika.url", "http://localhost:8093/");
// Use the docker images for transforms (local)
System.setProperty("localTransformer.pdfrenderer.url", "http://localhost:8090/");
System.setProperty("localTransformer.imagemagick.url", "http://localhost:8091");
System.setProperty("localTransformer.libreoffice.url", "http://localhost:8092/");
System.setProperty("localTransformer.tika.url", "http://localhost:8093/");
}
protected static void none()
{
System.setProperty("transform.service.enabled", "false");
System.setProperty("local.transform.service.enabled", "false");
System.setProperty("legacy.transform.service.enabled", "false");
}
protected static void legacy()
{
System.setProperty("transform.service.enabled", "false");
System.setProperty("local.transform.service.enabled", "false");
System.setProperty("legacy.transform.service.enabled", "true");
}
protected static void local()
{
System.setProperty("transform.service.enabled", "false");
System.setProperty("local.transform.service.enabled", "true");
System.setProperty("legacy.transform.service.enabled", "false");
}
protected static void service()
{
System.setProperty("transform.service.enabled", "true");
System.setProperty("local.transform.service.enabled", "false");
System.setProperty("legacy.transform.service.enabled", "false");
}
protected static void legacyLocal()
{
System.setProperty("transform.service.enabled", "false");
System.setProperty("local.transform.service.enabled", "true");
System.setProperty("legacy.transform.service.enabled", "true");
}
protected static void legacyLocalService()
{
System.setProperty("transform.service.enabled", "true");
System.setProperty("local.transform.service.enabled", "true");
System.setProperty("legacy.transform.service.enabled", "true");
}
@Before
public void setUp() throws Exception
{
assertTrue("The RenditionService2 needs to be enabled", renditionService2.isEnabled());
legacyTransformServiceRegistry.setEnabled(Boolean.parseBoolean(System.getProperty("legacy.transform.service.enabled")));
legacyTransformServiceRegistry.afterPropertiesSet();
localTransformServiceRegistry.setEnabled(Boolean.parseBoolean(System.getProperty("local.transform.service.enabled")));
localTransformServiceRegistry.afterPropertiesSet();
renditionDefinitionRegistry2.setTransformServiceRegistry(transformServiceRegistry);
thumbnailRegistry.setTransformServiceRegistry(transformServiceRegistry);
}
@After
@@ -205,15 +141,6 @@ public abstract class AbstractRenditionIntegrationTest extends BaseSpringTest
System.clearProperty("img.url");
System.clearProperty("jodconverter.url");
System.clearProperty("tika.url");
System.clearProperty("localTransformer.pdfrenderer.url");
System.clearProperty("localTransformer.imagemagick.url");
System.clearProperty("localTransformer.libreoffice.url");
System.clearProperty("localTransformer.tika.url");
System.clearProperty("transform.service.enabled");
System.clearProperty("local.transform.service.enabled");
System.clearProperty("legacy.transform.service.enabled");
}
protected void checkRendition(String testFileName, String renditionName, boolean expectedToPass)

View File

@@ -1,54 +0,0 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2018 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* 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 <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.rendition2;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
/**
* Repeats quick file rendition tests with local transforms and legacy transformers enabled.
* The Transform Service does not exist for the Community edition.
* Should be the same result as with legacy or local transforms on their own.
*
* @author adavis
*/
@Deprecated
public class LegacyLocalRenditionTest extends AbstractRenditionTest
{
@BeforeClass
public static void before()
{
AbstractRenditionIntegrationTest.before();
legacyLocal();
}
@AfterClass
public static void after()
{
AbstractRenditionIntegrationTest.after();
}
}

View File

@@ -30,89 +30,107 @@ import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import static org.alfresco.model.ContentModel.PROP_CONTENT;
/**
* Integration tests for {@link LocalTransformClient}
* Integration tests for {@link LegacyLocalTransformClient}
*/
public class LocalTransformClientIntegrationTest extends AbstractRenditionIntegrationTest
public class LegacyLocalTransformClientIntegrationTest extends AbstractRenditionIntegrationTest
{
@Autowired
protected TransformClient localTransformClient;
protected TransformClient transformClient;
@BeforeClass
public static void before()
{
AbstractRenditionIntegrationTest.before();
local();
}
@AfterClass
public static void after()
{
AbstractRenditionIntegrationTest.after();
}
@Before
public void setUp() throws Exception
{
super.setUp();
AuthenticationUtil.setRunAsUser(AuthenticationUtil.getAdminUserName());
transformClient = localTransformClient;
}
// PDF transformation
@Test
public void testLocalRenderPdfToJpegMedium() throws Exception
{
localCheckRendition("quick.pdf", "medium", true);
}
@Test
public void testLocalRenderPdfToDoclib() throws Exception
{
localCheckRendition("quick.pdf", "doclib", true);
}
@Test
public void testLocalRenderPdfJpegImgpreview() throws Exception
{
localCheckRendition("quick.pdf", "imgpreview", true);
}
@Test
public void testLocalRenderPdfPngAvatar() throws Exception
{
localCheckRendition("quick.pdf", "avatar", true);
}
@Test
public void testLocalRenderPdfPngAvatar32() throws Exception
{
localCheckRendition("quick.pdf", "avatar32", true);
}
@Test
public void testLocalRenderPdfFlashWebpreview() throws Exception
{
localCheckRendition("quick.pdf", "webpreview", false);
}
// DOCX transformation
@Test
public void testLocalRenderDocxJpegMedium() throws Exception
{
checkClientRendition("quick.docx", "medium", true);
localCheckRendition("quick.docx", "medium", true);
}
@Test
public void testLocalRenderDocxDoclib() throws Exception
{
checkClientRendition("quick.docx", "doclib", true);
localCheckRendition("quick.docx", "doclib", true);
}
@Test
public void testLocalRenderDocxJpegImgpreview() throws Exception
{
checkClientRendition("quick.docx", "imgpreview", true);
localCheckRendition("quick.docx", "imgpreview", true);
}
@Test
public void testLocalRenderDocxPngAvatar() throws Exception
{
checkClientRendition("quick.docx", "avatar", true);
localCheckRendition("quick.docx", "avatar", true);
}
@Test
public void testLocalRenderDocxPngAvatar32() throws Exception
{
checkClientRendition("quick.docx", "avatar32", true);
localCheckRendition("quick.docx", "avatar32", true);
}
@Test
public void testLocalRenderDocxFlashWebpreview() throws Exception
{
checkClientRendition("quick.docx", "webpreview", false);
localCheckRendition("quick.docx", "webpreview", false);
}
@Test
public void testLocalRenderDocxPdf() throws Exception
{
checkClientRendition("quick.docx", "pdf", false);
localCheckRendition("quick.docx", "pdf", false);
}
protected void checkClientRendition(String testFileName, String renditionDefinitionName, boolean expectedToPass) throws InterruptedException
private void localCheckRendition(String testFileName, String renditionDefinitionName, boolean expectedToPass) throws InterruptedException
{
if (expectedToPass)
{
@@ -125,12 +143,11 @@ public class LocalTransformClientIntegrationTest extends AbstractRenditionIntegr
{
RenditionDefinition2 renditionDefinition =
renditionDefinitionRegistry2.getRenditionDefinition(renditionDefinitionName);
String contentUrl = contentData.getContentUrl();
String sourceMimetype = contentData.getMimetype();
long size = contentData.getSize();
String adminUserName = AuthenticationUtil.getAdminUserName();
transformClient.checkSupported(sourceNode, renditionDefinition, sourceMimetype, size, contentUrl);
transformClient.transform(sourceNode, renditionDefinition, adminUserName, sourceContentHashCode);
transformClient.transform(
sourceNode,
renditionDefinition,
AuthenticationUtil.getAdminUserName(),
sourceContentHashCode);
return null;
});
ChildAssociationRef childAssociationRef = null;

View File

@@ -25,12 +25,9 @@
*/
package org.alfresco.repo.rendition2;
import org.alfresco.repo.content.transform.LocalTransformServiceRegistry;
import org.alfresco.transform.client.model.config.TransformServiceRegistry;
import org.junit.AfterClass;
import com.sun.star.auth.InvalidArgumentException;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
@@ -41,49 +38,28 @@ import static org.alfresco.repo.content.MimetypeMap.MIMETYPE_OPENXML_WORDPROCESS
import static org.alfresco.repo.content.MimetypeMap.MIMETYPE_PDF;
/**
* Integration tests for {@link LocalTransformServiceRegistry}
* Integration tests for {@link LegacyLocalTransformServiceRegistry}
*/
public class LocalTransformServiceRegistryTest extends AbstractRenditionIntegrationTest
public class LegacyLocalTransformServiceRegistryTest extends AbstractRenditionIntegrationTest
{
@Autowired
private LocalTransformServiceRegistry localTransformServiceRegistry;
private static final String RENDITION_NAME = "pdf";
protected TransformServiceRegistry transformServiceRegistry;
@Autowired
private LegacyLocalTransformServiceRegistry transformServiceRegistry;
@Autowired
private RenditionDefinitionRegistry2 renditionDefinitionRegistry2;
private Map<String, String> options;
@BeforeClass
public static void before()
{
AbstractRenditionIntegrationTest.before();
local();
}
@AfterClass
public static void after()
{
AbstractRenditionIntegrationTest.after();
}
@Before
public void setUp() throws Exception
{
super.setUp();
transformServiceRegistry = localTransformServiceRegistry;
RenditionDefinition2 definition2 = renditionDefinitionRegistry2.getRenditionDefinition(RENDITION_NAME);
options = definition2.getTransformOptions();
}
protected void setEnabled(boolean enabled)
{
localTransformServiceRegistry.setEnabled(enabled);
}
private static final String RENDITION_NAME = "pdf";
@Autowired
private LegacyTransformServiceRegistry legacyTransformServiceRegistry;
@Test
public void testIsSupported()
{
@@ -95,7 +71,7 @@ public class LocalTransformServiceRegistryTest extends AbstractRenditionIntegrat
// Bad Source
Assert.assertFalse(transformServiceRegistry.isSupported("docxBad", 1234, MIMETYPE_PDF, options, RENDITION_NAME));
// Bad Target
Assert.assertFalse(transformServiceRegistry.isSupported(MIMETYPE_OPENXML_WORDPROCESSING, 1234, "pdfBad", options, "pdfBad"));
Assert.assertFalse(transformServiceRegistry.isSupported(MIMETYPE_OPENXML_WORDPROCESSING, 1234, "pdfBad", options, RENDITION_NAME));
// Good MaxSize docx max size is 768K
Assert.assertTrue(transformServiceRegistry.isSupported(MIMETYPE_OPENXML_WORDPROCESSING, 768L*1024, MIMETYPE_PDF, options, RENDITION_NAME));
@@ -113,7 +89,7 @@ public class LocalTransformServiceRegistryTest extends AbstractRenditionIntegrat
Assert.assertTrue(transformServiceRegistry.isSupported(MIMETYPE_OPENXML_WORDPROCESSING, 1234, MIMETYPE_PDF, options, "custom"));
}
@Test
@Test(expected = IllegalArgumentException.class)
public void testBadOptions()
{
// Source, Target and Props are in dictionary.properties
@@ -129,12 +105,12 @@ public class LocalTransformServiceRegistryTest extends AbstractRenditionIntegrat
Assert.assertTrue(transformServiceRegistry.isSupported(MIMETYPE_OPENXML_WORDPROCESSING, 1234, MIMETYPE_PDF, options, RENDITION_NAME));
try
{
setEnabled(false);
transformServiceRegistry.setEnabled(false);
Assert.assertFalse(transformServiceRegistry.isSupported(MIMETYPE_OPENXML_WORDPROCESSING, 1234, MIMETYPE_PDF, options, RENDITION_NAME));
}
finally
{
setEnabled(true);
transformServiceRegistry.setEnabled(true);
}
Assert.assertTrue(transformServiceRegistry.isSupported(MIMETYPE_OPENXML_WORDPROCESSING, 1234, MIMETYPE_PDF, options, RENDITION_NAME));
}

View File

@@ -1,69 +0,0 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2018 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* 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 <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.rendition2;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import static org.alfresco.model.ContentModel.PROP_CONTENT;
/**
* Integration tests for {@link LegacyTransformClient}
*/
@Deprecated
public class LegacyTransformClientIntegrationTest extends LocalTransformClientIntegrationTest
{
@Autowired
protected TransformClient legacyTransformClient;
@BeforeClass
public static void before()
{
AbstractRenditionIntegrationTest.before();
legacy();
}
@AfterClass
public static void after()
{
AbstractRenditionIntegrationTest.after();
}
@Before
public void setUp() throws Exception
{
super.setUp();
transformClient = legacyTransformClient;
}
}

View File

@@ -1,75 +0,0 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2018 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* 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 <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.rendition2;
import org.alfresco.transform.client.model.config.TransformServiceRegistry;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.HashMap;
import java.util.Map;
import static org.alfresco.repo.content.MimetypeMap.MIMETYPE_OPENXML_WORDPROCESSING;
import static org.alfresco.repo.content.MimetypeMap.MIMETYPE_PDF;
/**
* Integration tests for {@link LegacyTransformServiceRegistry}
*/
@Deprecated
public class LegacyTransformServiceRegistryTest extends LocalTransformServiceRegistryTest
{
@Autowired
private LegacyTransformServiceRegistry legacyTransformServiceRegistry;
@Before
public void setUp() throws Exception
{
super.setUp();
transformServiceRegistry = legacyTransformServiceRegistry;
}
@BeforeClass
public static void before()
{
AbstractRenditionIntegrationTest.before();
legacy();
}
@AfterClass
public static void after()
{
AbstractRenditionIntegrationTest.after();
}
protected void setEnabled(boolean enabled)
{
legacyTransformServiceRegistry.setEnabled(enabled);
}
}

View File

@@ -1,64 +0,0 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2018 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* 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 <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.rendition2;
import org.alfresco.util.testing.category.DebugTests;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.experimental.categories.Category;
/**
* Repeats quick file rendition tests with local transforms enabled but legacy transformers disabled.
* The Transform Service does not exist for the Community edition.
* Should be the same result as with legacy transforms only.
*
* @author adavis
*/
public class LocalRenditionTest extends AbstractRenditionTest
{
@BeforeClass
public static void before()
{
AbstractRenditionIntegrationTest.before();
local();
}
@AfterClass
public static void after()
{
AbstractRenditionIntegrationTest.after();
}
// TODO this method will be removed when Local transformers support all 196 renditions supported by legacy
@Override
@Category(DebugTests.class)
@Test
public void testAllSourceExtensions() throws Exception
{
internalTestAllSourceExtensions(57, 0);
}
}

View File

@@ -32,26 +32,27 @@ import org.junit.Test;
import org.junit.experimental.categories.Category;
/**
* Repeats quick file rendition tests with local transforms and legacy transformers disabled.
* The Transform Service does not exist for the Community edition.
* Disables local transform and repeats the RenditionTests
*
* @author adavis
*/
public class NoneRenditionTest extends AbstractRenditionTest
public class NoLocalTransformRenditionTest extends RenditionTest
{
@BeforeClass
public static void before()
{
AbstractRenditionIntegrationTest.before();
none();
System.setProperty("local.transform.service.enabled", "false");
}
@AfterClass
public static void after()
{
AbstractRenditionIntegrationTest.after();
System.clearProperty("local.transform.service.enabled");
}
@Test
@Override
public void testTasRestApiRenditions() throws Exception

View File

@@ -36,9 +36,6 @@ import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import java.util.List;
@@ -51,13 +48,6 @@ import static org.junit.Assert.assertNotEquals;
*/
public class RenditionService2IntegrationTest extends AbstractRenditionIntegrationTest
{
@BeforeClass
public static void before()
{
AbstractRenditionIntegrationTest.before();
legacyLocal();
}
// PDF transformation
@Test

View File

@@ -28,6 +28,7 @@ package org.alfresco.repo.rendition2;
import junit.framework.AssertionFailedError;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.thumbnail.ThumbnailDefinition;
import org.alfresco.transform.client.model.config.TransformServiceRegistry;
import org.alfresco.util.testing.category.DebugTests;
import org.junit.Before;
import org.junit.Test;
@@ -44,12 +45,11 @@ import java.util.Set;
import java.util.StringJoiner;
/**
* Abstract test class to check it is possible to create renditions from the quick files using combinations of
* local transforms, legacy transforms and the Transform Service.
* Test it is possible to create renditions from the quick files.
*
* @author adavis
*/
public abstract class AbstractRenditionTest extends AbstractRenditionIntegrationTest
public class RenditionTest extends AbstractRenditionIntegrationTest
{
// This is the same order as produced by MimetypeMap
public static final List<String> TAS_REST_API_SOURCE_EXTENSIONS = Arrays.asList(
@@ -89,7 +89,9 @@ public abstract class AbstractRenditionTest extends AbstractRenditionIntegration
"wpd png avatar32",
"wpd jpg imgpreview");
@Override
@Autowired
private TransformServiceRegistry transformServiceRegistry;
@Before
public void setUp() throws Exception
{
@@ -146,15 +148,17 @@ public abstract class AbstractRenditionTest extends AbstractRenditionIntegration
}
else
{
String task = sourceExtension + " " + targetExtension + " " + renditionName;
try
{
checkRendition(testFileName, renditionName, !expectedToFail.contains(sourceTragetRendition));
successes.add(sourceTragetRendition);
successes.add(task);
successCount++;
}
catch (AssertionFailedError e)
{
failures.add(sourceTragetRendition + " " + e.getMessage());
failures.add(task + " " + e.getMessage());
failedCount++;
}
}
@@ -213,6 +217,48 @@ public abstract class AbstractRenditionTest extends AbstractRenditionIntegration
Collections.emptyList(), expectedRenditionCount, expectedFailedCount);
}
@Category(DebugTests.class)
@Test
public void testTransformServiceConfig() throws Exception
{
internalTestTransformServiceConfig(57, 0);
}
// Tests all renditions supported by the TransformServiceRegistry (in the case of Transform Service, see
// transform-service-config.json and the LegacyLocalTransformServiceRegistry see the original ACS config).
protected void internalTestTransformServiceConfig(int expectedRenditionCount, int expectedFailedCount) throws Exception
{
List<String> sourceExtensions = getAllSourceMimetypes();
List<String> excludeList = new ArrayList<>();
for (String sourceExtension : sourceExtensions)
{
String sourceMimetype = mimetypeMap.getMimetype(sourceExtension);
String testFileName = getTestFileName(sourceMimetype);
if (testFileName != null)
{
Set<String> renditionNames = renditionDefinitionRegistry2.getRenditionNamesFrom(sourceMimetype, -1);
for (String renditionName : renditionNames)
{
RenditionDefinition2 renditionDefinition = renditionDefinitionRegistry2.getRenditionDefinition(renditionName);
String targetMimetype = renditionDefinition.getTargetMimetype();
String targetExtension = mimetypeMap.getExtension(targetMimetype);
String sourceTragetRendition = sourceExtension + ' ' + targetExtension + ' ' + renditionName;
Map<String, String> actualOptions = renditionDefinition.getTransformOptions();
if (!transformServiceRegistry.isSupported(sourceMimetype, -1L, targetMimetype,
actualOptions, null))
{
excludeList.add(sourceTragetRendition);
}
}
}
}
assertRenditionsOkayFromSourceExtension(sourceExtensions, excludeList,
Collections.emptyList(), expectedRenditionCount, expectedFailedCount);
}
private List<String> getAllSourceMimetypes()
{
List<String> sourceExtensions = new ArrayList<>();

View File

@@ -1,99 +0,0 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2019 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* 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 <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.transform.client.model.config;
import org.alfresco.repo.content.transform.TransformerDebug;
import org.alfresco.repo.content.transform.LocalTransformServiceRegistry;
import org.junit.After;
import org.junit.Before;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.Properties;
/**
* Extends the {@link TransformServiceRegistryImplTest} (used to test the config received from the Transform Service)
* so that configuration for the local transformations may be tested. This includes pipelines and options specific
* transform steps.
*/
public class LocalTransformServiceRegistryTest extends TransformServiceRegistryImplTest
{
protected LocalTransformServiceRegistry registry;
private Properties properties;
@Mock
private TransformerDebug transformerDebug;
public static final String TRANSFORM_SERVICE_CONFIG = "alfresco/transformers";
@Before
public void setUp() throws Exception
{
MockitoAnnotations.initMocks(this);
properties = new Properties();
properties.setProperty( "name.url", "dummy");
properties.setProperty("transformer1.url", "dummy");
properties.setProperty("transformer2.url", "dummy");
properties.setProperty("transformer3.url", "dummy");
properties.setProperty("transformer4.url", "dummy");
properties.setProperty("transformer5.url", "dummy");
properties.setProperty( "libreoffice.url", "dummy");
properties.setProperty( "tika.url", "dummy");
properties.setProperty( "pdfrenderer.url", "dummy");
properties.setProperty( "imagemagick.url", "dummy");
super.setUp();
}
protected TransformServiceRegistryImpl buildTransformServiceRegistryImpl()
{
registry = new LocalTransformServiceRegistry();
registry.setJsonObjectMapper(JSON_OBJECT_MAPPER);
registry.setProperties(properties);
registry.setTransformerDebug(transformerDebug);
return registry;
}
@After
public void tearDown()
{
// shut down
}
protected String getTransformServiceConfig()
{
return TRANSFORM_SERVICE_CONFIG;
}
// TODO test pipeline
// TODO test strict mimetype check
// TODO test retry transform on different mimetype
// TODO test using system properties and alfresco-global.properties
// TODO test the JsonConverter
}

View File

@@ -2,7 +2,7 @@
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2019 Alfresco Software Limited
* Copyright (C) 2005 - 2018 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
@@ -26,8 +26,6 @@
package org.alfresco.transform.client.model.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -37,6 +35,7 @@ import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.Arrays;
import java.util.Collections;
@@ -51,48 +50,83 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
/**
* Test the config received from the Transform Service about what it supports.
*/
public class TransformServiceRegistryImplTest
{
private static Log log = LogFactory.getLog(TransformServiceRegistryImplTest.class);
public static final String GIF = "gif";
public static final String JPEG = "jpeg";
public static final String PNG = "png";
public static final String TIFF = "tiff";
public static final String PDF = "pdf";
public static final String DOC = "doc";
public static final String XLS = "xls";
public static final String PPT = "ppt";
public static final String DOCX = "docx";
public static final String XLSX = "xlsx";
public static final String PPTX = "pptx";
public static final String MSG = "msg";
public static final String TXT = "txt";
public static final String GIF = "image/gif";
public static final String JPEG = "image/jpeg";
public static final String PNG = "image/png";
public static final String TIFF = "image/tiff";
public static final String PDF = "application/pdf";
public static final String DOC = "application/msword";
public static final String XLS = "application/vnd.ms-excel";
public static final String PPT = "application/vnd.ms-powerpoint";
public static final String MSG = "application/vnd.ms-outlook";
public static final String TXT = "text/plain";
public static final String GIF_MIMETYPE = "image/gif";
public static final String JPEG_MIMETYPE = "image/jpeg";
public static final String PNG_MIMETYPE = "image/png";
public static final String TIFF_MIMETYPE = "image/tiff";
public static final String PDF_MIMETYPE = "application/pdf";
public static final String DOC_MIMETYPE = "application/msword";
public static final String XLS_MIMETYPE = "application/vnd.ms-excel";
public static final String PPT_MIMETYPE = "application/vnd.ms-powerpoint";
public static final String DOCX_MIMETYPE = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
public static final String XLSX_MIMETYPE = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
public static final String PPTX_MIMETYPE = "application/vnd.openxmlformats-officedocument.presentationml.presentation";
public static final String MSG_MIMETYPE = "application/vnd.ms-outlook";
public static final String TXT_MIMETYPE = "text/plain";
public static final String TRANSFORM_SERVICE_CONFIG = "alfresco/transform-service-config.json";
public static final ObjectMapper JSON_OBJECT_MAPPER = new ObjectMapper();
private TransformServiceRegistryImpl registry;
protected TransformBuilder builder;
protected Transformer transformer;
private TransformBuilder builder;
private Transformer transformer;
private ExtensionMap extensionMap;
@Before
public void setUp() throws Exception
{
extensionMap = new ExtensionMap()
{
private Map<String, String> map = new HashMap<>();
{
map.put(GIF, GIF_MIMETYPE);
map.put(JPEG, JPEG_MIMETYPE);
map.put(PNG, PNG_MIMETYPE);
map.put(TIFF, TIFF_MIMETYPE);
map.put(PDF, PDF_MIMETYPE);
map.put(DOC, DOC_MIMETYPE);
map.put(XLS, XLS_MIMETYPE);
map.put(PPT, PPT_MIMETYPE);
map.put(DOCX, DOCX_MIMETYPE);
map.put(XLSX, XLSX_MIMETYPE);
map.put(PPTX, PPTX_MIMETYPE);
map.put(MSG, MSG_MIMETYPE);
map.put(TXT, TXT_MIMETYPE);
}
@Override
public String toMimetype(String extension)
{
return map.get(extension);
}
};
registry = buildTransformServiceRegistryImpl();
builder = new TransformBuilder();
}
protected TransformServiceRegistryImpl buildTransformServiceRegistryImpl()
private TransformServiceRegistryImpl buildTransformServiceRegistryImpl()
{
TransformServiceRegistryImpl registry = new TransformServiceRegistryImpl()
{
@Override
protected Log getLog()
{
return log;
}
};
TransformServiceRegistryImpl registry = new TransformServiceRegistryImpl();
registry.setExtensionMap(extensionMap);
registry.setJsonObjectMapper(JSON_OBJECT_MAPPER);
return registry;
}
@@ -103,11 +137,6 @@ public class TransformServiceRegistryImplTest
// shut down
}
protected String getTransformServiceConfig()
{
return TRANSFORM_SERVICE_CONFIG;
}
private void assertAddToPossibleOptions(TransformOptionGroup transformOptionGroup, String actualOptionNames, String expectedNames, String expectedRequired)
{
Map<String, String> actualOptions = buildActualOptions(actualOptionNames);
@@ -159,7 +188,7 @@ public class TransformServiceRegistryImplTest
private void assertTransformOptions(List<TransformOption> transformOptions)
{
transformer = new Transformer("name",
transformer = new Transformer("name", "1",
transformOptions,
Arrays.asList(
new SupportedSourceAndTarget(DOC, TXT, -1),
@@ -168,56 +197,44 @@ public class TransformServiceRegistryImplTest
registry = buildTransformServiceRegistryImpl();
registry.register(transformer);
assertTrue(registry.isSupported(XLS, 1024, TXT, Collections.emptyMap(), null));
assertTrue(registry.isSupported(XLS, 1024000, TXT, null, null));
assertFalse(registry.isSupported(XLS, 1024001, TXT, Collections.emptyMap(), null));
assertTrue(registry.isSupported(DOC, 1024001, TXT, null, null));
assertTrue(registry.isSupported(XLS_MIMETYPE, 1024, TXT_MIMETYPE, Collections.emptyMap(), null));
assertTrue(registry.isSupported(XLS_MIMETYPE, 1024000, TXT_MIMETYPE, null, null));
assertFalse(registry.isSupported(XLS_MIMETYPE, 1024001, TXT_MIMETYPE, Collections.emptyMap(), null));
assertTrue(registry.isSupported(DOC_MIMETYPE, 1024001, TXT_MIMETYPE, null, null));
}
private void assertTransformerName(String sourceMimetype, long sourceSizeInBytes, String targetMimetype,
Map<String, String> actualOptions, String expectedTransformerName,
Transformer... transformers)
{
buildAndPopulateRegistry(transformers);
String transformerName = registry.getTransformerName(sourceMimetype, sourceSizeInBytes, targetMimetype, actualOptions, null);
assertEquals(sourceMimetype+" to "+targetMimetype+" should have returned "+expectedTransformerName, expectedTransformerName, transformerName);
}
private void assertSupported(String sourceMimetype, long sourceSizeInBytes, String targetMimetype,
private void assertSupported(String sourceExt, long sourceSizeInBytes, String targetExt,
Map<String, String> actualOptions, String unsupportedMsg)
{
assertSupported(sourceMimetype, sourceSizeInBytes, targetMimetype, actualOptions, unsupportedMsg, transformer);
assertSupported(sourceExt, sourceSizeInBytes, targetExt, actualOptions, unsupportedMsg, transformer);
}
private void assertSupported(String sourceMimetype, long sourceSizeInBytes, String targetMimetype,
private void assertSupported(String sourceExt, long sourceSizeInBytes, String targetExt,
Map<String, String> actualOptions, String unsupportedMsg,
Transformer... transformers)
{
buildAndPopulateRegistry(transformers);
assertSupported(sourceMimetype, sourceSizeInBytes, targetMimetype, actualOptions, null, unsupportedMsg);
}
private void buildAndPopulateRegistry(Transformer[] transformers)
{
registry = buildTransformServiceRegistryImpl();
for (Transformer transformer : transformers)
{
registry.register(transformer);
}
assertSupported(sourceExt, sourceSizeInBytes, targetExt, actualOptions, null, unsupportedMsg);
}
private void assertSupported(String sourceMimetype, long sourceSizeInBytes, String targetMimetype,
Map<String, String> actualOptions, String renditionName,
private void assertSupported(String sourceExt, long sourceSizeInBytes, String targetExt,
Map<String, String> actualOptions, String transformName,
String unsupportedMsg)
{
boolean supported = registry.isSupported(sourceMimetype, sourceSizeInBytes, targetMimetype, actualOptions, renditionName);
String sourceMimetype = extensionMap.toMimetype(sourceExt);
String targetMimetype = extensionMap.toMimetype(targetExt);
boolean supported = registry.isSupported(sourceMimetype, sourceSizeInBytes, targetMimetype, actualOptions, transformName);
if (unsupportedMsg == null || unsupportedMsg.isEmpty())
{
assertTrue(sourceMimetype+" to "+targetMimetype+" should be SUPPORTED", supported);
assertTrue(sourceExt+" to "+targetExt+" should be SUPPORTED", supported);
}
else
{
assertFalse(sourceMimetype+" to "+targetMimetype+" should NOT be supported", supported);
assertFalse(sourceExt+" to "+targetExt+" should NOT be supported", supported);
}
}
@@ -235,7 +252,7 @@ public class TransformServiceRegistryImplTest
@Test
public void testReadWriteJson() throws IOException
{
Transformer libreoffice = new Transformer("libreoffice",
Transformer libreOffice = new Transformer("libreOffice", "1",
null, // there are no options
Arrays.asList(
new SupportedSourceAndTarget(DOC, PDF, -1),
@@ -243,7 +260,7 @@ public class TransformServiceRegistryImplTest
new SupportedSourceAndTarget(PPT, PDF, -1),
new SupportedSourceAndTarget(MSG, PDF, -1)));
Transformer pdfrenderer = new Transformer("pdfrenderer",
Transformer pdfRenderer = new Transformer("pdfRenderer", "1",
Arrays.asList(
new TransformOptionValue(false, "page"),
new TransformOptionValue(false, "width"),
@@ -253,7 +270,7 @@ public class TransformServiceRegistryImplTest
Arrays.asList(
new SupportedSourceAndTarget(PDF, PNG, -1)));
Transformer tika = new Transformer("tika",
Transformer tika = new Transformer("tika", "1",
Arrays.asList(
new TransformOptionValue(false, "transform"),
new TransformOptionValue(false, "includeContents"),
@@ -267,7 +284,7 @@ public class TransformServiceRegistryImplTest
new SupportedSourceAndTarget(PPT, TXT, -1),
new SupportedSourceAndTarget(MSG, TXT, -1)));
Transformer imagemagick = new Transformer("imagemagick",
Transformer imageMagick = new Transformer("imageMagick", "1",
Arrays.asList(
new TransformOptionValue(false, "alphaRemove"),
new TransformOptionValue(false, "autoOrient"),
@@ -305,7 +322,7 @@ public class TransformServiceRegistryImplTest
new SupportedSourceAndTarget(TIFF, PNG, -1),
new SupportedSourceAndTarget(TIFF, TIFF, -1)));
Transformer officeToImage = builder.buildPipeLine("transformer1",
Transformer officeToImage = builder.buildPipeLine("officeToImageViaPdf", "1",
Arrays.asList(
new SupportedSourceAndTarget(DOC, GIF, -1),
new SupportedSourceAndTarget(DOC, JPEG, -1),
@@ -324,11 +341,11 @@ public class TransformServiceRegistryImplTest
new SupportedSourceAndTarget(MSG, PNG, -1),
new SupportedSourceAndTarget(MSG, TIFF, -1)),
Arrays.asList(
new ChildTransformer(false, libreoffice), // to pdf
new ChildTransformer(false, pdfrenderer), // to png
new ChildTransformer(true, imagemagick))); // to other image formats
new ChildTransformer(false, libreOffice), // to pdf
new ChildTransformer(false, pdfRenderer), // to png
new ChildTransformer(true, imageMagick))); // to other image formats
List<Transformer> transformers1 = Arrays.asList(libreoffice, tika, pdfrenderer, imagemagick, officeToImage);
List<Transformer> transformers1 = Arrays.asList(libreOffice, tika, pdfRenderer, imageMagick, officeToImage);
File tempFile = File.createTempFile("test", ".json");
ObjectMapper objectMapper = new ObjectMapper();
@@ -350,89 +367,97 @@ public class TransformServiceRegistryImplTest
assertSupported(PDF, 1234, PNG, null, null, ""); // pdfrenderer
assertSupported(JPEG,1234, GIF, null, null, ""); // imagemagick
assertSupported(MSG, 1234, TXT, null, null, ""); // tika
assertSupported(MSG, 1234, GIF, null, null, ""); // transformer1 (officeToImageViaPdf)
assertSupported(DOC, 1234, PNG, null, null, ""); // transformer1 (officeToImageViaPdf)
assertSupported(MSG, 1234, GIF, null, null, ""); // officeToImageViaPdf
assertSupported(DOC, 1234, PNG, null, null, ""); // officeToImageViaPdf
}
}
@Test
public void testJsonConfig() throws IOException
{
registry.register(getTransformServiceConfig());
try (Reader reader = new BufferedReader(new InputStreamReader(getClass().getClassLoader().
getResourceAsStream(TRANSFORM_SERVICE_CONFIG))))
{
registry.register(reader);
// Check the count of transforms supported
assertEquals("The number of UNIQUE source to target mimetypes transforms has changed. Config change?",
60, countSupportedTransforms(true));
assertEquals("The number of source to target mimetypes transforms has changed. " +
"There may be multiple transformers for the same combination. Config change?",
60, countSupportedTransforms(false));
// Check the count of transforms supported
assertEquals("The number of UNIQUE source to target mimetypes transforms has changed. Config change?",
63, countSupportedTransforms(true));
assertEquals("The number of source to target mimetypes transforms has changed. " +
"There may be multiple transformers for the same combination. Config change?",
63, countSupportedTransforms(false));
// Check a supported transform for each transformer.
assertSupported(DOC, 1234, PDF, null, null, ""); // libreoffice
assertSupported(DOC, 1234, PDF, null, null, ""); // libreoffice
assertSupported(PDF, 1234, PNG, null, null, ""); // pdfrenderer
assertSupported(JPEG,1234, GIF, null, null, ""); // imagemagick
assertSupported(MSG, 1234, TXT, null, null, ""); // tika
assertSupported(MSG, 1234, GIF, null, null, ""); // officeToImageViaPdf
// Check a supported transform for each transformer.
assertSupported(DOC, 1234, PDF, null, null, ""); // libreoffice
assertSupported(DOC, 1234, PDF, null, null, ""); // libreoffice
assertSupported(PDF, 1234, PNG, null, null, ""); // pdfrenderer
assertSupported(JPEG,1234, GIF, null, null, ""); // imagemagick
assertSupported(MSG, 1234, TXT, null, null, ""); // tika
assertSupported(MSG, 1234, GIF, null, null, ""); // officeToImageViaPdf
Map<String, String> invalidPdfOptions = new HashMap<>();
invalidPdfOptions.put("allowEnlargement", "false");
assertSupported(DOC, 1234, PDF, invalidPdfOptions, null, "Invalid as there is a extra option");
Map<String, String> invalidPdfOptions = new HashMap<>();
invalidPdfOptions.put("allowEnlargement", "false");
assertSupported(DOC, 1234, PDF, invalidPdfOptions, null, "Invalid as there is a extra option");
}
}
@Test
public void testJsonPipeline() throws IOException
{
registry.register("alfresco/transform-service-config-test1.json");
try (Reader reader = new BufferedReader(new InputStreamReader(getClass().getClassLoader().
getResourceAsStream("alfresco/transform-service-config-test1.json"))))
{
registry.register(reader);
// Check the count of transforms supported
assertEquals("The number of UNIQUE source to target mimetypes transforms has changed. Config change?",
4, countSupportedTransforms(true));
assertEquals("The number of source to target mimetypes transforms has changed. " +
"There may be multiple transformers for the same combination. Config change?",
4, countSupportedTransforms(false));
// Check the count of transforms supported
assertEquals("The number of UNIQUE source to target mimetypes transforms has changed. Config change?",
4, countSupportedTransforms(true));
assertEquals("The number of source to target mimetypes transforms has changed. " +
"There may be multiple transformers for the same combination. Config change?",
4, countSupportedTransforms(false));
ConcurrentMap<String, List<TransformServiceRegistryImpl.SupportedTransform>> transformer =
registry.transformers.get("officeToImageViaPdf");
ConcurrentMap<String, List<TransformServiceRegistryImpl.SupportedTransform>> transformer =
registry.transformers.get("officeToImageViaPdf");
// Check required and optional default correctly
ConcurrentMap<String, List<TransformServiceRegistryImpl.SupportedTransform>> transformsToWord =
registry.transformers.get(DOC);
List<TransformServiceRegistryImpl.SupportedTransform> supportedTransforms = transformsToWord.get(GIF);
TransformServiceRegistryImpl.SupportedTransform supportedTransform = supportedTransforms.get(0);
// Check required and optional default correctly
ConcurrentMap<String, List<TransformServiceRegistryImpl.SupportedTransform>> transformsToWord =
registry.transformers.get("application/msword");
List<TransformServiceRegistryImpl.SupportedTransform> supportedTransforms = transformsToWord.get("image/gif");
TransformServiceRegistryImpl.SupportedTransform supportedTransform = supportedTransforms.get(0);
TransformOptionGroup imagemagick = (TransformOptionGroup)supportedTransform.transformOptions.transformOptions.get(0);
TransformOptionGroup pdf = (TransformOptionGroup)supportedTransform.transformOptions.transformOptions.get(1);
TransformOptionGroup imageMagick = (TransformOptionGroup)supportedTransform.transformOptions.transformOptions.get(0);
TransformOptionGroup pdf = (TransformOptionGroup)supportedTransform.transformOptions.transformOptions.get(1);
TransformOptionValue alphaRemove = (TransformOptionValue)imagemagick.transformOptions.get(0);
TransformOptionGroup crop = (TransformOptionGroup)imagemagick.transformOptions.get(4);
TransformOptionValue cropGravity = (TransformOptionValue)crop.transformOptions.get(0);
TransformOptionValue cropWidth = (TransformOptionValue)crop.transformOptions.get(1);
TransformOptionValue alphaRemove = (TransformOptionValue)imageMagick.transformOptions.get(0);
TransformOptionGroup crop = (TransformOptionGroup)imageMagick.transformOptions.get(4);
TransformOptionValue cropGravity = (TransformOptionValue)crop.transformOptions.get(0);
TransformOptionValue cropWidth = (TransformOptionValue)crop.transformOptions.get(1);
assertTrue("The holding group should be required", supportedTransform.transformOptions.isRequired());
assertFalse("imagemagick should be optional as it is not set", imagemagick.isRequired());
assertFalse("pdf should be optional as required is not set", pdf.isRequired());
assertEquals("alphaRemove", alphaRemove.getName());
assertEquals("cropGravity", cropGravity.getName());
assertEquals("cropWidth", cropWidth.getName());
assertFalse("alphaRemove should be optional as required is not set", alphaRemove.isRequired());
assertFalse("crop should be optional as required is not set", crop.isRequired());
assertTrue("cropGravity should be required as it is set", cropGravity.isRequired());
assertFalse("cropWidth should be optional as required is not set", cropWidth.isRequired());
assertTrue("The holding group should be required", supportedTransform.transformOptions.isRequired());
assertTrue("imageMagick should be required as it is set", imageMagick.isRequired());
assertFalse("pdf should be optional as required is not set", pdf.isRequired());
assertEquals("alphaRemove", alphaRemove.getName());
assertEquals("cropGravity", cropGravity.getName());
assertEquals("cropWidth", cropWidth.getName());
assertFalse("alphaRemove should be optional as required is not set", alphaRemove.isRequired());
assertFalse("crop should be optional as required is not set", crop.isRequired());
assertTrue("cropGravity should be required as it is set", cropGravity.isRequired());
assertFalse("cropWidth should be optional as required is not set", cropWidth.isRequired());
// Check a supported transform for each transformer.
assertSupported(DOC,1234, GIF, null, null, "");
assertSupported(DOC,1234, PNG, null, null, "");
assertSupported(DOC,1234, JPEG, null, null, "");
assertSupported(DOC,1234, TIFF, null, null, "");
// Check a supported transform for each transformer.
assertSupported(DOC,1234, GIF, null, null, "");
assertSupported(DOC,1234, PNG, null, null, "");
assertSupported(DOC,1234, JPEG, null, null, "");
assertSupported(DOC,1234, TIFF, null, null, "");
Map<String, String> actualOptions = new HashMap<>();
actualOptions.put("thumbnail", "true");
actualOptions.put("resizeWidth", "100");
actualOptions.put("resizeHeight", "100");
actualOptions.put("allowEnlargement", "false");
actualOptions.put("maintainAspectRatio", "true");
assertSupported(DOC,1234, PNG, actualOptions, null, "");
Map<String, String> actualOptions = new HashMap<>();
actualOptions.put("thumbnail", "true");
actualOptions.put("resizeWidth", "100");
actualOptions.put("resizeHeight", "100");
actualOptions.put("allowEnlargement", "false");
actualOptions.put("maintainAspectRatio", "true");
assertSupported(DOC,1234, PNG, actualOptions, null, "");
}
}
private int countSupportedTransforms(boolean unique)
@@ -602,7 +627,7 @@ public class TransformServiceRegistryImplTest
@Test
public void testSupported()
{
transformer = new Transformer("name",
transformer = new Transformer("name", "1",
Arrays.asList(
new TransformOptionValue(false, "page"),
new TransformOptionValue(false, "width"),
@@ -628,7 +653,7 @@ public class TransformServiceRegistryImplTest
public void testCache()
{
// Note: transformNames are an alias for a set of actualOptions and the target mimetpe. The source mimetype may change.
transformer = new Transformer("name",
transformer = new Transformer("name", "1",
Arrays.asList(
new TransformOptionValue(false, "page"),
new TransformOptionValue(false, "width"),
@@ -642,50 +667,18 @@ public class TransformServiceRegistryImplTest
assertSupported(DOC, 1024, GIF, null, "doclib", "");
assertSupported(MSG, 1024, GIF, null, "doclib", "");
assertEquals(102400L, registry.getMaxSize(DOC, GIF, null, "doclib"));
assertEquals(-1L, registry.getMaxSize(MSG, GIF, null, "doclib"));
assertEquals(102400L, registry.getMaxSize(DOC_MIMETYPE, GIF_MIMETYPE, null, "doclib"));
assertEquals(-1L, registry.getMaxSize(MSG_MIMETYPE, GIF_MIMETYPE, null, "doclib"));
// Change the cached value and try and check we are now using the cached value.
List<TransformServiceRegistryImpl.SupportedTransform> supportedTransforms = registry.cachedSupportedTransformList.get("doclib").get(DOC);
supportedTransforms.get(0).maxSourceSizeBytes = 1234L;
assertEquals(1234L, registry.getMaxSize(DOC, GIF, null, "doclib"));
}
@Test
public void testGetTransformerName()
{
Transformer t1 = new Transformer("transformer1", null,
Arrays.asList(new SupportedSourceAndTarget(MSG, GIF, 100, 50)));
Transformer t2 = new Transformer("transformer2", null,
Arrays.asList(new SupportedSourceAndTarget(MSG, GIF, 200, 60)));
Transformer t3 = new Transformer("transformer3", null,
Arrays.asList(new SupportedSourceAndTarget(MSG, GIF, 200, 40)));
Transformer t4 = new Transformer("transformer4", null,
Arrays.asList(new SupportedSourceAndTarget(MSG, GIF, -1, 100)));
Transformer t5 = new Transformer("transformer5", null,
Arrays.asList(new SupportedSourceAndTarget(MSG, GIF, -1, 80)));
Map<String, String> actualOptions = null;
// Select on size - priority is ignored
assertTransformerName(MSG, 100, GIF, actualOptions, "transformer1", t1, t2);
assertTransformerName(MSG, 150, GIF, actualOptions, "transformer2", t1, t2);
assertTransformerName(MSG, 250, GIF, actualOptions, null, t1, t2);
// Select on priority - t1, t2 and t4 are discarded.
// t3 is a higher priority and has a larger size than t1 and t2.
// Similar story fo t4 with t5.
assertTransformerName(MSG, 100, GIF, actualOptions, "transformer3", t1, t2, t3, t4, t5);
assertTransformerName(MSG, 200, GIF, actualOptions, "transformer3", t1, t2, t3, t4, t5);
// Select on size and priority, t1 and t2 discarded
assertTransformerName(MSG, 200, GIF, actualOptions, "transformer3", t1, t2, t3, t4);
assertTransformerName(MSG, 300, GIF, actualOptions, "transformer4", t1, t2, t3, t4);
assertTransformerName(MSG, 300, GIF, actualOptions, "transformer5", t1, t2, t3, t4, t5);
registry.cachedMaxSizes.get("doclib").put(DOC_MIMETYPE, 1234L);
assertEquals(1234L, registry.getMaxSize(DOC_MIMETYPE, GIF_MIMETYPE, null, "doclib"));
}
@Test
public void testMultipleTransformers()
{
Transformer transformer1 = new Transformer("transformer1",
Transformer transformer1 = new Transformer("transformer1", "1",
Arrays.asList(
new TransformOptionValue(false, "page"),
new TransformOptionValue(false, "width"),
@@ -695,7 +688,7 @@ public class TransformServiceRegistryImplTest
new SupportedSourceAndTarget(DOC, JPEG, -1),
new SupportedSourceAndTarget(MSG, GIF, -1)));
Transformer transformer2 = new Transformer("transformer2",
Transformer transformer2 = new Transformer("transformer2", "1",
Arrays.asList(
new TransformOptionValue(false, "opt1"),
new TransformOptionValue(false, "opt2")),
@@ -703,7 +696,7 @@ public class TransformServiceRegistryImplTest
new SupportedSourceAndTarget(PDF, GIF, -1),
new SupportedSourceAndTarget(PPT, JPEG, -1)));
Transformer transformer3 = new Transformer("transformer3",
Transformer transformer3 = new Transformer("transformer3", "1",
Arrays.asList(
new TransformOptionValue(false, "opt1")),
Arrays.asList(
@@ -732,13 +725,13 @@ public class TransformServiceRegistryImplTest
@Test
public void testPipeline()
{
Transformer transformer1 = new Transformer("transformer1",
Transformer transformer1 = new Transformer("transformer1", "1",
null, // there are no options
Arrays.asList(
new SupportedSourceAndTarget(DOC, PDF, -1),
new SupportedSourceAndTarget(MSG, PDF, -1)));
Transformer transformer2 = new Transformer("transformer2",
Transformer transformer2 = new Transformer("transformer2", "1",
Arrays.asList(
new TransformOptionValue(false, "page"),
new TransformOptionValue(false, "width"),
@@ -771,7 +764,7 @@ public class TransformServiceRegistryImplTest
private void buildPipelineTransformer(Transformer transformer1, Transformer transformer2)
{
transformer = builder.buildPipeLine("transformer1",
transformer = builder.buildPipeLine("officeToImage", "1",
Arrays.asList(
new SupportedSourceAndTarget(DOC, GIF, -1),
new SupportedSourceAndTarget(DOC, JPEG, -1),
@@ -780,4 +773,14 @@ public class TransformServiceRegistryImplTest
new ChildTransformer(false, transformer1),
new ChildTransformer(true, transformer2)));
}
@Test(expected = IllegalArgumentException.class)
public void textMissingMimetype()
{
transformer = new Transformer("name", "1",
null, // there are no options
Arrays.asList(
new SupportedSourceAndTarget("rubbish", PDF, -1)));
registry.register(transformer);
}
}

View File

@@ -1,47 +1,49 @@
{
"transformOptions": {
"pdfrendererOptions": [
{"value": {"name": "page"}},
{"value": {"name": "width"}},
{"value": {"name": "height"}},
{"value": {"name": "allowPdfEnlargement"}},
{"value": {"name": "maintainPdfAspectRatio"}}
[
{
"name": "officeToImageViaPdf",
"version": "1",
"transformOptions": [
{
"group": {
"required": true,
"transformOptions": [
{"value": {"name": "alphaRemove"}},
{"value": {"name": "autoOrient"}},
{"value": {"name": "startPage"}},
{"value": {"name": "endPage"}},
{"group": {"transformOptions": [
{"value": {"required": "true", "name": "cropGravity"}},
{"value": {"name": "cropWidth"}},
{"value": {"name": "cropHeight"}},
{"value": {"name": "cropPercentage"}},
{"value": {"name": "cropXOffset"}},
{"value": {"name": "cropYOffset"}}
]}},
{"group": {"transformOptions": [
{"value": {"name": "thumbnail"}},
{"value": {"name": "resizeHeight"}},
{"value": {"name": "resizeWidth"}},
{"value": {"name": "resizePercentage"}},
{"value": {"name": "allowEnlargement"}},
{"value": {"name": "maintainAspectRatio"}}
]}}
]}},{
"group": {
"transformOptions": [
{"value": {"name": "page"}},
{"value": {"name": "width"}},
{"value": {"name": "height"}},
{"value": {"name": "allowPdfEnlargement"}},
{"value": {"name": "maintainPdfAspectRatio"}}
]
}
}
],
"imagemagickOptions": [
{"value": {"name": "alphaRemove"}},
{"value": {"name": "autoOrient"}},
{"value": {"name": "startPage"}},
{"value": {"name": "endPage"}},
{"group": {"transformOptions": [
{"value": {"required": "true", "name": "cropGravity"}},
{"value": {"name": "cropWidth"}},
{"value": {"name": "cropHeight"}},
{"value": {"name": "cropPercentage"}},
{"value": {"name": "cropXOffset"}},
{"value": {"name": "cropYOffset"}}
]}},
{"group": {"transformOptions": [
{"value": {"name": "thumbnail"}},
{"value": {"name": "resizeHeight"}},
{"value": {"name": "resizeWidth"}},
{"value": {"name": "resizePercentage"}},
{"value": {"name": "allowEnlargement"}},
{"value": {"name": "maintainAspectRatio"}}
]}}
"supportedSourceAndTargetList": [
{"sourceExt": "doc", "targetExt": "gif" },
{"sourceExt": "doc", "targetExt": "jpeg"},
{"sourceExt": "doc", "targetExt": "png" },
{"sourceExt": "doc", "targetExt": "tiff"}
]
},
"transformers": [
{
"supportedSourceAndTargetList": [
{"sourceMediaType": "application/msword", "targetMediaType": "image/gif" },
{"sourceMediaType": "application/msword", "targetMediaType": "image/jpeg"},
{"sourceMediaType": "application/msword", "targetMediaType": "image/png" },
{"sourceMediaType": "application/msword", "targetMediaType": "image/tiff"}
],
"transformOptions": [
"pdfrendererOptions",
"imagemagickOptions"
]
}
]
}
}
]