Reverting LocalTransformer work for the moment

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

View File

@@ -1,28 +1,28 @@
/* /*
* #%L * #%L
* Alfresco Repository * Alfresco Repository
* %% * %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited * Copyright (C) 2005 - 2016 Alfresco Software Limited
* %% * %%
* This file is part of the Alfresco software. * This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of * If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is * the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms: * provided under the following open source license terms:
* *
* Alfresco is free software: you can redistribute it and/or modify * 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 * 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 * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* Alfresco is distributed in the hope that it will be useful, * Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details. * GNU Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public License * You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>. * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L% * #L%
*/ */
package org.alfresco.repo.action.executer; package org.alfresco.repo.action.executer;
import java.util.List; import java.util.List;
@@ -59,7 +59,6 @@ import org.apache.commons.logging.LogFactory;
* *
* @author Roy Wetherall * @author Roy Wetherall
*/ */
@Deprecated
public class TransformActionExecuter extends ActionExecuterAbstractBase public class TransformActionExecuter extends ActionExecuterAbstractBase
{ {
/* Error messages */ /* Error messages */

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,128 +0,0 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2019 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.content.transform;
import org.alfresco.repo.content.filestore.FileContentWriter;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.MimetypeService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.util.TempFileProvider;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Transformer that passes a document through a pipeline of transformations to arrive at an target mimetype.
*
* Instances are automatically created for transformers identified by alfresco/transform json files and returned from
* T-Engines which are themselves identified by global properties the match the pattern localTransformer.&lt;name>.url.
* The transforms take place in a separate process (typically a Docker container).
*/
public class LocalPipelineTransformer extends AbstractLocalTransformer
{
private final List<IntermediateTransformer> transformers = new ArrayList<>();
private class IntermediateTransformer
{
LocalTransformer intermediateTransformer;
String targetMimetype;
}
public LocalPipelineTransformer(String name, TransformerDebug transformerDebug,
MimetypeService mimetypeService, boolean strictMimeTypeCheck,
Map<String, Set<String>> strictMimetypeExceptions,
boolean retryTransformOnDifferentMimeType,
LocalTransformServiceRegistry localTransformServiceRegistry)
{
super(name, transformerDebug, mimetypeService, strictMimeTypeCheck, strictMimetypeExceptions,
retryTransformOnDifferentMimeType, localTransformServiceRegistry);
}
@Override
public boolean isAvailable()
{
return true;
}
public void addIntermediateTransformer(LocalTransformer intermediateTransformer, String targetMimetype)
{
IntermediateTransformer transformer = new IntermediateTransformer();
transformer.intermediateTransformer = intermediateTransformer;
transformer.targetMimetype = targetMimetype;
transformers.add(transformer);
}
@Override
protected void transformImpl(ContentReader reader,
ContentWriter writer, Map<String, String> transformOptions,
String sourceMimetype, String targetMimetype,
String sourceExtension, String targetExtension,
String renditionName, NodeRef sourceNodeRef) throws Exception
{
ContentReader currentReader = reader;
int lastI = transformers.size() - 1;
for (int i = 0; i <= lastI; i++)
{
IntermediateTransformer transformer = transformers.get(i);
ContentWriter currentWriter;
if (i == lastI)
{
currentWriter = writer;
}
else
{
// make a temp file writer with the correct extension
String sourceExt = mimetypeService.getExtension(currentReader.getMimetype());
String targetExt = mimetypeService.getExtension(transformer.targetMimetype);
File tempFile = TempFileProvider.createTempFile(
"LocalPipelineTransformer_intermediate_" + sourceExt + "_",
"." + targetExt);
currentWriter = new FileContentWriter(tempFile);
currentWriter.setMimetype(transformer.targetMimetype);
}
transformer.intermediateTransformer.transform(currentReader, currentWriter, transformOptions, renditionName, sourceNodeRef);
// Clear the sourceNodeRef after the first transformation to avoid later transformers thinking the
// intermediate file is the original node.
if (i == 0)
{
sourceNodeRef = null;
}
// Pass the output to the next transformer
if (i < lastI)
{
currentReader = currentWriter.getReader();
}
}
}
}

View File

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

View File

@@ -1,42 +0,0 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2019 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.content.transform;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.NodeRef;
import java.util.Map;
/**
* Interface of a local transformer using flat transform options.
*/
public interface LocalTransformer
{
void transform(ContentReader reader, ContentWriter writer, Map<String, String> transformOptions,
String renditionName, NodeRef sourceNodeRef)
throws Exception;
}

View File

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

View File

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

View File

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

View File

@@ -30,12 +30,16 @@ import org.alfresco.error.AlfrescoRuntimeException;
/** /**
* Exception indicates that a transformer is unable to transform a requested * Exception indicates that a transformer is unable to transform a requested
* transformation. Normally the transformer is a component of a pipeline transformer * transformation. Normally the transformer is a component of a complex (compound) transformer
* and has been asked to transform a file that is too large as the * and has been asked to transform a file that is too large (see transformation limits) as the
* size of the intermediate file is unknown at the start. * size of the intermediate file is unknown at the start.
* *
* @author Alan Davis * @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 public class UnsupportedTransformationException extends AlfrescoRuntimeException
{ {
private static final long serialVersionUID = 9039331287661301086L; private static final long serialVersionUID = 9039331287661301086L;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,177 +0,0 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2019 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.rendition2;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.content.transform.LocalTransformer;
import org.alfresco.repo.content.transform.LocalTransformServiceRegistry;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.util.PropertyCheck;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import java.io.InputStream;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Requests rendition transforms take place using transforms available on the local machine (based on
* {@link LocalTransformer}. The transform and consumption of the
* resulting content is linked into a single operation that will take place at some point in the future on the local
* machine.
*
* @author adavis
*/
public class LocalTransformClient implements TransformClient, InitializingBean
{
private static Log logger = LogFactory.getLog(LocalTransformClient.class);
private LocalTransformServiceRegistry localTransformServiceRegistry;
private TransactionService transactionService;
private ContentService contentService;
private RenditionService2Impl renditionService2;
private ExecutorService executorService;
public void setLocalTransformServiceRegistry(LocalTransformServiceRegistry localTransformServiceRegistry)
{
this.localTransformServiceRegistry = localTransformServiceRegistry;
}
public void setTransactionService(TransactionService transactionService)
{
this.transactionService = transactionService;
}
public void setContentService(ContentService contentService)
{
this.contentService = contentService;
}
public void setRenditionService2(RenditionService2Impl renditionService2)
{
this.renditionService2 = renditionService2;
}
public void setExecutorService(ExecutorService executorService)
{
this.executorService = executorService;
}
@Override
public void afterPropertiesSet() throws Exception
{
PropertyCheck.mandatory(this, "localTransformServiceRegistry", localTransformServiceRegistry);
PropertyCheck.mandatory(this, "transactionService", transactionService);
PropertyCheck.mandatory(this, "contentService", contentService);
PropertyCheck.mandatory(this, "renditionService2", renditionService2);
if (executorService == null)
{
executorService = Executors.newCachedThreadPool();
}
}
@Override
public void checkSupported(NodeRef sourceNodeRef, RenditionDefinition2 renditionDefinition, String sourceMimetype, long size, String contentUrl)
{
String targetMimetype = renditionDefinition.getTargetMimetype();
String renditionName = renditionDefinition.getRenditionName();
Map<String, String> options = renditionDefinition.getTransformOptions();
if (!localTransformServiceRegistry.isSupported(sourceMimetype, size, targetMimetype, options, renditionName))
{
String message = "Unsupported rendition " + renditionName + " from " + sourceMimetype + " size: " + size + " using local transforms";
logger.debug(message);
throw new UnsupportedOperationException(message);
}
if (logger.isDebugEnabled())
{
logger.debug("Rendition of " + renditionName + " from " + sourceMimetype + " will use local transforms");
}
}
@Override
public void transform(NodeRef sourceNodeRef, RenditionDefinition2 renditionDefinition, String user, int sourceContentHashCode)
{
executorService.submit(() ->
{
AuthenticationUtil.runAs((AuthenticationUtil.RunAsWork<Void>) () ->
transactionService.getRetryingTransactionHelper().doInTransaction(() ->
{
try
{
String targetMimetype = renditionDefinition.getTargetMimetype();
String renditionName = renditionDefinition.getRenditionName();
Map<String, String> options = renditionDefinition.getTransformOptions();
ContentReader reader = contentService.getReader(sourceNodeRef, ContentModel.PROP_CONTENT);
if (null == reader || !reader.exists())
{
throw new IllegalArgumentException("The supplied sourceNodeRef "+sourceNodeRef+" has no content.");
}
ContentWriter writer = contentService.getTempWriter();
writer.setMimetype(targetMimetype);
if (logger.isDebugEnabled())
{
logger.debug("Local transform requested for rendition of " + renditionDefinition.getRenditionName());
}
localTransformServiceRegistry.transform(reader, writer, options, renditionName, sourceNodeRef);
InputStream inputStream = writer.getReader().getContentInputStream();
if (logger.isDebugEnabled())
{
logger.debug("Local transform to be consumed for rendition of " + renditionDefinition.getRenditionName());
}
renditionService2.consume(sourceNodeRef, inputStream, renditionDefinition, sourceContentHashCode);
if (logger.isDebugEnabled())
{
logger.debug("Local transform consumed for rendition of " + renditionDefinition.getRenditionName());
}
}
catch (Exception e)
{
if (logger.isDebugEnabled())
{
String renditionName = renditionDefinition.getRenditionName();
logger.error("Rendition of "+renditionName+" failed", e);
}
renditionService2.failure(sourceNodeRef, renditionDefinition, sourceContentHashCode);
throw e;
}
return null;
}), user);
});
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,66 +0,0 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2019 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.transform.client.model.config;
/**
* Represents a single transform step in a transform pipeline. The last step in the pipeline does not specify the
* target type as that is based on the supported types and what has been requested.
*/
public class TransformStep
{
private String transformerName;
private String targetMediaType;
public TransformStep()
{
}
public TransformStep(String transformerName, String targetMediaType)
{
setTransformerName(transformerName);
setTargetMediaType(targetMediaType);
}
public String getTransformerName()
{
return transformerName;
}
public void setTransformerName(String transformerName)
{
this.transformerName = transformerName;
}
public String getTargetMediaType()
{
return targetMediaType;
}
public void setTargetMediaType(String targetMediaType)
{
this.targetMediaType = targetMediaType;
}
}

View File

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

View File

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

View File

@@ -71,20 +71,9 @@
<!-- Replaced in the enterprise edition --> <!-- Replaced in the enterprise edition -->
<bean id="transformClient" parent="localTransformClient"/> <bean id="transformClient" parent="localTransformClient"/>
<bean id="localTransformClient" class="org.alfresco.repo.rendition2.SwitchingTransformClient"> <bean id="localTransformClient" class="org.alfresco.repo.rendition2.LegacyLocalTransformClient">
<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="transactionService" ref="transactionService" />
<property name="nodeService" ref="NodeService" />
<property name="contentService" ref="ContentService" /> <property name="contentService" ref="ContentService" />
<property name="renditionService2" ref="renditionService2" /> <property name="renditionService2" ref="renditionService2" />
<property name="converter" ref="transformOptionsConverter" /> <property name="converter" ref="transformOptionsConverter" />
@@ -102,28 +91,10 @@
<!-- Replaced in the enterprise edition --> <!-- Replaced in the enterprise edition -->
<bean id="transformServiceRegistry" parent="localTransformServiceRegistry"/> <bean id="transformServiceRegistry" parent="localTransformServiceRegistry"/>
<bean id="localTransformServiceRegistry" class="org.alfresco.repo.rendition2.SwitchingTransformServiceRegistry"> <bean id="localTransformServiceRegistry" class="org.alfresco.repo.rendition2.LegacyLocalTransformServiceRegistry" >
<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="contentService" ref="contentService" />
<property name="converter" ref="transformOptionsConverter" /> <property name="converter" ref="transformOptionsConverter" />
<property name="enabled" value="${legacy.transform.service.enabled}" /> <property name="enabled" value="${local.transform.service.enabled}" />
<property name="transformerDebug" ref="transformerDebug" /> <property name="transformerDebug" ref="transformerDebug" />
</bean> </bean>

View File

@@ -562,7 +562,7 @@ img.root=./ImageMagick
img.dyn=${img.root}/lib img.dyn=${img.root}/lib
img.exe=${img.root}/bin/convert img.exe=${img.root}/bin/convert
# Legacy imageMagick transformer url to T-Engine to service transform requests via http. Disabled by default. # Remote server (or docker container) url used to service imagemagick requests.
img.url= img.url=
# When img.url is set, this value indicates the amount of time to wait after a connection failure # When img.url is set, this value indicates the amount of time to wait after a connection failure
@@ -611,26 +611,13 @@ system.thumbnail.redeployStaticDefsOnStartup=true
# The default timeout for metadata mapping extracters # The default timeout for metadata mapping extracters
content.metadataExtracter.default.timeoutMs=20000 content.metadataExtracter.default.timeoutMs=20000
# Legacy tika transformer url to T-Engines to service transform requests via http. Disabled by default. # Remote server (or docker container) url used to service tika requests.
tika.url= tika.url=
# When the legacy tika transformer .url is set, this value indicates the amount of time to wait after a connection failure # When tika.url is set, this value indicates the amount of time to wait after a connection failure
# before retrying the connection to allow a docker container to (re)start. # before retrying the connection to allow a docker container to (re)start.
tika.startupRetryPeriodSeconds=60 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.maxDocumentSizeMB=10
content.metadataExtracter.pdf.maxConcurrentExtractionsCount=5 content.metadataExtracter.pdf.maxConcurrentExtractionsCount=5
@@ -1078,9 +1065,6 @@ system.cronJob.startDelayMilliseconds=60000
# Used to disable transforms locally. # Used to disable transforms locally.
local.transform.service.enabled=true 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 # 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. # mimetype of the content (via Tika) before a transformation takes place.
@@ -1090,15 +1074,13 @@ legacy.transform.service.enabled=true
# #
# There are a few issues with the Tika mimetype detection. So that transformations # 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, # still take place where the detected mimetype is not the same as the declared mimetype,
# another property (transformer.strict.mimetype.check.whitelist.mimetypes) contains pairs # another property (transformer.strict.mimetype.check.whitelist.mimetypes in transformers.properties
# of declared and detected mimetypes that should be allowed. This parameter value is a # so can be changed via JMX) contains pairs of declared and detected mimetypes that should
# sequence of ; separated pairs. The declared and derived mimetypes are also ; separated. # be allowed. This parameter value is a sequence of ; separated pairs. The declared and
# derived mimetypes are also ; separated.
# #
transformer.strict.mimetype.check=true 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. # Enable transformation retrying if the file has MIME type differ than file extension.
# Ignored if transformer.strict.mimetype.check is true as these transformations # Ignored if transformer.strict.mimetype.check is true as these transformations
@@ -1275,4 +1257,5 @@ messaging.subsystem.autoStart=true
# Raw events # Raw events
acs.repo.rendition.events.endpoint=jms:acs-repo-rendition-events?jmsMessageType=Text acs.repo.rendition.events.endpoint=jms:acs-repo-rendition-events?jmsMessageType=Text

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -200,8 +200,7 @@ import org.junit.runners.Suite;
org.alfresco.util.bean.HierarchicalBeanLoaderTest.class, org.alfresco.util.bean.HierarchicalBeanLoaderTest.class,
org.alfresco.util.resource.HierarchicalResourceLoaderTest.class, org.alfresco.util.resource.HierarchicalResourceLoaderTest.class,
org.alfresco.repo.events.ClientUtilTest.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 public class AllUnitTestsSuite
{ {

View File

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

View File

@@ -41,7 +41,10 @@ import org.mockito.MockitoAnnotations;
* Test class for TransformerDebugLog. * Test class for TransformerDebugLog.
* *
* @author Alan Davis * @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 public class TransformerDebugLogTest
{ {
@Mock @Mock

View File

@@ -25,9 +25,9 @@
*/ */
package org.alfresco.repo.content.transform; 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.MimetypeService;
import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.TransformationOptions;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.mockito.Mock; import org.mockito.Mock;
@@ -49,7 +49,10 @@ import static org.mockito.Mockito.when;
* Test class for TransformerDebug. * Test class for TransformerDebug.
* *
* @author Alan Davis * @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 public class TransformerDebugTest
{ {
@Mock @Mock
@@ -65,7 +68,7 @@ public class TransformerDebugTest
private TransformerConfig transformerConfig; private TransformerConfig transformerConfig;
@Mock @Mock
private TransformClient transformClient; private TransformationOptions options;
@Mock @Mock
private AbstractContentTransformerLimits transformer1; private AbstractContentTransformerLimits transformer1;
@@ -105,14 +108,7 @@ public class TransformerDebugTest
when(transformer3.getName()).thenReturn("transformer3"); when(transformer3.getName()).thenReturn("transformer3");
when(transformer4.getName()).thenReturn("transformer4"); when(transformer4.getName()).thenReturn("transformer4");
transformerDebug = new TransformerDebug(); transformerDebug = new TransformerDebug(nodeService, mimetypeService, transformerRegistry, transformerConfig, log, debug);
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.setTransformerDebug(transformerDebug);
log.setTransformerConfig(transformerConfig); log.setTransformerConfig(transformerConfig);
@@ -155,7 +151,7 @@ public class TransformerDebugTest
{ {
long sourceSize = 1024*1024*3/2; long sourceSize = 1024*1024*3/2;
transformerDebug.pushAvailable("sourceUrl", "application/pdf", "text/plain", null, null); transformerDebug.pushAvailable("sourceUrl", "application/pdf", "text/plain", options);
transformerDebug.unavailableTransformer(transformer1, "application/pdf", "text/plain", 50); transformerDebug.unavailableTransformer(transformer1, "application/pdf", "text/plain", 50);
transformerDebug.unavailableTransformer(transformer2, "application/pdf", "text/plain", 0); transformerDebug.unavailableTransformer(transformer2, "application/pdf", "text/plain", 0);
@@ -164,7 +160,7 @@ public class TransformerDebugTest
List<ContentTransformer> transformers = Arrays.asList(new ContentTransformer[] {}); List<ContentTransformer> transformers = Arrays.asList(new ContentTransformer[] {});
transformerDebug.availableTransformers(transformers, sourceSize, null, null, "ContentService.transform(...)"); transformerDebug.availableTransformers(transformers, sourceSize, options, "ContentService.transform(...)");
transformerDebug.popAvailable(); transformerDebug.popAvailable();

View File

@@ -39,7 +39,10 @@ import org.mockito.MockitoAnnotations;
* Test class for TransformerLog. * Test class for TransformerLog.
* *
* @author Alan Davis * @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 public class TransformerLogTest
{ {
@Mock @Mock

View File

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

View File

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

View File

@@ -1,54 +0,0 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2018 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.rendition2;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
/**
* Repeats quick file rendition tests with local transforms and legacy transformers enabled.
* The Transform Service does not exist for the Community edition.
* Should be the same result as with legacy or local transforms on their own.
*
* @author adavis
*/
@Deprecated
public class LegacyLocalRenditionTest extends AbstractRenditionTest
{
@BeforeClass
public static void before()
{
AbstractRenditionIntegrationTest.before();
legacyLocal();
}
@AfterClass
public static void after()
{
AbstractRenditionIntegrationTest.after();
}
}

View File

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

View File

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

View File

@@ -1,69 +0,0 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2018 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.rendition2;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import static org.alfresco.model.ContentModel.PROP_CONTENT;
/**
* Integration tests for {@link LegacyTransformClient}
*/
@Deprecated
public class LegacyTransformClientIntegrationTest extends LocalTransformClientIntegrationTest
{
@Autowired
protected TransformClient legacyTransformClient;
@BeforeClass
public static void before()
{
AbstractRenditionIntegrationTest.before();
legacy();
}
@AfterClass
public static void after()
{
AbstractRenditionIntegrationTest.after();
}
@Before
public void setUp() throws Exception
{
super.setUp();
transformClient = legacyTransformClient;
}
}

View File

@@ -1,75 +0,0 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2018 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.rendition2;
import org.alfresco.transform.client.model.config.TransformServiceRegistry;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.HashMap;
import java.util.Map;
import static org.alfresco.repo.content.MimetypeMap.MIMETYPE_OPENXML_WORDPROCESSING;
import static org.alfresco.repo.content.MimetypeMap.MIMETYPE_PDF;
/**
* Integration tests for {@link LegacyTransformServiceRegistry}
*/
@Deprecated
public class LegacyTransformServiceRegistryTest extends LocalTransformServiceRegistryTest
{
@Autowired
private LegacyTransformServiceRegistry legacyTransformServiceRegistry;
@Before
public void setUp() throws Exception
{
super.setUp();
transformServiceRegistry = legacyTransformServiceRegistry;
}
@BeforeClass
public static void before()
{
AbstractRenditionIntegrationTest.before();
legacy();
}
@AfterClass
public static void after()
{
AbstractRenditionIntegrationTest.after();
}
protected void setEnabled(boolean enabled)
{
legacyTransformServiceRegistry.setEnabled(enabled);
}
}

View File

@@ -1,64 +0,0 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2018 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.rendition2;
import org.alfresco.util.testing.category.DebugTests;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.experimental.categories.Category;
/**
* Repeats quick file rendition tests with local transforms enabled but legacy transformers disabled.
* The Transform Service does not exist for the Community edition.
* Should be the same result as with legacy transforms only.
*
* @author adavis
*/
public class LocalRenditionTest extends AbstractRenditionTest
{
@BeforeClass
public static void before()
{
AbstractRenditionIntegrationTest.before();
local();
}
@AfterClass
public static void after()
{
AbstractRenditionIntegrationTest.after();
}
// TODO this method will be removed when Local transformers support all 196 renditions supported by legacy
@Override
@Category(DebugTests.class)
@Test
public void testAllSourceExtensions() throws Exception
{
internalTestAllSourceExtensions(57, 0);
}
}

View File

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

View File

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

View File

@@ -28,6 +28,7 @@ package org.alfresco.repo.rendition2;
import junit.framework.AssertionFailedError; import junit.framework.AssertionFailedError;
import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.thumbnail.ThumbnailDefinition; import org.alfresco.repo.thumbnail.ThumbnailDefinition;
import org.alfresco.transform.client.model.config.TransformServiceRegistry;
import org.alfresco.util.testing.category.DebugTests; import org.alfresco.util.testing.category.DebugTests;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@@ -44,12 +45,11 @@ import java.util.Set;
import java.util.StringJoiner; import java.util.StringJoiner;
/** /**
* Abstract test class to check it is possible to create renditions from the quick files using combinations of * Test it is possible to create renditions from the quick files.
* local transforms, legacy transforms and the Transform Service.
* *
* @author adavis * @author adavis
*/ */
public abstract class AbstractRenditionTest extends AbstractRenditionIntegrationTest public class RenditionTest extends AbstractRenditionIntegrationTest
{ {
// This is the same order as produced by MimetypeMap // This is the same order as produced by MimetypeMap
public static final List<String> TAS_REST_API_SOURCE_EXTENSIONS = Arrays.asList( public static final List<String> TAS_REST_API_SOURCE_EXTENSIONS = Arrays.asList(
@@ -89,7 +89,9 @@ public abstract class AbstractRenditionTest extends AbstractRenditionIntegration
"wpd png avatar32", "wpd png avatar32",
"wpd jpg imgpreview"); "wpd jpg imgpreview");
@Override @Autowired
private TransformServiceRegistry transformServiceRegistry;
@Before @Before
public void setUp() throws Exception public void setUp() throws Exception
{ {
@@ -146,15 +148,17 @@ public abstract class AbstractRenditionTest extends AbstractRenditionIntegration
} }
else else
{ {
String task = sourceExtension + " " + targetExtension + " " + renditionName;
try try
{ {
checkRendition(testFileName, renditionName, !expectedToFail.contains(sourceTragetRendition)); checkRendition(testFileName, renditionName, !expectedToFail.contains(sourceTragetRendition));
successes.add(sourceTragetRendition); successes.add(task);
successCount++; successCount++;
} }
catch (AssertionFailedError e) catch (AssertionFailedError e)
{ {
failures.add(sourceTragetRendition + " " + e.getMessage()); failures.add(task + " " + e.getMessage());
failedCount++; failedCount++;
} }
} }
@@ -213,6 +217,48 @@ public abstract class AbstractRenditionTest extends AbstractRenditionIntegration
Collections.emptyList(), expectedRenditionCount, expectedFailedCount); 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() private List<String> getAllSourceMimetypes()
{ {
List<String> sourceExtensions = new ArrayList<>(); List<String> sourceExtensions = new ArrayList<>();

View File

@@ -1,99 +0,0 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2019 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.transform.client.model.config;
import org.alfresco.repo.content.transform.TransformerDebug;
import org.alfresco.repo.content.transform.LocalTransformServiceRegistry;
import org.junit.After;
import org.junit.Before;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.Properties;
/**
* Extends the {@link TransformServiceRegistryImplTest} (used to test the config received from the Transform Service)
* so that configuration for the local transformations may be tested. This includes pipelines and options specific
* transform steps.
*/
public class LocalTransformServiceRegistryTest extends TransformServiceRegistryImplTest
{
protected LocalTransformServiceRegistry registry;
private Properties properties;
@Mock
private TransformerDebug transformerDebug;
public static final String TRANSFORM_SERVICE_CONFIG = "alfresco/transformers";
@Before
public void setUp() throws Exception
{
MockitoAnnotations.initMocks(this);
properties = new Properties();
properties.setProperty( "name.url", "dummy");
properties.setProperty("transformer1.url", "dummy");
properties.setProperty("transformer2.url", "dummy");
properties.setProperty("transformer3.url", "dummy");
properties.setProperty("transformer4.url", "dummy");
properties.setProperty("transformer5.url", "dummy");
properties.setProperty( "libreoffice.url", "dummy");
properties.setProperty( "tika.url", "dummy");
properties.setProperty( "pdfrenderer.url", "dummy");
properties.setProperty( "imagemagick.url", "dummy");
super.setUp();
}
protected TransformServiceRegistryImpl buildTransformServiceRegistryImpl()
{
registry = new LocalTransformServiceRegistry();
registry.setJsonObjectMapper(JSON_OBJECT_MAPPER);
registry.setProperties(properties);
registry.setTransformerDebug(transformerDebug);
return registry;
}
@After
public void tearDown()
{
// shut down
}
protected String getTransformServiceConfig()
{
return TRANSFORM_SERVICE_CONFIG;
}
// TODO test pipeline
// TODO test strict mimetype check
// TODO test retry transform on different mimetype
// TODO test using system properties and alfresco-global.properties
// TODO test the JsonConverter
}

View File

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

View File

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