REPO-4319 Local Transformers (#313)

Creation of local transformers that don't depend on any of the legacy transformer code deprecated in ACS 6.1.  The previous local transformers are now referred to as legacy transformers.

The localTransformClient and localTransformServiceRegistry now are switches between these two classes of transform.
This commit is contained in:
alandavis
2019-05-31 22:06:47 +01:00
committed by GitHub
parent 2ee0d62b80
commit 436ba847f6
61 changed files with 3439 additions and 1027 deletions

View File

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

View File

@@ -0,0 +1,259 @@
/*
* #%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 targetEncoding, 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 targetEncoding = writer.getEncoding();
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 + "\n" +
" target encoding: " + targetEncoding);
}
transformWithDebug(reader, writer, transformOptions, renditionName, sourceNodeRef, sourceMimetype,
targetMimetype, targetEncoding, 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 targetEncoding, 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, targetEncoding, 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,10 +42,17 @@ 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.
*
@@ -74,6 +81,8 @@ public abstract class AbstractRemoteContentTransformer extends AbstractContentTr
}
public void afterPropertiesSet()
{
if (enabled)
{
// check availability
if (remoteTransformerClientConfigured())
@@ -88,12 +97,12 @@ public abstract class AbstractRemoteContentTransformer extends AbstractContentTr
{
String versionString = msg;
setAvailable(true);
logger.info("Using remote " + getName() + ": " + versionString);
logger.info("Using legacy local " + getName() + ": " + versionString);
}
else
{
setAvailable(false);
String message = "Remote " + getName() + " is not available for transformations. " + msg;
String message = "Legacy local " + getName() + " is not available for transformations. " + msg;
if (isAvailable == null)
{
logger.debug(message);
@@ -117,6 +126,7 @@ public abstract class AbstractRemoteContentTransformer extends AbstractContentTr
available = true;
}
}
}
public boolean isAvailable()
{

View File

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

View File

@@ -48,8 +48,15 @@ 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;
@@ -82,6 +89,8 @@ public class JodContentTransformer extends OOoContentTransformerHelper implement
@Override
public void afterPropertiesSet()
{
if (enabled)
{
super.afterPropertiesSet();
if (remoteTransformerClientConfigured())
@@ -91,11 +100,11 @@ public class JodContentTransformer extends OOoContentTransformerHelper implement
if (isAvailable != null && isAvailable)
{
String versionString = result.getSecond().trim();
logger.info("Using remote JodCoverter: "+versionString);
logger.info("Using legacy local JodCoverter: " + versionString);
}
else
{
String message = "Remote JodConverter is not available for transformations. " + result.getSecond();
String message = "Legacy local JodConverter is not available for transformations. " + result.getSecond();
if (isAvailable == null)
{
logger.debug(message);
@@ -107,6 +116,7 @@ public class JodContentTransformer extends OOoContentTransformerHelper implement
}
}
}
}
@Override
protected void convert(File tempFromFile, DocumentFormat sourceFormat, File tempToFile,

View File

@@ -0,0 +1,128 @@
/*
* #%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 targetEncoding, 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

@@ -0,0 +1,398 @@
/*
* #%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

@@ -0,0 +1,42 @@
/*
* #%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

@@ -0,0 +1,163 @@
/*
* #%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 targetEncoding, String renditionName, NodeRef sourceNodeRef) throws Exception
{
// 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) * 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;
}
}
remoteTransformerClient.request(reader, writer, sourceMimetype, sourceExtension, targetExtension,
timeoutMs, log, args);
}
}

View File

@@ -53,10 +53,7 @@ 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;
@@ -137,7 +134,7 @@ public class RemoteTransformerClient
if (logger.isDebugEnabled())
{
logger.debug("Remote "+name+' '+sourceExtension+' '+targetExtension+' '+url+' '+args);
logger.debug(name+' '+sourceExtension+' '+targetExtension+' '+url+' '+args);
}
try
@@ -149,7 +146,7 @@ public class RemoteTransformerClient
StatusLine statusLine = response.getStatusLine();
if (statusLine == null)
{
throw new AlfrescoRuntimeException("Remote "+name+" returned no status " + url + ' ' + args);
throw new AlfrescoRuntimeException(name+" returned no status " + url + ' ' + args);
}
HttpEntity resEntity = response.getEntity();
if (resEntity != null)
@@ -164,7 +161,7 @@ public class RemoteTransformerClient
long responseContentLength = resEntity.getContentLength();
Header responseContentEncoding = resEntity.getContentEncoding();
Header responseContentType = resEntity.getContentType();
logger.debug("Remote " + name + ' ' + sourceExtension + ' ' + targetExtension +
logger.debug(name + ' ' + sourceExtension + ' ' + targetExtension +
" returned. length=" + responseContentLength +
" type=" + responseContentType +
" encoding=" + responseContentEncoding);
@@ -175,13 +172,13 @@ public class RemoteTransformerClient
}
catch (IOException e)
{
throw new AlfrescoRuntimeException("Remote " + name + " failed to read the returned content", e);
throw new AlfrescoRuntimeException(name + " failed to read the returned content", e);
}
}
else
{
String message = getErrorMessage(resEntity);
String msg = ("Remote " + name + " returned a " + statusCode + " status " + message +
String msg = (name + " returned a " + statusCode + " status " + message +
' ' + url + ' ' + args).trim();
if (statusCode == 401)
{
@@ -199,7 +196,7 @@ public class RemoteTransformerClient
}
else
{
throw new AlfrescoRuntimeException("Remote " + name + " did not return an entity " + url);
throw new AlfrescoRuntimeException(name + " did not return an entity " + url);
}
}
catch (IOException e)
@@ -207,12 +204,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("Remote " + name + " failed to connect or to read the response", e);
throw new AlfrescoRuntimeException(name + " failed to connect or to read the response", e);
}
}
catch (IOException e)
{
throw new AlfrescoRuntimeException("Remote " + name + " failed to create an HttpClient", e);
throw new AlfrescoRuntimeException(name + " failed to create an HttpClient", e);
}
}
catch (AlfrescoRuntimeException e)
@@ -235,7 +232,7 @@ public class RemoteTransformerClient
{
if (!isTimeToCheckAvailability())
{
logger.debug("Remote "+name+' '+" too early to check availability");
logger.debug(name+' '+" too early to check availability");
Pair<Boolean, String> result = getCheckResult();
return result;
}
@@ -245,7 +242,7 @@ public class RemoteTransformerClient
if (logger.isDebugEnabled())
{
logger.debug("Remote "+name+' '+" check" +url);
logger.debug(name+' '+" check" +url);
}
try
@@ -257,7 +254,7 @@ public class RemoteTransformerClient
StatusLine statusLine = response.getStatusLine();
if (statusLine == null)
{
throw new AlfrescoRuntimeException("Remote "+name+" check returned no status " + url);
throw new AlfrescoRuntimeException(name+" check returned no status " + url);
}
HttpEntity resEntity = response.getEntity();
if (resEntity != null)
@@ -274,7 +271,7 @@ public class RemoteTransformerClient
long responseContentLength = resEntity.getContentLength();
Header responseContentType = resEntity.getContentType();
Header responseContentEncoding = resEntity.getContentEncoding();
logger.debug("Remote " + name +
logger.debug(name +
" check returned. length=" + responseContentLength +
" type=" + responseContentType +
" encoding=" + responseContentEncoding+
@@ -289,28 +286,28 @@ public class RemoteTransformerClient
}
catch (IOException e)
{
throw new AlfrescoRuntimeException("Remote " + name + " check failed to read the returned content", e);
throw new AlfrescoRuntimeException(name + " check failed to read the returned content", e);
}
}
else
{
String message = getErrorMessage(resEntity);
throw new AlfrescoRuntimeException("Remote " + name + " check returned a " + statusCode + " status " + message + ' ' + url);
throw new AlfrescoRuntimeException(name + " check returned a " + statusCode + " status " + message + ' ' + url);
}
}
else
{
throw new AlfrescoRuntimeException("Remote " + name + " check did not return an entity " + url);
throw new AlfrescoRuntimeException(name + " check did not return an entity " + url);
}
}
catch (IOException e)
{
throw new AlfrescoRuntimeException("Remote " + name + " check failed to connect or to read the response", e);
throw new AlfrescoRuntimeException(name + " check failed to connect or to read the response", e);
}
}
catch (IOException e)
{
throw new AlfrescoRuntimeException("Remote " + name + " check failed to create an HttpClient", e);
throw new AlfrescoRuntimeException(name + " check failed to create an HttpClient", e);
}
}
catch (AlfrescoRuntimeException e)

View File

@@ -25,8 +25,37 @@
*/
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.IOException;
import java.io.Serializable;
import java.net.URI;
import java.net.URL;
import java.util.ArrayDeque;
import java.util.ArrayList;
@@ -34,8 +63,11 @@ 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;
@@ -43,24 +75,7 @@ import java.util.TreeSet;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Pattern;
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;
import static org.alfresco.repo.rendition2.RenditionService2Impl.SOURCE_HAS_NO_CONTENT;
/**
* Debugs transformers selection and activity.<p>
@@ -79,21 +94,26 @@ import org.apache.commons.logging.LogFactory;
* 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.
*/
@Deprecated
@AlfrescoPublicApi
public class TransformerDebug
public class TransformerDebug implements ApplicationContextAware
{
private static final String FINISHED_IN = "Finished in ";
private static final String NO_TRANSFORMERS = "No transformers";
private final Log logger;
private final Log info;
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;
@Deprecated
@AlfrescoPublicApi
private enum Call
{
AVAILABLE,
@@ -101,8 +121,6 @@ public class TransformerDebug
AVAILABLE_AND_TRANSFORM
};
@Deprecated
@AlfrescoPublicApi
private static class ThreadInfo
{
private static final ThreadLocal<ThreadInfo> threadInfo = new ThreadLocal<ThreadInfo>()
@@ -153,8 +171,6 @@ public class TransformerDebug
}
}
@Deprecated
@AlfrescoPublicApi
private static class Frame
{
private static final AtomicInteger uniqueId = new AtomicInteger(0);
@@ -163,7 +179,8 @@ public class TransformerDebug
private final String fromUrl;
private final String sourceMimetype;
private final String targetMimetype;
private final TransformationOptions options;
private final NodeRef sourceNodeRef;
private final String renditionName;
private final boolean origDebugOutput;
private long start;
@@ -176,7 +193,7 @@ public class TransformerDebug
private String transformerName;
private Frame(Frame parent, String transformerName, String fromUrl, String sourceMimetype, String targetMimetype,
long sourceSize, TransformationOptions options, Call pushCall, boolean origDebugOutput)
long sourceSize, String renditionName, NodeRef sourceNodeRef, Call pushCall, boolean origDebugOutput)
{
this.id = -1;
this.parent = parent;
@@ -185,7 +202,8 @@ public class TransformerDebug
this.sourceMimetype = sourceMimetype;
this.targetMimetype = targetMimetype;
this.sourceSize = sourceSize;
this.options = options;
this.renditionName = renditionName;
this.sourceNodeRef = sourceNodeRef;
this.callType = pushCall;
this.origDebugOutput = origDebugOutput;
start = System.currentTimeMillis();
@@ -232,7 +250,6 @@ public class TransformerDebug
}
@Deprecated
@AlfrescoPublicApi
private class UnavailableTransformer implements Comparable<UnavailableTransformer>
{
private final String name;
@@ -283,26 +300,49 @@ public class TransformerDebug
}
}
private final NodeService nodeService;
private final MimetypeService mimetypeService;
private final ContentTransformerRegistry transformerRegistry;
private final TransformerConfig transformerConfig;
private ContentService contentService;
public void setTransformerLog(Log transformerLog)
{
info = new LogTee(LogFactory.getLog(TransformerLog.class), transformerLog);
}
/**
* Constructor
*/
public TransformerDebug(NodeService nodeService, MimetypeService mimetypeService,
ContentTransformerRegistry transformerRegistry, TransformerConfig transformerConfig,
Log transformerLog, Log transformerDebugLog)
public void setTransformerDebugLog(Log transformerDebugLog)
{
logger = new LogTee(LogFactory.getLog(TransformerDebug.class), transformerDebugLog);
}
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
this.mimetypeService = mimetypeService;
this.transformerRegistry = transformerRegistry;
this.transformerConfig = transformerConfig;
}
logger = new LogTee(LogFactory.getLog(TransformerDebug.class), transformerDebugLog);
info = new LogTee(LogFactory.getLog(TransformerLog.class), transformerLog);
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;
}
public void setContentService(ContentService contentService)
@@ -310,37 +350,135 @@ public class TransformerDebug
this.contentService = contentService;
}
/**
* Called prior to working out what transformers are available.
*/
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)
{
if (isEnabled())
{
push(null, fromUrl, sourceMimetype, targetMimetype, -1, options, Call.AVAILABLE);
push(null, fromUrl, sourceMimetype, targetMimetype, -1, renditionName,
sourceNodeRef, 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, TransformationOptions options)
String targetMimetype, long sourceSize, String renditionName, NodeRef sourceNodeRef)
{
if (isEnabled())
{
push(getName(transformer), fromUrl, sourceMimetype, targetMimetype, sourceSize,
options, Call.TRANSFORM);
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);
}
}
@@ -353,13 +491,14 @@ public class TransformerDebug
{
if (isEnabled())
{
push(null, null, null, null, -1, null, Call.AVAILABLE);
push(null, null, null, null, -1, null, null, Call.AVAILABLE);
}
}
/**
* Called prior to calling a nested isTransformable.
*/
@Deprecated
public void pushIsTransformableSize(ContentTransformer transformer)
{
if (isEnabled())
@@ -369,7 +508,7 @@ public class TransformerDebug
}
private void push(String transformerName, String fromUrl, String sourceMimetype, String targetMimetype,
long sourceSize, TransformationOptions options, Call callType)
long sourceSize, String renditionName, NodeRef sourceNodeRef, Call callType)
{
Deque<Frame> ourStack = ThreadInfo.getStack();
Frame frame = ourStack.peek();
@@ -383,13 +522,14 @@ public class TransformerDebug
// 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, options, callType, origDebugOutput);
frame = new Frame(frame, transformerName, fromUrl, sourceMimetype, targetMimetype, sourceSize, renditionName,
sourceNodeRef, callType, origDebugOutput);
ourStack.push(frame);
if (callType == Call.TRANSFORM)
{
// Log the basic info about this transformation
logBasicDetails(frame, sourceSize, options.getUse(), transformerName, (ourStack.size() == 1));
logBasicDetails(frame, sourceSize, renditionName, transformerName, (ourStack.size() == 1));
}
}
@@ -397,6 +537,7 @@ public class TransformerDebug
* 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())
@@ -421,11 +562,21 @@ public class TransformerDebug
}
}
@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,
TransformationOptions options, String calledFrom)
String renditionName, NodeRef sourceNodeRef, String calledFrom)
{
if (isEnabled())
{
@@ -447,7 +598,7 @@ public class TransformerDebug
frame.setSourceSize(sourceSize);
// Log the basic info about this transformation
logBasicDetails(frame, sourceSize, options.getUse(),
logBasicDetails(frame, sourceSize, renditionName,
calledFrom + ((transformers.size() == 0) ? " NO transformers" : ""), firstLevel);
// Report available and unavailable transformers
@@ -457,7 +608,11 @@ public class TransformerDebug
{
String name = getName(trans);
int padName = longestNameLength - name.length() + 1;
long maxSourceSizeKBytes = trans.getMaxSourceSizeKBytes(frame.sourceMimetype, frame.targetMimetype, frame.options);
// 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);
String size = maxSourceSizeKBytes > 0 ? "< "+fileSize(maxSourceSizeKBytes*1024) : "";
int padSize = 10 - size.length();
String priority = gePriority(trans, frame.sourceMimetype, frame.targetMimetype);
@@ -491,11 +646,13 @@ public class TransformerDebug
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)
{
@@ -511,6 +668,7 @@ public class TransformerDebug
(maxSourceSizeKBytes == 0 ? " disabled" : ""));
}
@Deprecated
public void activeTransformer(String sourceMimetype, String targetMimetype,
int transformerCount, ContentTransformer transformer, long maxSourceSizeKBytes,
boolean firstTransformer)
@@ -548,7 +706,7 @@ public class TransformerDebug
return longestNameLength;
}
private void logBasicDetails(Frame frame, long sourceSize, String use, String message, boolean firstLevel)
private void logBasicDetails(Frame frame, long sourceSize, String renditionName, 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))
@@ -557,14 +715,14 @@ public class TransformerDebug
}
log(frame.sourceMimetype+' '+frame.targetMimetype, false);
String fileName = getFileName(frame.options, firstLevel, sourceSize);
String fileName = getFileName(frame.sourceNodeRef, firstLevel, sourceSize);
log(getMimetypeExt(frame.sourceMimetype)+getMimetypeExt(frame.targetMimetype) +
((fileName != null) ? fileName+' ' : "")+
((sourceSize >= 0) ? fileSize(sourceSize)+' ' : "") +
(firstLevel && use != null ? "-- "+use+" -- " : "") + message);
(firstLevel && renditionName != null ? "-- "+renditionName+" -- " : "") + message);
if (firstLevel)
{
String nodeRef = getNodeRef(frame.options, firstLevel, sourceSize);
String nodeRef = getNodeRef(frame.sourceNodeRef, firstLevel, sourceSize);
if (!nodeRef.isEmpty())
{
log(nodeRef);
@@ -659,7 +817,7 @@ public class TransformerDebug
boolean firstLevel = size == 1;
String sourceExt = getMimetypeExt(frame.sourceMimetype);
String targetExt = getMimetypeExt(frame.targetMimetype);
String fileName = getFileName(frame.options, firstLevel, frame.sourceSize);
String fileName = getFileName(frame.sourceNodeRef, firstLevel, frame.sourceSize);
long sourceSize = frame.getSourceSize();
String transformerName = frame.getTransformerName();
String level = null;
@@ -893,9 +1051,11 @@ public class TransformerDebug
* @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 use to which the transformation will be put (such as "Index", "Preview", null).
* @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.
*/
public String transformationsByTransformer(String transformerName, boolean toString, boolean format42, String use)
@Deprecated
public String transformationsByTransformer(String transformerName, boolean toString, boolean format42, String renditionName)
{
// Do not generate this type of debug if already generating other debug to a StringBuilder
// (for example a test transform).
@@ -915,7 +1075,7 @@ public class TransformerDebug
: mimetypeService.getMimetypes();
TransformationOptions options = new TransformationOptions();
options.setUse(use);
options.setUse(renditionName);
StringBuilder sb = null;
try
{
@@ -977,10 +1137,12 @@ public class TransformerDebug
* level transformers.
* @param onlyNonDeterministic if true only report transformations where there is more than
* one transformer available with the same priority.
* @param use to which the transformation will be put (such as "Index", "Preview", null).
* @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.
*/
@Deprecated
public String transformationsByExtension(String sourceExtension, String targetExtension, boolean toString,
boolean format42, boolean onlyNonDeterministic, String use)
boolean format42, boolean onlyNonDeterministic, String renditionName)
{
// Do not generate this type of debug if already generating other debug to a StringBuilder
// (for example a test transform).
@@ -1000,7 +1162,7 @@ public class TransformerDebug
: mimetypeService.getMimetypes();
TransformationOptions options = new TransformationOptions();
options.setUse(use);
options.setUse(renditionName);
StringBuilder sb = null;
try
{
@@ -1248,24 +1410,30 @@ public class TransformerDebug
return !transformerRegistry.getTransformers().contains(transformer);
}
@Deprecated
public String getFileName(TransformationOptions options, boolean firstLevel, long sourceSize)
{
return getFileNameOrNodeRef(options, firstLevel, sourceSize, true);
NodeRef sourceNodeRef = options == null ? null : options.getSourceNodeRef();
return getFileName(sourceNodeRef, firstLevel, sourceSize);
}
private String getNodeRef(TransformationOptions options, boolean firstLevel, long sourceSize)
public String getFileName(NodeRef sourceNodeRef, boolean firstLevel, long sourceSize)
{
return getFileNameOrNodeRef(options, firstLevel, sourceSize, false);
return getFileNameOrNodeRef(sourceNodeRef, firstLevel, sourceSize, true);
}
private String getFileNameOrNodeRef(TransformationOptions options, boolean firstLevel, long sourceSize, boolean getName)
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)
{
String result = getName ? null : "";
if (options != null)
if (sourceNodeRef != null)
{
try
{
NodeRef sourceNodeRef = options.getSourceNodeRef();
result = getName
? (String)nodeService.getProperty(sourceNodeRef, ContentModel.PROP_NAME)
: sourceNodeRef.toString()+" ";
@@ -1368,7 +1536,9 @@ public class TransformerDebug
* @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)
@@ -1389,13 +1559,14 @@ public class TransformerDebug
* Debugs a request to the Transform Service
*/
public int debugTransformServiceRequest(String sourceMimetype, long sourceSize, NodeRef sourceNodeRef,
int contentHashcode, String fileName, String targetMimetype, String use)
int contentHashcode, String fileName, String targetMimetype,
String renditionName)
{
pushMisc();
debug(getMimetypeExt(sourceMimetype)+getMimetypeExt(targetMimetype) +
((fileName != null) ? fileName+' ' : "")+
((sourceSize >= 0) ? fileSize(sourceSize)+' ' : "") +
(use != null ? "-- "+use+" -- " : "") + " RenditionService2");
(renditionName != null ? "-- "+renditionName+" -- " : "") + " RenditionService2");
debug(sourceNodeRef.toString() + ' ' +contentHashcode);
debug(" **a) [01] TransformService");
return pop(Call.AVAILABLE, true, false);
@@ -1426,35 +1597,19 @@ public class TransformerDebug
pop(Call.AVAILABLE, suppressFinish, true);
}
public String testTransform(String sourceExtension, String targetExtension, String use)
public String testTransform(String sourceExtension, String targetExtension, String renditionName)
{
return new TestTransform()
{
protected void transform(ContentReader reader, ContentWriter writer, TransformationOptions options)
{
contentService.transform(reader, writer, options);
}
}.run(sourceExtension, targetExtension, use);
return new TestTransform().run(sourceExtension, targetExtension, renditionName);
}
/**
* @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 use)
String targetExtension, String renditionName)
{
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);
return "The testTransform operation for a specific transformer is no longer supported.";
}
public String[] getTestFileExtensionsAndMimetypes()
@@ -1499,68 +1654,58 @@ public class TransformerDebug
}
@Deprecated
@AlfrescoPublicApi
private abstract class TestTransform
private class TestTransform
{
String run(String sourceExtension, String targetExtension, String use)
protected LinkedList<NodeRef> nodesToDeleteAfterTest = new LinkedList<NodeRef>();
String run(String sourceExtension, String targetExtension, String renditionName)
{
String debug;
RenditionDefinitionRegistry2Impl renditionDefinitionRegistry2 = getRenditionDefinitionRegistry2Impl();
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);
long sourceSize = reader.getSize();
TransformationOptions options = new TransformationOptions();
options.setUse(use);
debug = isTransformable(sourceMimetype, sourceSize, targetMimetype, options);
if (debug == null)
{
String testRenditionName = "testTransform"+System.currentTimeMillis();
NodeRef sourceNodeRef = null;
StringBuilder sb = new StringBuilder();
try
{
setStringBuilder(sb);
transform(reader, writer, options);
}
catch (AlfrescoRuntimeException e)
RenditionDefinition2 renditionDefinition = new RenditionDefinition2Impl(testRenditionName, targetMimetype,
Collections.emptyMap(), renditionDefinitionRegistry2);
sourceNodeRef = createSourceNode(sourceExtension, sourceMimetype);
ContentData contentData = (ContentData) nodeService.getProperty(sourceNodeRef, ContentModel.PROP_CONTENT);
if (contentData != null)
{
sb.append(e.getMessage());
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);
}
}
}
finally
{
setStringBuilder(null);
renditionDefinitionRegistry2.unregister(testRenditionName);
deleteSourceNode(sourceNodeRef);
}
debug = sb.toString();
}
return debug;
return sb.toString();
}
private String getMimetype(String extension, boolean isSource)
@@ -1581,11 +1726,57 @@ public class TransformerDebug
return mimetype;
}
protected String isTransformable(String sourceMimetype, long sourceSize, String targetMimetype, TransformationOptions options)
public NodeRef createSourceNode(String extension, String sourceMimetype)
{
return null;
// 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;
}
protected abstract void transform(ContentReader reader, ContentWriter writer, TransformationOptions options);
public void deleteSourceNode(NodeRef sourceNodeRef)
{
if (sourceNodeRef != null)
{
getTransactionService().getRetryingTransactionHelper().doInTransaction(
(RetryingTransactionHelper.RetryingTransactionCallback<Void>) () ->
{
if (nodeService.exists(sourceNodeRef))
{
nodeService.deleteNode(sourceNodeRef);
}
return null;
});
}
}
}
}

View File

@@ -30,16 +30,12 @@ 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 complex (compound) transformer
* and has been asked to transform a file that is too large (see transformation limits) as the
* 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
* 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,6 +81,8 @@ public class ImageMagickContentTransformerWorker extends AbstractImageMagickCont
/** the system command executer */
private RuntimeExec executer;
private boolean enabled = true;
/** the check command executer */
private RuntimeExec checkCommand;
@@ -116,6 +118,11 @@ 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.
@@ -145,6 +152,8 @@ public class ImageMagickContentTransformerWorker extends AbstractImageMagickCont
*/
@Override
public void afterPropertiesSet()
{
if (enabled)
{
if (!remoteTransformerClientConfigured() && executer == null)
{
@@ -180,13 +189,13 @@ public class ImageMagickContentTransformerWorker extends AbstractImageMagickCont
{
setAvailable(true);
versionString = result.getSecond().trim();
logger.info("Using remote ImageMagick: "+versionString);
logger.info("Using legacy local ImageMagick: " + versionString);
}
else
{
setAvailable(false);
versionString = "unknown";
String message = "Remote ImageMagick is not available for transformations. " + result.getSecond();
String message = "Leacy remote ImageMagick is not available for transformations. " + result.getSecond();
if (isAvailable == null)
{
logger.debug(message);
@@ -198,6 +207,7 @@ public class ImageMagickContentTransformerWorker extends AbstractImageMagickCont
}
}
}
}
/**
* Transform the image content from the source file to the target file

View File

@@ -77,6 +77,8 @@ public class AlfrescoPdfRendererContentTransformerWorker extends ContentTransfor
/** the system command executer */
private RuntimeExec executer;
private boolean enabled = true;
/** the check command executer */
private RuntimeExec checkCommand;
@@ -110,6 +112,11 @@ 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.
*
@@ -140,6 +147,8 @@ public class AlfrescoPdfRendererContentTransformerWorker extends ContentTransfor
@Override
public void afterPropertiesSet()
{
if (enabled)
{
PropertyCheck.mandatory(this, "executer", executer);
PropertyCheck.mandatory(this, "isAvailable", checkCommand);
@@ -154,12 +163,12 @@ public class AlfrescoPdfRendererContentTransformerWorker extends ContentTransfor
{
versionString = result.getSecond();
setAvailable(true);
logger.info("Using remote Alfresco PDF Renderer: "+versionString);
logger.info("Using legacy local Alfresco PDF Renderer: " + versionString);
}
else
{
setAvailable(false);
String message = "Remote Alfresco PDF Renderer is not available for transformations. " + result.getSecond();
String message = "Legacy local Alfresco PDF Renderer is not available for transformations. " + result.getSecond();
if (isAvailable == null)
{
logger.debug(message);
@@ -178,6 +187,7 @@ public class AlfrescoPdfRendererContentTransformerWorker extends ContentTransfor
logger.debug(e);
}
}
}
/**
* @return Returns true if the transformer is functioning otherwise false

View File

@@ -37,6 +37,7 @@ 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;
@@ -52,9 +53,9 @@ import java.util.concurrent.Executors;
* @author adavis
*/
@Deprecated
public class LegacyLocalTransformClient extends AbstractTransformClient implements TransformClient
public class LegacyTransformClient implements TransformClient, InitializingBean
{
private static Log logger = LogFactory.getLog(LegacyLocalTransformClient.class);
private static Log logger = LogFactory.getLog(LegacyTransformClient.class);
private TransactionService transactionService;
@@ -94,7 +95,7 @@ public class LegacyLocalTransformClient extends AbstractTransformClient implemen
@Override
public void afterPropertiesSet() throws Exception
{
super.afterPropertiesSet();
PropertyCheck.mandatory(this, "transactionService", transactionService);
PropertyCheck.mandatory(this, "contentService", contentService);
PropertyCheck.mandatory(this, "renditionService2", renditionService2);
PropertyCheck.mandatory(this, "converter", converter);
@@ -144,7 +145,7 @@ public class LegacyLocalTransformClient extends AbstractTransformClient implemen
TransformationOptions transformationOptions = converter.getTransformationOptions(renditionName, options);
transformationOptions.setSourceNodeRef(sourceNodeRef);
ContentReader reader = LegacyLocalTransformClient.this.contentService.getReader(sourceNodeRef, ContentModel.PROP_CONTENT);
ContentReader reader = LegacyTransformClient.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 LegacyLocalTransformServiceRegistry extends AbstractTransformServiceRegistry implements InitializingBean
public class LegacyTransformServiceRegistry extends AbstractTransformServiceRegistry implements InitializingBean
{
private ContentService contentService;
private TransformationOptionsConverter converter;
@@ -85,15 +85,22 @@ public class LegacyLocalTransformServiceRegistry extends AbstractTransformServic
if (firstTime)
{
firstTime = false;
transformerDebug.debug("Local legacy transformers are " + (enabled ? "enabled" : "disabled"));
transformerDebug.debug("Legacy transforms 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.
}
}
return maxSize;
}
}

View File

@@ -0,0 +1,177 @@
/*
* #%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;
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,16 +49,18 @@ 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 renditionDefinitions.get(renditionName);
return getRenditionDefinition(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 = new ThreadLocal<>();
private ThreadLocal<Boolean> usePrimary = ThreadLocal.withInitial(()->Boolean.FALSE);
public SwitchingTransformClient(TransformClient primary, TransformClient secondary)
{

View File

@@ -166,6 +166,7 @@ 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 - 2018 Alfresco Software Limited
* Copyright (C) 2005 - 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
@@ -26,10 +26,21 @@
package org.alfresco.transform.client.model.config;
/**
* 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.
* Abstract implementation of TransformOption.
*/
public interface ExtensionMap
public abstract class AbstractTransformOption implements TransformOption
{
String toMimetype(String extension);
private boolean required;
@Override
public boolean isRequired()
{
return required;
}
@Override
public void setRequired(boolean required)
{
this.required = required;
}
}

View File

@@ -0,0 +1,273 @@
/*
* #%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 - 2018 Alfresco Software Limited
* Copyright (C) 2005 - 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
@@ -31,29 +31,36 @@ package org.alfresco.transform.client.model.config;
*/
public class SupportedSourceAndTarget
{
private String sourceExt;
private String sourceMediaType;
private long maxSourceSizeBytes = -1;
private String targetExt;
private String targetMediaType;
private int priority = 50;
public SupportedSourceAndTarget()
{
}
public SupportedSourceAndTarget(String sourceExt, String targetExt, long maxSourceSizeBytes)
public SupportedSourceAndTarget(String sourceMediaType, String targetMediaType, long maxSourceSizeBytes)
{
setSourceExt(sourceExt);
this(sourceMediaType, targetMediaType, maxSourceSizeBytes, 50);
}
public SupportedSourceAndTarget(String sourceMediaType, String targetMediaType, long maxSourceSizeBytes, int priority)
{
setSourceMediaType(sourceMediaType);
setMaxSourceSizeBytes(maxSourceSizeBytes);
setTargetExt(targetExt);
setTargetMediaType(targetMediaType);
setPriority(priority);
}
public String getSourceExt()
public String getSourceMediaType()
{
return sourceExt;
return sourceMediaType;
}
public void setSourceExt(String sourceExt)
public void setSourceMediaType(String sourceMediaType)
{
this.sourceExt = sourceExt;
this.sourceMediaType = sourceMediaType;
}
public long getMaxSourceSizeBytes()
@@ -66,13 +73,23 @@ public class SupportedSourceAndTarget
this.maxSourceSizeBytes = maxSourceSizeBytes;
}
public String getTargetExt()
public String getTargetMediaType()
{
return targetExt;
return targetMediaType;
}
public void setTargetExt(String targetExt)
public void setTargetMediaType(String targetMediaType)
{
this.targetExt = targetExt;
this.targetMediaType = targetMediaType;
}
public int getPriority()
{
return priority;
}
public void setPriority(int priority)
{
this.priority = priority;
}
}

View File

@@ -2,7 +2,7 @@
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2018 Alfresco Software Limited
* Copyright (C) 2005 - 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

View File

@@ -30,11 +30,12 @@ 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. The top
* optional or required based on their own setting alone.
*
* In a pipeline transformation, a group of options
*/
public class TransformOptionGroup implements TransformOption
public class TransformOptionGroup extends AbstractTransformOption
{
private boolean required;
List<TransformOption> transformOptions;
public TransformOptionGroup()
@@ -47,18 +48,6 @@ public class TransformOptionGroup implements TransformOption
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,9 +28,8 @@ package org.alfresco.transform.client.model.config;
/**
* Represents a single transformation option.
*/
public class TransformOptionValue implements TransformOption
public class TransformOptionValue extends AbstractTransformOption
{
private boolean required;
private String name;
public TransformOptionValue()
@@ -43,18 +42,6 @@ public class TransformOptionValue implements TransformOption
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,6 +27,7 @@ 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;
@@ -44,38 +45,36 @@ import static org.alfresco.repo.rendition2.RenditionDefinition2.TIMEOUT;
/**
* Used by clients to work out if a transformation is supported by the Transform Service.
*/
public class TransformServiceRegistryImpl implements TransformServiceRegistry, InitializingBean
public abstract class TransformServiceRegistryImpl implements TransformServiceRegistry, InitializingBean
{
class SupportedTransform
{
TransformOptionGroup transformOptions;
private long maxSourceSizeBytes;
long maxSourceSizeBytes;
private String name;
private int priority;
public SupportedTransform(List<TransformOption> transformOptions, long maxSourceSizeBytes)
public SupportedTransform(String name, List<TransformOption> transformOptions, long maxSourceSizeBytes, int priority)
{
// 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, Long>> cachedMaxSizes = new ConcurrentHashMap<>();
ConcurrentMap<String, ConcurrentMap<String, List<SupportedTransform>>> cachedSupportedTransformList = new ConcurrentHashMap<>();
public void setJsonObjectMapper(ObjectMapper jsonObjectMapper)
{
this.jsonObjectMapper = jsonObjectMapper;
}
public void setExtensionMap(ExtensionMap extensionMap)
{
this.extensionMap = extensionMap;
}
@Override
public void afterPropertiesSet() throws Exception
{
@@ -83,30 +82,21 @@ public class TransformServiceRegistryImpl implements TransformServiceRegistry, I
{
throw new IllegalStateException("jsonObjectMapper has not been set");
}
if (extensionMap == null)
{
throw new IllegalStateException("extensionMap has not been set");
}
cachedSupportedTransformList.clear();
transformers.clear();
}
private String toMimetype(String ext)
{
String mimetype = extensionMap.toMimetype(ext);
if (mimetype == null)
{
throw new IllegalArgumentException("The mimetype for the file extension "+ext+" cannot be looked up by: "+
extensionMap.getClass().getName());
}
return mimetype;
}
protected abstract Log getLog();
public void register(Transformer transformer)
public void register(String path) throws IOException
{
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())));
JsonConverter jsonConverter = new JsonConverter(getLog());
jsonConverter.addJsonSource(path);
List<Transformer> transformers = jsonConverter.getTransformers();
for (Transformer transformer : transformers)
{
register(transformer);
}
}
public void register(Reader reader) throws IOException
@@ -115,31 +105,78 @@ public class TransformServiceRegistryImpl implements TransformServiceRegistry, I
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 transformName)
Map<String, String> actualOptions, String renditionName)
{
long maxSize = getMaxSize(sourceMimetype, targetMimetype, actualOptions, transformName);
long maxSize = getMaxSize(sourceMimetype, targetMimetype, actualOptions, renditionName);
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 transformName)
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)
{
if (actualOptions == null)
{
actualOptions = Collections.EMPTY_MAP;
}
if (transformName != null && transformName.trim().isEmpty())
if (renditionName != null && renditionName.trim().isEmpty())
{
transformName = null;
renditionName = null;
}
Long maxSize = transformName == null ? null : cachedMaxSizes.computeIfAbsent(transformName, k -> new ConcurrentHashMap<>()).get(sourceMimetype);
if (maxSize != null)
List<SupportedTransform> transformListBySize = renditionName == null ? null
: cachedSupportedTransformList.computeIfAbsent(renditionName, k -> new ConcurrentHashMap<>()).get(sourceMimetype);
if (transformListBySize != null)
{
return maxSize.longValue();
return transformListBySize;
}
// Remove the "timeout" property from the actualOptions as it is not used to select a transformer.
@@ -149,7 +186,7 @@ public class TransformServiceRegistryImpl implements TransformServiceRegistry, I
actualOptions.remove(TIMEOUT);
}
long calculatedMaxSize = 0;
transformListBySize = new ArrayList<>();
ConcurrentMap<String, List<SupportedTransform>> targetMap = transformers.get(sourceMimetype);
if (targetMap != null)
{
@@ -163,24 +200,66 @@ public class TransformServiceRegistryImpl implements TransformServiceRegistry, I
addToPossibleTransformOptions(possibleTransformOptions, transformOptions, true, actualOptions);
if (isSupported(possibleTransformOptions, actualOptions))
{
if (supportedTransform.maxSourceSizeBytes < 0)
addToSupportedTransformList(transformListBySize, supportedTransform);
}
}
}
}
if (renditionName != null)
{
calculatedMaxSize = -1;
break;
cachedSupportedTransformList.get(renditionName).put(sourceMimetype, transformListBySize);
}
calculatedMaxSize = Math.max(calculatedMaxSize, supportedTransform.maxSourceSizeBytes);
}
}
}
return transformListBySize;
}
if (transformName != null)
// 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)
{
cachedMaxSizes.get(transformName).put(sourceMimetype, calculatedMaxSize);
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);
}
return calculatedMaxSize;
// 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;
}
/**

View File

@@ -0,0 +1,66 @@
/*
* #%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 - 2018 Alfresco Software Limited
* Copyright (C) 2005 - 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
@@ -26,28 +26,34 @@
package org.alfresco.transform.client.model.config;
import java.util.List;
import java.util.Objects;
import org.alfresco.transform.client.model.config.TransformServiceRegistry;
/**
* 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
* 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
* 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 change client data structures other
* transformations which allows new transformations to be added without the need to 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>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>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>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 name;
private String version;
private String transformerName;
private List<TransformStep> transformerPipeline;
private List<TransformOption> transformOptions;
private List<SupportedSourceAndTarget> supportedSourceAndTargetList;
@@ -55,32 +61,37 @@ public class Transformer
{
}
public Transformer(String name, String version, List<TransformOption> transformOptions, List<SupportedSourceAndTarget> supportedSourceAndTargetList)
public Transformer(String transformerName, List<TransformOption> transformOptions, List<SupportedSourceAndTarget> supportedSourceAndTargetList)
{
setName(name);
setVersion(version);
setTransformerName(transformerName);
setTransformOptions(transformOptions);
setSupportedSourceAndTargetList(supportedSourceAndTargetList);
}
public String getName()
public Transformer(String transformerName, List<TransformStep> transformerPipeline, List<TransformOption> transformOptions, List<SupportedSourceAndTarget> supportedSourceAndTargetList)
{
return name;
this(transformerName, transformOptions, supportedSourceAndTargetList);
setTransformerPipeline(transformerPipeline);
}
public void setName(String name)
public String getTransformerName()
{
this.name = name;
return transformerName;
}
public String getVersion()
public void setTransformerName(String transformerName)
{
return version;
this.transformerName = transformerName;
}
public void setVersion(String version)
public List<TransformStep> getTransformerPipeline()
{
this.version = version;
return transformerPipeline;
}
public void setTransformerPipeline(List<TransformStep> transformerPipeline)
{
this.transformerPipeline = transformerPipeline;
}
public List<TransformOption> getTransformOptions()

View File

@@ -328,33 +328,18 @@
<constructor-arg>
<ref bean="transformerSelector"/>
</constructor-arg>
<property name="enabled" value="${local.transform.service.enabled}" />
<property name="enabled" value="${legacy.transform.service.enabled}" />
<property name="transformerDebug" ref="transformerDebug" />
</bean>
<!-- Transformation Debug -->
<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>
<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>
<!-- Import the transformer configuration from the transformers subsystem -->
@@ -489,6 +474,7 @@
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,9 +71,20 @@
<!-- Replaced in the enterprise edition -->
<bean id="transformClient" parent="localTransformClient"/>
<bean id="localTransformClient" class="org.alfresco.repo.rendition2.LegacyLocalTransformClient">
<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">
<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" />
@@ -91,10 +102,28 @@
<!-- Replaced in the enterprise edition -->
<bean id="transformServiceRegistry" parent="localTransformServiceRegistry"/>
<bean id="localTransformServiceRegistry" class="org.alfresco.repo.rendition2.LegacyLocalTransformServiceRegistry" >
<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" >
<property name="contentService" ref="contentService" />
<property name="converter" ref="transformOptionsConverter" />
<property name="enabled" value="${local.transform.service.enabled}" />
<property name="enabled" value="${legacy.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
# Remote server (or docker container) url used to service imagemagick requests.
# Legacy imageMagick transformer url to T-Engine to service transform requests via http. Disabled by default.
img.url=
# When img.url is set, this value indicates the amount of time to wait after a connection failure
@@ -611,13 +611,26 @@ system.thumbnail.redeployStaticDefsOnStartup=true
# The default timeout for metadata mapping extracters
content.metadataExtracter.default.timeoutMs=20000
# Remote server (or docker container) url used to service tika requests.
# Legacy tika transformer url to T-Engines to service transform requests via http. Disabled by default.
tika.url=
# When tika.url is set, this value indicates the amount of time to wait after a connection failure
# When the legacy tika 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.
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
@@ -1065,6 +1078,9 @@ 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.
@@ -1074,13 +1090,15 @@ local.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 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.
# 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.
#
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
@@ -1258,4 +1276,3 @@ messaging.subsystem.autoStart=true
# Raw events
acs.repo.rendition.events.endpoint=jms:acs-repo-rendition-events?jmsMessageType=Text

View File

@@ -53,6 +53,7 @@
<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,6 +61,7 @@
</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,58 +1,20 @@
[
{
"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": [
{
"transformOptions": {
"tikaOptions": [
{"value": {"name": "transform"}},
{"value": {"name": "includeContents"}},
{"value": {"name": "notExtractBookmarksText"}},
{"value": {"name": "targetMimetype"}},
{"value": {"name": "targetEncoding"}}
],
"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": [
"pdfrendererOptions": [
{"value": {"name": "page"}},
{"value": {"name": "width"}},
{"value": {"name": "height"}},
{"value": {"name": "allowPdfEnlargement"}},
{"value": {"name": "maintainPdfAspectRatio"}}
],
"supportedSourceAndTargetList": [
{"sourceExt": "pdf", "targetExt": "png" }
]
},
{
"name": "imageMagick",
"version": "1",
"transformOptions": [
"imagemagickOptions": [
{"value": {"name": "alphaRemove"}},
{"value": {"name": "autoOrient"}},
{"value": {"name": "startPage"}},
@@ -73,103 +35,110 @@
{"value": {"name": "allowEnlargement"}},
{"value": {"name": "maintainAspectRatio"}}
]}}
],
]
},
"transformers": [
{
"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"}
{"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"}
]
},
{
"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": "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"},
{"sourceExt": "xls", "targetExt": "gif" },
{"sourceExt": "xls", "targetExt": "jpeg"},
{"sourceExt": "xls", "targetExt": "png" },
{"sourceExt": "xls", "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": "ppt", "targetExt": "gif" },
{"sourceExt": "ppt", "targetExt": "jpeg"},
{"sourceExt": "ppt", "targetExt": "png" },
{"sourceExt": "ppt", "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": "docx", "targetExt": "gif" },
{"sourceExt": "docx", "targetExt": "jpeg"},
{"sourceExt": "docx", "targetExt": "png" },
{"sourceExt": "docx", "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": "xlsx", "targetExt": "gif" },
{"sourceExt": "xlsx", "targetExt": "jpeg"},
{"sourceExt": "xlsx", "targetExt": "png" },
{"sourceExt": "xlsx", "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": "pptx", "targetExt": "gif" },
{"sourceExt": "pptx", "targetExt": "jpeg"},
{"sourceExt": "pptx", "targetExt": "png" },
{"sourceExt": "pptx", "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": "msg", "targetExt": "gif" },
{"sourceExt": "msg", "targetExt": "jpeg"},
{"sourceExt": "msg", "targetExt": "png" },
{"sourceExt": "msg", "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"
]
}
]
]
}

View File

@@ -0,0 +1,53 @@
{
"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

@@ -0,0 +1,29 @@
{
"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

@@ -0,0 +1,22 @@
{
"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

@@ -0,0 +1,18 @@
{
"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

@@ -0,0 +1,52 @@
{
"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,7 +200,8 @@ 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.repo.rendition2.RenditionService2Test.class,
org.alfresco.transform.client.model.config.TransformServiceRegistryImplTest.class
})
public class AllUnitTestsSuite
{

View File

@@ -47,11 +47,18 @@ 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.LegacyLocalTransformClientIntegrationTest.class,
org.alfresco.repo.rendition2.LegacyLocalTransformServiceRegistryTest.class,
org.alfresco.repo.rendition2.RenditionTest.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.solr.SOLRTrackingComponentTest.class,
org.alfresco.repo.tagging.TaggingServiceImplTest.class,
org.alfresco.repo.transaction.AlfrescoTransactionSupportTest.class,
@@ -64,6 +71,7 @@ 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,10 +41,7 @@ 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,10 +49,7 @@ 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
@@ -68,7 +65,7 @@ public class TransformerDebugTest
private TransformerConfig transformerConfig;
@Mock
private TransformationOptions options;
private TransformClient transformClient;
@Mock
private AbstractContentTransformerLimits transformer1;
@@ -108,7 +105,14 @@ public class TransformerDebugTest
when(transformer3.getName()).thenReturn("transformer3");
when(transformer4.getName()).thenReturn("transformer4");
transformerDebug = new TransformerDebug(nodeService, mimetypeService, transformerRegistry, transformerConfig, log, debug);
transformerDebug = new TransformerDebug();
transformerDebug.setNodeService(nodeService);
transformerDebug.setMimetypeService(mimetypeService);
transformerDebug.setTransformerRegistry(transformerRegistry);
transformerDebug.setTransformerConfig(transformerConfig);
transformerDebug.setTransformerLog(log);
transformerDebug.setTransformerDebugLog(debug);
transformerDebug.setTransformClient(transformClient);
log.setTransformerDebug(transformerDebug);
log.setTransformerConfig(transformerConfig);
@@ -151,7 +155,7 @@ public class TransformerDebugTest
{
long sourceSize = 1024*1024*3/2;
transformerDebug.pushAvailable("sourceUrl", "application/pdf", "text/plain", options);
transformerDebug.pushAvailable("sourceUrl", "application/pdf", "text/plain", null, null);
transformerDebug.unavailableTransformer(transformer1, "application/pdf", "text/plain", 50);
transformerDebug.unavailableTransformer(transformer2, "application/pdf", "text/plain", 0);
@@ -160,7 +164,7 @@ public class TransformerDebugTest
List<ContentTransformer> transformers = Arrays.asList(new ContentTransformer[] {});
transformerDebug.availableTransformers(transformers, sourceSize, options, "ContentService.transform(...)");
transformerDebug.availableTransformers(transformers, sourceSize, null, null, "ContentService.transform(...)");
transformerDebug.popAvailable();

View File

@@ -39,10 +39,7 @@ 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,6 +36,7 @@ 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}
@@ -51,6 +52,7 @@ public class TransactionAwareEventProducerTest extends BaseSpringTest
@Autowired
private TransactionAwareEventProducer eventProducer;
@Autowired
@Qualifier("alfrescoEventObjectMapper")
private ObjectMapper messagingObjectMapper;
@Test

View File

@@ -28,6 +28,7 @@ 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;
@@ -44,7 +45,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.util.ApplicationContextHelper;
import org.alfresco.transform.client.model.config.TransformServiceRegistry;
import org.alfresco.util.BaseSpringTest;
import org.alfresco.util.GUID;
import org.alfresco.util.PropertyMap;
@@ -72,10 +73,7 @@ public abstract class AbstractRenditionIntegrationTest extends BaseSpringTest
protected RenditionService2Impl renditionService2;
@Autowired
protected RenditionDefinitionRegistry2 renditionDefinitionRegistry2;
@Autowired
protected TransformClient transformClient;
protected RenditionDefinitionRegistry2Impl renditionDefinitionRegistry2;
@Autowired
protected RenditionService renditionService;
@@ -107,6 +105,15 @@ 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";
@@ -115,17 +122,74 @@ public abstract class AbstractRenditionIntegrationTest extends BaseSpringTest
@BeforeClass
public static void before()
{
// Use the docker images for transforms
// Use the docker images for transforms (legacy)
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
@@ -141,6 +205,15 @@ 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

@@ -28,7 +28,6 @@ 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;
@@ -45,11 +44,12 @@ import java.util.Set;
import java.util.StringJoiner;
/**
* Test it is possible to create renditions from the quick files.
* 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.
*
* @author adavis
*/
public class RenditionTest extends AbstractRenditionIntegrationTest
public abstract class AbstractRenditionTest extends AbstractRenditionIntegrationTest
{
// This is the same order as produced by MimetypeMap
public static final List<String> TAS_REST_API_SOURCE_EXTENSIONS = Arrays.asList(
@@ -89,9 +89,7 @@ public class RenditionTest extends AbstractRenditionIntegrationTest
"wpd png avatar32",
"wpd jpg imgpreview");
@Autowired
private TransformServiceRegistry transformServiceRegistry;
@Override
@Before
public void setUp() throws Exception
{
@@ -148,17 +146,15 @@ public class RenditionTest extends AbstractRenditionIntegrationTest
}
else
{
String task = sourceExtension + " " + targetExtension + " " + renditionName;
try
{
checkRendition(testFileName, renditionName, !expectedToFail.contains(sourceTragetRendition));
successes.add(task);
successes.add(sourceTragetRendition);
successCount++;
}
catch (AssertionFailedError e)
{
failures.add(task + " " + e.getMessage());
failures.add(sourceTragetRendition + " " + e.getMessage());
failedCount++;
}
}
@@ -217,48 +213,6 @@ public class RenditionTest extends AbstractRenditionIntegrationTest
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

@@ -25,30 +25,30 @@
*/
package org.alfresco.repo.rendition2;
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;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
/**
* Contains common code used in TransformClients.
* 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
*/
public abstract class AbstractTransformClient implements InitializingBean
@Deprecated
public class LegacyLocalRenditionTest extends AbstractRenditionTest
{
protected NodeService nodeService;
public void setNodeService(NodeService nodeService)
@BeforeClass
public static void before()
{
this.nodeService = nodeService;
AbstractRenditionIntegrationTest.before();
legacyLocal();
}
@Override
public void afterPropertiesSet() throws Exception
@AfterClass
public static void after()
{
PropertyCheck.mandatory(this, "nodeService", nodeService);
AbstractRenditionIntegrationTest.after();
}
}

View File

@@ -0,0 +1,52 @@
/*
* #%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.BeforeClass;
/**
* 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.
*
* @author adavis
*/
public class LegacyRenditionTest extends AbstractRenditionTest
{
@BeforeClass
public static void before()
{
AbstractRenditionIntegrationTest.before();
legacy();
}
@AfterClass
public static void after()
{
AbstractRenditionIntegrationTest.after();
}
}

View File

@@ -0,0 +1,69 @@
/*
* #%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

@@ -0,0 +1,75 @@
/*
* #%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

@@ -0,0 +1,64 @@
/*
* #%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

@@ -30,107 +30,89 @@ 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 LegacyLocalTransformClient}
* Integration tests for {@link LocalTransformClient}
*/
public class LegacyLocalTransformClientIntegrationTest extends AbstractRenditionIntegrationTest
public class LocalTransformClientIntegrationTest 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
{
localCheckRendition("quick.docx", "medium", true);
checkClientRendition("quick.docx", "medium", true);
}
@Test
public void testLocalRenderDocxDoclib() throws Exception
{
localCheckRendition("quick.docx", "doclib", true);
checkClientRendition("quick.docx", "doclib", true);
}
@Test
public void testLocalRenderDocxJpegImgpreview() throws Exception
{
localCheckRendition("quick.docx", "imgpreview", true);
checkClientRendition("quick.docx", "imgpreview", true);
}
@Test
public void testLocalRenderDocxPngAvatar() throws Exception
{
localCheckRendition("quick.docx", "avatar", true);
checkClientRendition("quick.docx", "avatar", true);
}
@Test
public void testLocalRenderDocxPngAvatar32() throws Exception
{
localCheckRendition("quick.docx", "avatar32", true);
checkClientRendition("quick.docx", "avatar32", true);
}
@Test
public void testLocalRenderDocxFlashWebpreview() throws Exception
{
localCheckRendition("quick.docx", "webpreview", false);
checkClientRendition("quick.docx", "webpreview", false);
}
@Test
public void testLocalRenderDocxPdf() throws Exception
{
localCheckRendition("quick.docx", "pdf", false);
checkClientRendition("quick.docx", "pdf", false);
}
private void localCheckRendition(String testFileName, String renditionDefinitionName, boolean expectedToPass) throws InterruptedException
protected void checkClientRendition(String testFileName, String renditionDefinitionName, boolean expectedToPass) throws InterruptedException
{
if (expectedToPass)
{
@@ -143,11 +125,12 @@ public class LegacyLocalTransformClientIntegrationTest extends AbstractRendition
{
RenditionDefinition2 renditionDefinition =
renditionDefinitionRegistry2.getRenditionDefinition(renditionDefinitionName);
transformClient.transform(
sourceNode,
renditionDefinition,
AuthenticationUtil.getAdminUserName(),
sourceContentHashCode);
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);
return null;
});
ChildAssociationRef childAssociationRef = null;

View File

@@ -25,9 +25,12 @@
*/
package org.alfresco.repo.rendition2;
import com.sun.star.auth.InvalidArgumentException;
import org.alfresco.repo.content.transform.LocalTransformServiceRegistry;
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;
@@ -38,28 +41,49 @@ import static org.alfresco.repo.content.MimetypeMap.MIMETYPE_OPENXML_WORDPROCESS
import static org.alfresco.repo.content.MimetypeMap.MIMETYPE_PDF;
/**
* Integration tests for {@link LegacyLocalTransformServiceRegistry}
* Integration tests for {@link LocalTransformServiceRegistry}
*/
public class LegacyLocalTransformServiceRegistryTest extends AbstractRenditionIntegrationTest
public class LocalTransformServiceRegistryTest extends AbstractRenditionIntegrationTest
{
private static final String RENDITION_NAME = "pdf";
@Autowired
private LegacyLocalTransformServiceRegistry transformServiceRegistry;
private LocalTransformServiceRegistry localTransformServiceRegistry;
@Autowired
private RenditionDefinitionRegistry2 renditionDefinitionRegistry2;
protected TransformServiceRegistry transformServiceRegistry;
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()
{
@@ -71,7 +95,7 @@ public class LegacyLocalTransformServiceRegistryTest extends AbstractRenditionIn
// 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, RENDITION_NAME));
Assert.assertFalse(transformServiceRegistry.isSupported(MIMETYPE_OPENXML_WORDPROCESSING, 1234, "pdfBad", options, "pdfBad"));
// Good MaxSize docx max size is 768K
Assert.assertTrue(transformServiceRegistry.isSupported(MIMETYPE_OPENXML_WORDPROCESSING, 768L*1024, MIMETYPE_PDF, options, RENDITION_NAME));
@@ -89,7 +113,7 @@ public class LegacyLocalTransformServiceRegistryTest extends AbstractRenditionIn
Assert.assertTrue(transformServiceRegistry.isSupported(MIMETYPE_OPENXML_WORDPROCESSING, 1234, MIMETYPE_PDF, options, "custom"));
}
@Test(expected = IllegalArgumentException.class)
@Test
public void testBadOptions()
{
// Source, Target and Props are in dictionary.properties
@@ -105,12 +129,12 @@ public class LegacyLocalTransformServiceRegistryTest extends AbstractRenditionIn
Assert.assertTrue(transformServiceRegistry.isSupported(MIMETYPE_OPENXML_WORDPROCESSING, 1234, MIMETYPE_PDF, options, RENDITION_NAME));
try
{
transformServiceRegistry.setEnabled(false);
setEnabled(false);
Assert.assertFalse(transformServiceRegistry.isSupported(MIMETYPE_OPENXML_WORDPROCESSING, 1234, MIMETYPE_PDF, options, RENDITION_NAME));
}
finally
{
transformServiceRegistry.setEnabled(true);
setEnabled(true);
}
Assert.assertTrue(transformServiceRegistry.isSupported(MIMETYPE_OPENXML_WORDPROCESSING, 1234, MIMETYPE_PDF, options, RENDITION_NAME));
}

View File

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

View File

@@ -36,6 +36,9 @@ 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;
@@ -48,6 +51,13 @@ import static org.junit.Assert.assertNotEquals;
*/
public class RenditionService2IntegrationTest extends AbstractRenditionIntegrationTest
{
@BeforeClass
public static void before()
{
AbstractRenditionIntegrationTest.before();
legacyLocal();
}
// PDF transformation
@Test

View File

@@ -0,0 +1,99 @@
/*
* #%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

@@ -29,12 +29,12 @@ import java.util.ArrayList;
import java.util.List;
/**
* 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.
* Helper class that builds a {@link Transformer} given the source and target types and a pipeline of Transformers
* for creating intermediary content.
*/
public class TransformBuilder
{
public Transformer buildPipeLine(String name, String version, List<SupportedSourceAndTarget> sourceAndTargetList,
public Transformer buildPipeLine(String name, List<SupportedSourceAndTarget> sourceAndTargetList,
List<ChildTransformer> transformerList)
{
List<TransformOption> options = new ArrayList<>(transformerList.size());
@@ -47,13 +47,6 @@ public class TransformBuilder
options.add(new TransformOptionGroup(t.isRequired(), t.getTransformer().getTransformOptions()));
}
});
return new Transformer(name, version, options, sourceAndTargetList);
return new Transformer(name, 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 - 2018 Alfresco Software Limited
* Copyright (C) 2005 - 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
@@ -26,6 +26,8 @@
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;
@@ -35,7 +37,6 @@ 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;
@@ -50,83 +51,48 @@ 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
{
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";
private static Log log = LogFactory.getLog(TransformServiceRegistryImplTest.class);
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 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 TRANSFORM_SERVICE_CONFIG = "alfresco/transform-service-config.json";
public static final ObjectMapper JSON_OBJECT_MAPPER = new ObjectMapper();
private TransformServiceRegistryImpl registry;
private TransformBuilder builder;
private Transformer transformer;
private ExtensionMap extensionMap;
protected TransformBuilder builder;
protected Transformer transformer;
@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();
}
private TransformServiceRegistryImpl buildTransformServiceRegistryImpl()
protected TransformServiceRegistryImpl buildTransformServiceRegistryImpl()
{
TransformServiceRegistryImpl registry = new TransformServiceRegistryImpl();
registry.setExtensionMap(extensionMap);
TransformServiceRegistryImpl registry = new TransformServiceRegistryImpl()
{
@Override
protected Log getLog()
{
return log;
}
};
registry.setJsonObjectMapper(JSON_OBJECT_MAPPER);
return registry;
}
@@ -137,6 +103,11 @@ 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);
@@ -188,7 +159,7 @@ public class TransformServiceRegistryImplTest
private void assertTransformOptions(List<TransformOption> transformOptions)
{
transformer = new Transformer("name", "1",
transformer = new Transformer("name",
transformOptions,
Arrays.asList(
new SupportedSourceAndTarget(DOC, TXT, -1),
@@ -197,44 +168,56 @@ public class TransformServiceRegistryImplTest
registry = buildTransformServiceRegistryImpl();
registry.register(transformer);
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));
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));
}
private void assertSupported(String sourceExt, long sourceSizeInBytes, String targetExt,
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,
Map<String, String> actualOptions, String unsupportedMsg)
{
assertSupported(sourceExt, sourceSizeInBytes, targetExt, actualOptions, unsupportedMsg, transformer);
assertSupported(sourceMimetype, sourceSizeInBytes, targetMimetype, actualOptions, unsupportedMsg, transformer);
}
private void assertSupported(String sourceExt, long sourceSizeInBytes, String targetExt,
private void assertSupported(String sourceMimetype, long sourceSizeInBytes, String targetMimetype,
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 sourceExt, long sourceSizeInBytes, String targetExt,
Map<String, String> actualOptions, String transformName,
private void assertSupported(String sourceMimetype, long sourceSizeInBytes, String targetMimetype,
Map<String, String> actualOptions, String renditionName,
String unsupportedMsg)
{
String sourceMimetype = extensionMap.toMimetype(sourceExt);
String targetMimetype = extensionMap.toMimetype(targetExt);
boolean supported = registry.isSupported(sourceMimetype, sourceSizeInBytes, targetMimetype, actualOptions, transformName);
boolean supported = registry.isSupported(sourceMimetype, sourceSizeInBytes, targetMimetype, actualOptions, renditionName);
if (unsupportedMsg == null || unsupportedMsg.isEmpty())
{
assertTrue(sourceExt+" to "+targetExt+" should be SUPPORTED", supported);
assertTrue(sourceMimetype+" to "+targetMimetype+" should be SUPPORTED", supported);
}
else
{
assertFalse(sourceExt+" to "+targetExt+" should NOT be supported", supported);
assertFalse(sourceMimetype+" to "+targetMimetype+" should NOT be supported", supported);
}
}
@@ -252,7 +235,7 @@ public class TransformServiceRegistryImplTest
@Test
public void testReadWriteJson() throws IOException
{
Transformer libreOffice = new Transformer("libreOffice", "1",
Transformer libreoffice = new Transformer("libreoffice",
null, // there are no options
Arrays.asList(
new SupportedSourceAndTarget(DOC, PDF, -1),
@@ -260,7 +243,7 @@ public class TransformServiceRegistryImplTest
new SupportedSourceAndTarget(PPT, PDF, -1),
new SupportedSourceAndTarget(MSG, PDF, -1)));
Transformer pdfRenderer = new Transformer("pdfRenderer", "1",
Transformer pdfrenderer = new Transformer("pdfrenderer",
Arrays.asList(
new TransformOptionValue(false, "page"),
new TransformOptionValue(false, "width"),
@@ -270,7 +253,7 @@ public class TransformServiceRegistryImplTest
Arrays.asList(
new SupportedSourceAndTarget(PDF, PNG, -1)));
Transformer tika = new Transformer("tika", "1",
Transformer tika = new Transformer("tika",
Arrays.asList(
new TransformOptionValue(false, "transform"),
new TransformOptionValue(false, "includeContents"),
@@ -284,7 +267,7 @@ public class TransformServiceRegistryImplTest
new SupportedSourceAndTarget(PPT, TXT, -1),
new SupportedSourceAndTarget(MSG, TXT, -1)));
Transformer imageMagick = new Transformer("imageMagick", "1",
Transformer imagemagick = new Transformer("imagemagick",
Arrays.asList(
new TransformOptionValue(false, "alphaRemove"),
new TransformOptionValue(false, "autoOrient"),
@@ -322,7 +305,7 @@ public class TransformServiceRegistryImplTest
new SupportedSourceAndTarget(TIFF, PNG, -1),
new SupportedSourceAndTarget(TIFF, TIFF, -1)));
Transformer officeToImage = builder.buildPipeLine("officeToImageViaPdf", "1",
Transformer officeToImage = builder.buildPipeLine("transformer1",
Arrays.asList(
new SupportedSourceAndTarget(DOC, GIF, -1),
new SupportedSourceAndTarget(DOC, JPEG, -1),
@@ -341,11 +324,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();
@@ -367,25 +350,22 @@ 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, ""); // officeToImageViaPdf
assertSupported(DOC, 1234, PNG, null, null, ""); // officeToImageViaPdf
assertSupported(MSG, 1234, GIF, null, null, ""); // transformer1 (officeToImageViaPdf)
assertSupported(DOC, 1234, PNG, null, null, ""); // transformer1 (officeToImageViaPdf)
}
}
@Test
public void testJsonConfig() throws IOException
{
try (Reader reader = new BufferedReader(new InputStreamReader(getClass().getClassLoader().
getResourceAsStream(TRANSFORM_SERVICE_CONFIG))))
{
registry.register(reader);
registry.register(getTransformServiceConfig());
// Check the count of transforms supported
assertEquals("The number of UNIQUE source to target mimetypes transforms has changed. Config change?",
63, countSupportedTransforms(true));
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?",
63, countSupportedTransforms(false));
60, countSupportedTransforms(false));
// Check a supported transform for each transformer.
assertSupported(DOC, 1234, PDF, null, null, ""); // libreoffice
@@ -399,15 +379,11 @@ public class TransformServiceRegistryImplTest
invalidPdfOptions.put("allowEnlargement", "false");
assertSupported(DOC, 1234, PDF, invalidPdfOptions, null, "Invalid as there is a extra option");
}
}
@Test
public void testJsonPipeline() throws IOException
{
try (Reader reader = new BufferedReader(new InputStreamReader(getClass().getClassLoader().
getResourceAsStream("alfresco/transform-service-config-test1.json"))))
{
registry.register(reader);
registry.register("alfresco/transform-service-config-test1.json");
// Check the count of transforms supported
assertEquals("The number of UNIQUE source to target mimetypes transforms has changed. Config change?",
@@ -421,20 +397,20 @@ public class TransformServiceRegistryImplTest
// 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");
registry.transformers.get(DOC);
List<TransformServiceRegistryImpl.SupportedTransform> supportedTransforms = transformsToWord.get(GIF);
TransformServiceRegistryImpl.SupportedTransform supportedTransform = supportedTransforms.get(0);
TransformOptionGroup imageMagick = (TransformOptionGroup)supportedTransform.transformOptions.transformOptions.get(0);
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 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());
assertTrue("imageMagick should be required as it is set", imageMagick.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());
@@ -458,7 +434,6 @@ public class TransformServiceRegistryImplTest
actualOptions.put("maintainAspectRatio", "true");
assertSupported(DOC,1234, PNG, actualOptions, null, "");
}
}
private int countSupportedTransforms(boolean unique)
{
@@ -627,7 +602,7 @@ public class TransformServiceRegistryImplTest
@Test
public void testSupported()
{
transformer = new Transformer("name", "1",
transformer = new Transformer("name",
Arrays.asList(
new TransformOptionValue(false, "page"),
new TransformOptionValue(false, "width"),
@@ -653,7 +628,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", "1",
transformer = new Transformer("name",
Arrays.asList(
new TransformOptionValue(false, "page"),
new TransformOptionValue(false, "width"),
@@ -667,18 +642,50 @@ public class TransformServiceRegistryImplTest
assertSupported(DOC, 1024, GIF, null, "doclib", "");
assertSupported(MSG, 1024, GIF, null, "doclib", "");
assertEquals(102400L, registry.getMaxSize(DOC_MIMETYPE, GIF_MIMETYPE, null, "doclib"));
assertEquals(-1L, registry.getMaxSize(MSG_MIMETYPE, GIF_MIMETYPE, null, "doclib"));
assertEquals(102400L, registry.getMaxSize(DOC, GIF, null, "doclib"));
assertEquals(-1L, registry.getMaxSize(MSG, GIF, null, "doclib"));
// Change the cached value and try and check we are now using the cached value.
registry.cachedMaxSizes.get("doclib").put(DOC_MIMETYPE, 1234L);
assertEquals(1234L, registry.getMaxSize(DOC_MIMETYPE, GIF_MIMETYPE, null, "doclib"));
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);
}
@Test
public void testMultipleTransformers()
{
Transformer transformer1 = new Transformer("transformer1", "1",
Transformer transformer1 = new Transformer("transformer1",
Arrays.asList(
new TransformOptionValue(false, "page"),
new TransformOptionValue(false, "width"),
@@ -688,7 +695,7 @@ public class TransformServiceRegistryImplTest
new SupportedSourceAndTarget(DOC, JPEG, -1),
new SupportedSourceAndTarget(MSG, GIF, -1)));
Transformer transformer2 = new Transformer("transformer2", "1",
Transformer transformer2 = new Transformer("transformer2",
Arrays.asList(
new TransformOptionValue(false, "opt1"),
new TransformOptionValue(false, "opt2")),
@@ -696,7 +703,7 @@ public class TransformServiceRegistryImplTest
new SupportedSourceAndTarget(PDF, GIF, -1),
new SupportedSourceAndTarget(PPT, JPEG, -1)));
Transformer transformer3 = new Transformer("transformer3", "1",
Transformer transformer3 = new Transformer("transformer3",
Arrays.asList(
new TransformOptionValue(false, "opt1")),
Arrays.asList(
@@ -725,13 +732,13 @@ public class TransformServiceRegistryImplTest
@Test
public void testPipeline()
{
Transformer transformer1 = new Transformer("transformer1", "1",
Transformer transformer1 = new Transformer("transformer1",
null, // there are no options
Arrays.asList(
new SupportedSourceAndTarget(DOC, PDF, -1),
new SupportedSourceAndTarget(MSG, PDF, -1)));
Transformer transformer2 = new Transformer("transformer2", "1",
Transformer transformer2 = new Transformer("transformer2",
Arrays.asList(
new TransformOptionValue(false, "page"),
new TransformOptionValue(false, "width"),
@@ -764,7 +771,7 @@ public class TransformServiceRegistryImplTest
private void buildPipelineTransformer(Transformer transformer1, Transformer transformer2)
{
transformer = builder.buildPipeLine("officeToImage", "1",
transformer = builder.buildPipeLine("transformer1",
Arrays.asList(
new SupportedSourceAndTarget(DOC, GIF, -1),
new SupportedSourceAndTarget(DOC, JPEG, -1),
@@ -773,14 +780,4 @@ 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,12 +1,13 @@
[
{
"name": "officeToImageViaPdf",
"version": "1",
"transformOptions": [
{
"group": {
"required": true,
"transformOptions": [
{
"transformOptions": {
"pdfrendererOptions": [
{"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"}},
@@ -27,23 +28,20 @@
{"value": {"name": "allowEnlargement"}},
{"value": {"name": "maintainAspectRatio"}}
]}}
]}},{
"group": {
"transformOptions": [
{"value": {"name": "page"}},
{"value": {"name": "width"}},
{"value": {"name": "height"}},
{"value": {"name": "allowPdfEnlargement"}},
{"value": {"name": "maintainPdfAspectRatio"}}
]
}
}
],
},
"transformers": [
{
"supportedSourceAndTargetList": [
{"sourceExt": "doc", "targetExt": "gif" },
{"sourceExt": "doc", "targetExt": "jpeg"},
{"sourceExt": "doc", "targetExt": "png" },
{"sourceExt": "doc", "targetExt": "tiff"}
{"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"
]
}
]
]
}