Save point: [skip ci]

* cleaning up TransformController - more to do
* wire up all transforms
This commit is contained in:
alandavis
2022-07-06 17:38:15 +01:00
parent 0eb8d9e142
commit 2e17c3ec53
29 changed files with 862 additions and 512 deletions

View File

@@ -1,58 +0,0 @@
/*
* #%L
* Alfresco Transform Core
* %%
* Copyright (C) 2005 - 2022 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;
import org.alfresco.transform.config.TransformConfig;
import org.alfresco.transformer.probes.ProbeTestTransform;
import java.util.Set;
/**
* The interface to the custom transform code applied on top of a base t-engine.
*/
public interface TransformEngine
{
/**
* @return the name of the t-engine. The t-router reads config from t-engines in name order.
*/
String getTransformEngineName();
/**
* @return a definition of what the t-engine supports. Normally read from a json Resource on the classpath.
*/
TransformConfig getTransformConfig();
/**
* @return actual transform codes.
*/
Set<CustomTransformer> getTransformers();
/**
* @return a ProbeTestTransform (will do a quick transform) for k8 liveness and readiness probes.
*/
ProbeTestTransform getLivenessAndReadinessProbeTestTransform();
}

View File

@@ -36,12 +36,14 @@ import java.util.Map;
* Interface to be implemented by transform specific code. The {@code transformerName} should match the transformerName * Interface to be implemented by transform specific code. The {@code transformerName} should match the transformerName
* in the {@link TransformConfig} returned by the {@link TransformEngine}. So that it is automatically picked up, it * in the {@link TransformConfig} returned by the {@link TransformEngine}. So that it is automatically picked up, it
* must exist in a package under {@code org.alfresco.transform} and have the Spring {@code @Component} annotation. * must exist in a package under {@code org.alfresco.transform} and have the Spring {@code @Component} annotation.
*
* Implementations may also use the {@link TransformManager} if they wish to interact with the base t-engine.
*/ */
public interface CustomTransformer public interface CustomTransformer
{ {
String getTransformerName(); String getTransformerName();
void transform(String sourceMimetype, String sourceEncoding, InputStream inputStream, void transform(String sourceMimetype, InputStream inputStream,
String targetMimetype, String targetEncoding, OutputStream outputStream, String targetMimetype, OutputStream outputStream,
Map<String, String> transformOptions) throws Exception; Map<String, String> transformOptions, TransformManager transformManager) throws Exception;
} }

View File

@@ -26,7 +26,9 @@
*/ */
package org.alfresco.transform.base; package org.alfresco.transform.base;
import org.alfresco.transform.base.fs.FileManager;
import org.alfresco.transform.base.probes.ProbeTestTransform; import org.alfresco.transform.base.probes.ProbeTestTransform;
import org.alfresco.transform.base.util.OutputStreamLengthRecorder;
import org.alfresco.transform.common.TransformerDebug; import org.alfresco.transform.common.TransformerDebug;
import org.alfresco.transform.client.model.InternalContext; import org.alfresco.transform.client.model.InternalContext;
import org.alfresco.transform.client.model.TransformReply; import org.alfresco.transform.client.model.TransformReply;
@@ -38,7 +40,6 @@ import org.alfresco.transform.common.TransformException;
import org.alfresco.transform.base.clients.AlfrescoSharedFileStoreClient; import org.alfresco.transform.base.clients.AlfrescoSharedFileStoreClient;
import org.alfresco.transform.base.logging.LogEntry; import org.alfresco.transform.base.logging.LogEntry;
import org.alfresco.transform.base.model.FileRefResponse; import org.alfresco.transform.base.model.FileRefResponse;
import org.codehaus.plexus.util.FileUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.TypeMismatchException; import org.springframework.beans.TypeMismatchException;
@@ -65,13 +66,16 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.client.HttpClientErrorException; import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import java.io.BufferedOutputStream;
import java.io.File; import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.net.URL; import java.io.InputStream;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Comparator; import java.util.Comparator;
@@ -82,6 +86,8 @@ import java.util.concurrent.atomic.AtomicInteger;
import static java.text.MessageFormat.format; import static java.text.MessageFormat.format;
import static java.util.stream.Collectors.joining; import static java.util.stream.Collectors.joining;
import static org.alfresco.transform.base.fs.FileManager.createTargetFile;
import static org.alfresco.transform.common.RequestParamMap.TARGET_ENCODING;
import static org.alfresco.transform.config.CoreVersionDecorator.setOrClearCoreVersion; import static org.alfresco.transform.config.CoreVersionDecorator.setOrClearCoreVersion;
import static org.alfresco.transform.common.RequestParamMap.DIRECT_ACCESS_URL; import static org.alfresco.transform.common.RequestParamMap.DIRECT_ACCESS_URL;
import static org.alfresco.transform.common.RequestParamMap.CONFIG_VERSION; import static org.alfresco.transform.common.RequestParamMap.CONFIG_VERSION;
@@ -89,11 +95,7 @@ import static org.alfresco.transform.common.RequestParamMap.CONFIG_VERSION_DEFAU
import static org.alfresco.transform.common.RequestParamMap.ENDPOINT_TRANSFORM; import static org.alfresco.transform.common.RequestParamMap.ENDPOINT_TRANSFORM;
import static org.alfresco.transform.common.RequestParamMap.ENDPOINT_TRANSFORM_CONFIG; import static org.alfresco.transform.common.RequestParamMap.ENDPOINT_TRANSFORM_CONFIG;
import static org.alfresco.transform.base.fs.FileManager.TempFileProvider.createTempFile; import static org.alfresco.transform.base.fs.FileManager.TempFileProvider.createTempFile;
import static org.alfresco.transform.base.fs.FileManager.buildFile; import static org.alfresco.transform.base.fs.FileManager.getDirectAccessUrlInputStream;
import static org.alfresco.transform.base.fs.FileManager.createAttachment;
import static org.alfresco.transform.base.fs.FileManager.createSourceFile;
import static org.alfresco.transform.base.fs.FileManager.createTargetFile;
import static org.alfresco.transform.base.fs.FileManager.createTargetFileName;
import static org.alfresco.transform.base.fs.FileManager.deleteFile; import static org.alfresco.transform.base.fs.FileManager.deleteFile;
import static org.alfresco.transform.base.fs.FileManager.getFilenameFromContentDisposition; import static org.alfresco.transform.base.fs.FileManager.getFilenameFromContentDisposition;
import static org.alfresco.transform.base.fs.FileManager.save; import static org.alfresco.transform.base.fs.FileManager.save;
@@ -280,7 +282,7 @@ public class TransformController
} }
@PostMapping(value = ENDPOINT_TRANSFORM, consumes = MULTIPART_FORM_DATA_VALUE) @PostMapping(value = ENDPOINT_TRANSFORM, consumes = MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<Resource> transform(HttpServletRequest request, public StreamingResponseBody transform(HttpServletRequest request,
@RequestParam(value = FILE, required = false) MultipartFile sourceMultipartFile, @RequestParam(value = FILE, required = false) MultipartFile sourceMultipartFile,
@RequestParam(value = SOURCE_MIMETYPE, required = false) String sourceMimetype, @RequestParam(value = SOURCE_MIMETYPE, required = false) String sourceMimetype,
@RequestParam(value = TARGET_MIMETYPE, required = false) String targetMimetype, @RequestParam(value = TARGET_MIMETYPE, required = false) String targetMimetype,
@@ -291,51 +293,55 @@ public class TransformController
logger.debug("Processing request via HTTP endpoint. Params: sourceMimetype: '{}', targetMimetype: '{}', " logger.debug("Processing request via HTTP endpoint. Params: sourceMimetype: '{}', targetMimetype: '{}', "
+ "requestParameters: {}", sourceMimetype, targetMimetype, requestParameters); + "requestParameters: {}", sourceMimetype, targetMimetype, requestParameters);
} }
final String directUrl = requestParameters.getOrDefault(DIRECT_ACCESS_URL, "");
File sourceFile;
String sourceFilename;
if (directUrl.isBlank())
{
if (sourceMultipartFile == null)
{
throw new TransformException(BAD_REQUEST.value(), "Required request part 'file' is not present");
}
sourceFile = createSourceFile(request, sourceMultipartFile);
sourceFilename = sourceMultipartFile.getOriginalFilename();
}
else
{
sourceFile = getSourceFileFromDirectUrl(directUrl);
sourceFilename = sourceFile.getName();
}
final String targetFilename = createTargetFileName(sourceFilename, sourceMimetype, targetMimetype);
probeTestTransform.incrementTransformerCount(); probeTestTransform.incrementTransformerCount();
final File targetFile = createTargetFile(request, targetFilename);
// Obtain the source
final String directUrl = requestParameters.getOrDefault(DIRECT_ACCESS_URL, "");
InputStream inputStream = directUrl.isBlank()
? FileManager.getMultipartFileInputStream(sourceMultipartFile)
: getDirectAccessUrlInputStream(directUrl);
long sourceSizeInBytes = -1L; // TODO pass in t-options or just ignore for http request as the repo will have checked.
Map<String, String> transformOptions = getTransformOptions(requestParameters); Map<String, String> transformOptions = getTransformOptions(requestParameters);
String transformName = getTransformerName(sourceFile, sourceMimetype, targetMimetype, transformOptions); String transformName = getTransformerName(sourceSizeInBytes, sourceMimetype, targetMimetype, transformOptions);
CustomTransformer customTransformer = getCustomTransformer(transformName);
String sourceEncoding = transformOptions.get(SOURCE_ENCODING);
String targetEncoding = transformOptions.get(TARGET_ENCODING); // TODO not normally set
String reference = "e"+httpRequestCount.getAndIncrement(); String reference = "e"+httpRequestCount.getAndIncrement();
transformerDebug.pushTransform(reference, sourceMimetype, targetMimetype, sourceFile, transformName); transformerDebug.pushTransform(reference, sourceMimetype, targetMimetype, sourceSizeInBytes, transformName);
transformerDebug.logOptions(reference, requestParameters); transformerDebug.logOptions(reference, requestParameters);
return os -> {
OutputStreamLengthRecorder outputStream = new OutputStreamLengthRecorder(os);
try try
{ {
transformImpl(transformName, sourceMimetype, targetMimetype, transformOptions, sourceFile, targetFile); TransformManagerImpl transformManager = TransformManagerImpl.builder()
.withRequest(request)
.withSourceMimetype(sourceMimetype)
.withTargetMimetype(targetMimetype)
.withInputStream(inputStream)
.withOutputStream(outputStream)
.build();
final ResponseEntity<Resource> body = createAttachment(targetFilename, targetFile); customTransformer.transform(sourceMimetype, inputStream,
LogEntry.setTargetSize(targetFile.length()); targetMimetype, outputStream, transformOptions, transformManager);
transformManager.ifUsedCopyTargetFileToOutputStream();
LogEntry.setTargetSize(outputStream.getLength());
long time = LogEntry.setStatusCodeAndMessage(OK.value(), "Success"); long time = LogEntry.setStatusCodeAndMessage(OK.value(), "Success");
transformManager.deleteSourceFileIfExists();
transformManager.deleteTargetFileIfExists();
probeTestTransform.recordTransformTime(time); probeTestTransform.recordTransformTime(time);
transformerDebug.popTransform(reference, time); transformerDebug.popTransform(reference, time);
return body;
} }
catch (Throwable t) catch (Exception e)
{ {
transformerDebug.logFailure(reference, t.getMessage()); transformerDebug.logFailure(reference, e.getMessage());
throw t; throw new RuntimeException(e);
} }
};
} }
/** /**
@@ -353,89 +359,68 @@ public class TransformController
public ResponseEntity<TransformReply> transform(@RequestBody TransformRequest request, public ResponseEntity<TransformReply> transform(@RequestBody TransformRequest request,
@RequestParam(value = "timeout", required = false) Long timeout) @RequestParam(value = "timeout", required = false) Long timeout)
{ {
long start = System.currentTimeMillis();
logger.trace("Received {}, timeout {} ms", request, timeout); logger.trace("Received {}, timeout {} ms", request, timeout);
probeTestTransform.incrementTransformerCount();
TransformReply reply = createBasicTransformReply(request);
final TransformReply reply = new TransformReply(); if (isTransformRequestValid(request, reply) == false)
reply.setRequestId(request.getRequestId());
reply.setSourceReference(request.getSourceReference());
reply.setSchema(request.getSchema());
reply.setClientData(request.getClientData());
final Errors errors = validateTransformRequest(request);
validateInternalContext(request, errors);
initialiseContext(request);
reply.setInternalContext(request.getInternalContext());
if (!errors.getAllErrors().isEmpty())
{ {
reply.setStatus(BAD_REQUEST.value());
reply.setErrorDetails(errors
.getAllErrors()
.stream()
.map(Object::toString)
.collect(joining(", ")));
transformerDebug.logFailure(reply);
logger.trace("Invalid request, sending {}", reply);
return new ResponseEntity<>(reply, HttpStatus.valueOf(reply.getStatus()));
}
transformerDebug.pushTransform(request);
// Load the source file
File sourceFile;
try
{
final String directUrl = request.getTransformRequestOptions().getOrDefault(DIRECT_ACCESS_URL, "");
if (directUrl.isBlank())
{
sourceFile = loadSourceFile(request.getSourceReference(), request.getSourceExtension());
}
else
{
sourceFile = getSourceFileFromDirectUrl(directUrl);
}
}
catch (TransformException e)
{
reply.setStatus(e.getStatusCode());
reply.setErrorDetails(messageWithCause("Failed at reading the source file", e));
transformerDebug.logFailure(reply);
logger.trace("Failed to load source file (TransformException), sending " + reply);
return new ResponseEntity<>(reply, HttpStatus.valueOf(reply.getStatus()));
}
catch (HttpClientErrorException e)
{
reply.setStatus(e.getStatusCode().value());
reply.setErrorDetails(messageWithCause("Failed at reading the source file", e));
transformerDebug.logFailure(reply);
logger.trace("Failed to load source file (HttpClientErrorException), sending " + reply, e);
return new ResponseEntity<>(reply, HttpStatus.valueOf(reply.getStatus()));
}
catch (Exception e)
{
reply.setStatus(INTERNAL_SERVER_ERROR.value());
reply.setErrorDetails(messageWithCause("Failed at reading the source file", e));
transformerDebug.logFailure(reply);
logger.trace("Failed to load source file (Exception), sending " + reply, e);
return new ResponseEntity<>(reply, HttpStatus.valueOf(reply.getStatus())); return new ResponseEntity<>(reply, HttpStatus.valueOf(reply.getStatus()));
} }
// Create local temp target file in order to run the transformation InputStream inputStream = getInputStream(request, reply);
final String targetFilename = createTargetFileName(sourceFile.getName(), request.getTargetMediaType(), request.getSourceMediaType()); if (inputStream == null)
final File targetFile = buildFile(targetFilename);
// Run the transformation
try
{ {
return new ResponseEntity<>(reply, HttpStatus.valueOf(reply.getStatus()));
}
String targetMimetype = request.getTargetMediaType(); String targetMimetype = request.getTargetMediaType();
String sourceMimetype = request.getSourceMediaType(); String sourceMimetype = request.getSourceMediaType();
File targetFile = createTargetFile(null, sourceMimetype, targetMimetype);
transformerDebug.pushTransform(request);
try
{
OutputStreamLengthRecorder outputStream =
new OutputStreamLengthRecorder(new BufferedOutputStream(new FileOutputStream(targetFile)));
long sourceSizeInBytes = request.getSourceSize();
Map<String, String> transformOptions = getTransformOptions(request.getTransformRequestOptions()); Map<String, String> transformOptions = getTransformOptions(request.getTransformRequestOptions());
String sourceEncoding = transformOptions.get(SOURCE_ENCODING);
String targetEncoding = transformOptions.get(TARGET_ENCODING); // TODO not normally set
transformerDebug.logOptions(request); transformerDebug.logOptions(request);
String transformName = getTransformerName(sourceFile, sourceMimetype, targetMimetype, transformOptions); String transformName = getTransformerName(sourceSizeInBytes, sourceMimetype, targetMimetype, transformOptions);
transformImpl(transformName, sourceMimetype, targetMimetype, transformOptions, sourceFile, targetFile); CustomTransformer customTransformer = getCustomTransformer(transformName);
reply.getInternalContext().setCurrentSourceSize(targetFile.length());
TransformManagerImpl transformManager = TransformManagerImpl.builder()
.withSourceMimetype(sourceMimetype)
.withTargetMimetype(targetMimetype)
.withInputStream(inputStream)
.withOutputStream(outputStream)
.withTargetFile(targetFile)
.build();
customTransformer.transform(sourceMimetype, inputStream,
targetMimetype, outputStream, transformOptions, transformManager);
transformManager.ifUsedCopyTargetFileToOutputStream();
reply.getInternalContext().setCurrentSourceSize(outputStream.getLength());
if (saveTargetFileInSharedFileStore(targetFile, reply) == false)
{
return new ResponseEntity<>(reply, HttpStatus.valueOf(reply.getStatus()));
}
transformManager.deleteSourceFileIfExists();
transformManager.deleteTargetFileIfExists();
probeTestTransform.recordTransformTime(System.currentTimeMillis()-start);
transformerDebug.popTransform(reply);
logger.trace("Sending successful {}, timeout {} ms", reply, timeout);
return new ResponseEntity<>(reply, HttpStatus.valueOf(reply.getStatus()));
} }
catch (TransformException e) catch (TransformException e)
{ {
@@ -455,65 +440,38 @@ public class TransformController
logger.trace("Failed to perform transform (Exception), sending " + reply, e); logger.trace("Failed to perform transform (Exception), sending " + reply, e);
return new ResponseEntity<>(reply, HttpStatus.valueOf(reply.getStatus())); return new ResponseEntity<>(reply, HttpStatus.valueOf(reply.getStatus()));
} }
// Write the target file
FileRefResponse targetRef;
try
{
targetRef = alfrescoSharedFileStoreClient.saveFile(targetFile);
} }
catch (TransformException e)
private boolean isTransformRequestValid(TransformRequest request, TransformReply reply)
{ {
reply.setStatus(e.getStatusCode()); final Errors errors = validateTransformRequest(request);
reply.setErrorDetails(messageWithCause("Failed at writing the transformed file", e)); validateInternalContext(request, errors);
reply.setInternalContext(request.getInternalContext());
if (!errors.getAllErrors().isEmpty())
{
reply.setStatus(BAD_REQUEST.value());
reply.setErrorDetails(errors
.getAllErrors()
.stream()
.map(Object::toString)
.collect(joining(", ")));
transformerDebug.logFailure(reply); transformerDebug.logFailure(reply);
logger.trace("Failed to save target file (TransformException), sending " + reply, e); logger.trace("Invalid request, sending {}", reply);
return new ResponseEntity<>(reply, HttpStatus.valueOf(reply.getStatus())); return false;
} }
catch (HttpClientErrorException e) return true;
{
reply.setStatus(e.getStatusCode().value());
reply.setErrorDetails(messageWithCause("Failed at writing the transformed file. ", e));
transformerDebug.logFailure(reply);
logger.trace("Failed to save target file (HttpClientErrorException), sending " + reply, e);
return new ResponseEntity<>(reply, HttpStatus.valueOf(reply.getStatus()));
}
catch (Exception e)
{
reply.setStatus(INTERNAL_SERVER_ERROR.value());
reply.setErrorDetails(messageWithCause("Failed at writing the transformed file. ", e));
transformerDebug.logFailure(reply);
logger.trace("Failed to save target file (Exception), sending " + reply, e);
return new ResponseEntity<>(reply, HttpStatus.valueOf(reply.getStatus()));
} }
try private TransformReply createBasicTransformReply(TransformRequest request)
{ {
deleteFile(targetFile); TransformReply reply = new TransformReply();
} reply.setRequestId(request.getRequestId());
catch (Exception e) reply.setSourceReference(request.getSourceReference());
{ reply.setSchema(request.getSchema());
logger.error("Failed to delete local temp target file '{}'. Error will be ignored ", reply.setClientData(request.getClientData());
targetFile, e); reply.setInternalContext(request.getInternalContext());
} return reply;
try
{
deleteFile(sourceFile);
}
catch (Exception e)
{
logger.error("Failed to delete source local temp file " + sourceFile, e);
}
reply.setTargetReference(targetRef.getEntry().getFileRef());
reply.setStatus(CREATED.value());
transformerDebug.popTransform(reply);
logger.trace("Sending successful {}, timeout {} ms", reply, timeout);
return new ResponseEntity<>(reply, HttpStatus.valueOf(reply.getStatus()));
} }
private Errors validateTransformRequest(final TransformRequest transformRequest) private Errors validateTransformRequest(final TransformRequest transformRequest)
@@ -530,6 +488,7 @@ public class TransformController
{ {
errors.rejectValue("internalContext", null, errorMessage); errors.rejectValue("internalContext", null, errorMessage);
} }
initialiseContext(request);
} }
private void initialiseContext(TransformRequest request) private void initialiseContext(TransformRequest request)
@@ -538,25 +497,6 @@ public class TransformController
request.setInternalContext(InternalContext.initialise(request.getInternalContext())); request.setInternalContext(InternalContext.initialise(request.getInternalContext()));
} }
private File getSourceFileFromDirectUrl(String directUrl)
{
File sourceFile = createTempFile("tmp", ".tmp");
try
{
FileUtils.copyURLToFile(new URL(directUrl), sourceFile);
}
catch (IllegalArgumentException e)
{
throw new TransformException(BAD_REQUEST.value(), "Direct Access Url is invalid.", e);
}
catch (IOException e)
{
throw new TransformException(BAD_REQUEST.value(), "Direct Access Url not found.", e);
}
return sourceFile;
}
protected Map<String, String> getTransformOptions(Map<String, String> requestParameters) protected Map<String, String> getTransformOptions(Map<String, String> requestParameters)
{ {
Map<String, String> transformOptions = new HashMap<>(requestParameters); Map<String, String> transformOptions = new HashMap<>(requestParameters);
@@ -565,6 +505,108 @@ public class TransformController
return transformOptions; return transformOptions;
} }
private InputStream getSharedFileStoreInputStream(String sourceReference)
{
ResponseEntity<Resource> responseEntity = alfrescoSharedFileStoreClient.retrieveFile(sourceReference);
final Resource body = responseEntity.getBody();
if (body == null)
{
String message = "Source file with reference: " + sourceReference + " is null or empty.";
logger.warn(message);
throw new TransformException(BAD_REQUEST.value(), message);
}
try
{
return body.getInputStream();
}
catch (IOException e)
{
String message = "Shared File Store reference is invalid.";
logger.warn(message);
throw new TransformException(BAD_REQUEST.value(), message, e);
}
}
private InputStream getInputStream(TransformRequest request, TransformReply reply)
{
final String directUrl = request.getTransformRequestOptions().getOrDefault(DIRECT_ACCESS_URL, "");
InputStream inputStream = null;
try
{
inputStream = directUrl.isBlank()
? getSharedFileStoreInputStream(request.getSourceReference())
: getDirectAccessUrlInputStream(directUrl);
}
catch (TransformException e)
{
reply.setStatus(e.getStatusCode());
reply.setErrorDetails(messageWithCause("Failed at reading the source file", e));
transformerDebug.logFailure(reply);
logger.trace("Failed to load source file (TransformException), sending " + reply);
}
catch (HttpClientErrorException e)
{
reply.setStatus(e.getStatusCode().value());
reply.setErrorDetails(messageWithCause("Failed at reading the source file", e));
transformerDebug.logFailure(reply);
logger.trace("Failed to load source file (HttpClientErrorException), sending " + reply, e);
}
return inputStream;
}
private boolean saveTargetFileInSharedFileStore(File targetFile, TransformReply reply)
{
FileRefResponse targetRef;
try
{
targetRef = alfrescoSharedFileStoreClient.saveFile(targetFile);
}
catch (TransformException e)
{
reply.setStatus(e.getStatusCode());
reply.setErrorDetails(messageWithCause("Failed at writing the transformed file", e));
transformerDebug.logFailure(reply);
logger.trace("Failed to save target file (TransformException), sending " + reply, e);
return false;
}
catch (HttpClientErrorException e)
{
reply.setStatus(e.getStatusCode().value());
reply.setErrorDetails(messageWithCause("Failed at writing the transformed file. ", e));
transformerDebug.logFailure(reply);
logger.trace("Failed to save target file (HttpClientErrorException), sending " + reply, e);
return false;
}
catch (Exception e)
{
reply.setStatus(INTERNAL_SERVER_ERROR.value());
reply.setErrorDetails(messageWithCause("Failed at writing the transformed file. ", e));
transformerDebug.logFailure(reply);
logger.trace("Failed to save target file (Exception), sending " + reply, e);
return false;
}
try
{
deleteFile(targetFile);
}
catch (Exception e)
{
logger.error("Failed to delete local temp target file. Error will be ignored ", e);
}
reply.setTargetReference(targetRef.getEntry().getFileRef());
reply.setStatus(CREATED.value());
return true;
}
/** /**
* Loads the file with the specified sourceReference from Alfresco Shared File Store * Loads the file with the specified sourceReference from Alfresco Shared File Store
* *
@@ -574,9 +616,7 @@ public class TransformController
*/ */
private File loadSourceFile(final String sourceReference, final String sourceExtension) private File loadSourceFile(final String sourceReference, final String sourceExtension)
{ {
ResponseEntity<Resource> responseEntity = alfrescoSharedFileStoreClient ResponseEntity<Resource> responseEntity = alfrescoSharedFileStoreClient.retrieveFile(sourceReference);
.retrieveFile(sourceReference);
probeTestTransform.incrementTransformerCount();
HttpHeaders headers = responseEntity.getHeaders(); HttpHeaders headers = responseEntity.getHeaders();
String filename = getFilenameFromContentDisposition(headers); String filename = getFilenameFromContentDisposition(headers);
@@ -621,7 +661,7 @@ public class TransformController
return sb.toString(); return sb.toString();
} }
private String getTransformerName(final File sourceFile, final String sourceMimetype, private String getTransformerName(long sourceSizeInBytes, final String sourceMimetype,
final String targetMimetype, final Map<String, String> transformOptions) final String targetMimetype, final Map<String, String> transformOptions)
{ {
// The transformOptions always contains sourceEncoding when sent to a T-Engine, even though it should not be // The transformOptions always contains sourceEncoding when sent to a T-Engine, even though it should not be
@@ -630,7 +670,6 @@ public class TransformController
String sourceEncoding = transformOptions.remove(SOURCE_ENCODING); String sourceEncoding = transformOptions.remove(SOURCE_ENCODING);
try try
{ {
final long sourceSizeInBytes = sourceFile.length();
final String transformerName = transformRegistry.findTransformerName(sourceMimetype, final String transformerName = transformRegistry.findTransformerName(sourceMimetype,
sourceSizeInBytes, targetMimetype, transformOptions, null); sourceSizeInBytes, targetMimetype, transformOptions, null);
if (transformerName == null) if (transformerName == null)
@@ -648,6 +687,16 @@ public class TransformController
} }
} }
private CustomTransformer getCustomTransformer(String transformName)
{
CustomTransformer customTransformer = customTransformersByName.get(transformName);
if (customTransformer == null)
{
throw new TransformException(BAD_REQUEST.value(), "Custom Transformer "+customTransformer+" not found");
}
return customTransformer;
}
public void transformImpl(String transformName, String sourceMimetype, String targetMimetype, public void transformImpl(String transformName, String sourceMimetype, String targetMimetype,
Map<String, String> transformOptions, File sourceFile, File targetFile) Map<String, String> transformOptions, File sourceFile, File targetFile)
{ {

View File

@@ -33,7 +33,8 @@ import org.alfresco.transform.base.probes.ProbeTestTransform;
/** /**
* Interface to be implemented by transform specific code. Provides information about the t-engine as a whole. * Interface to be implemented by transform specific code. Provides information about the t-engine as a whole.
* Also see {@link CustomTransformer} which provides the code that performs transformation. There may be several * Also see {@link CustomTransformer} which provides the code that performs transformation. There may be several
* in a single t-engine. * in a single t-engine. So that it is automatically picked up, it must exist in a package under
* {@code org.alfresco.transform} and have the Spring {@code @Component} annotation.
*/ */
public interface TransformEngine public interface TransformEngine
{ {

View File

@@ -55,7 +55,6 @@ public class TransformInterceptor extends HandlerInterceptorAdapter
public void afterCompletion(HttpServletRequest request, public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex) HttpServletResponse response, Object handler, Exception ex)
{ {
// TargetFile cannot be deleted until completion, otherwise 0 bytes are sent.
deleteFile(request, SOURCE_FILE); deleteFile(request, SOURCE_FILE);
deleteFile(request, TARGET_FILE); deleteFile(request, TARGET_FILE);

View File

@@ -0,0 +1,76 @@
/*
* #%L
* Alfresco Transform Core
* %%
* Copyright (C) 2005 - 2022 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.base;
import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Map;
/**
* Allows {@link CustomTransformer} implementations to interact with the base t-engine.
*/
public interface TransformManager
{
/**
* Allows a {@link CustomTransformer} to use a local source {@code File} rather than the supplied {@code InputStream}.
* The file will be deleted once the request is completed.
* If possible this method should be avoided as it is better not to leave content on disk.
* @throws IllegalStateException if this method has already been called.
*/
File createSourceFile();
/**
* Allows a {@link CustomTransformer} to use a local target {@code File} rather than the supplied {@code OutputStream}.
* The file will be deleted once the request is completed.
* If possible this method should be avoided as it is better not to leave content on disk.
* @throws IllegalStateException if this method has already been called. A call to {@link #respondWithFragment(Integer)}
* allows the method to be called again.
*/
File createTargetFile();
// TODO: Do we want to support the following?
/**
* Allows a single transform request to have multiple transform responses. For example images from a video at
* different time offsets or different pages of a document. Following a call to this method a transform response is
* made with output that has already been generated. The {@code CustomTransformer} may then use the returned
* {@code outputStream} to generate more output for the next transform response.
* {@code CustomTransformer} to throw an {@code Exception} when it finds it has no more output.
* @param index returned with the response, so that it may be distinguished from other responses. Renditions
* use the index as an offset into elements. A {@code null} value indicates that there is no more output
* so there should not be another transform reply once the
* {@link CustomTransformer#transform(String, InputStream, String, OutputStream, Map, TransformManager)}
* returns.
* @throws IllegalStateException if a synchronous (http) request has been made as this only works with messages
* on queues.
*/
// This works because all the state is in the TransformResponse and the t-router will just see each response as
// something to either return to the client or pass to the next stage in a pipeline. We might be able to enhance
// the logging to include the index. We may also wish to modify the client data or just make the index available
// in the message.
OutputStream respondWithFragment(Integer index);
}

View File

@@ -0,0 +1,245 @@
/*
* #%L
* Alfresco Transform Core
* %%
* Copyright (C) 2005 - 2022 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.base;
import org.alfresco.transform.base.fs.FileManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
@Component
public class TransformManagerImpl implements TransformManager
{
private static final Logger logger = LoggerFactory.getLogger(TransformManagerImpl.class);
private HttpServletRequest request;
private InputStream inputStream;
private OutputStream outputStream;
private String sourceMimetype;
private String targetMimetype;
private File sourceFile;
private File targetFile;
private boolean createSourceFileCalled;
private boolean createTargetFileCalled;
private boolean targetFileCreated;
private TransformManagerImpl()
{
}
public void init()
{
request = null;
inputStream = null;
outputStream = null;
sourceFile = null;
targetFile = null;
createSourceFileCalled = false;
createTargetFileCalled = false;
targetFileCreated = false;
}
public void setRequest(HttpServletRequest request)
{
this.request = request;
}
public void setInputStream(InputStream inputStream)
{
this.inputStream = inputStream;
}
public void setOutputStream(OutputStream outputStream)
{
this.outputStream = outputStream;
}
public void setSourceMimetype(String sourceMimetype)
{
this.sourceMimetype = sourceMimetype;
}
public void setTargetMimetype(String targetMimetype)
{
this.targetMimetype = targetMimetype;
}
public File getSourceFile()
{
return sourceFile;
}
public void setSourceFile(File sourceFile)
{
this.sourceFile = sourceFile;
}
public File getTargetFile() {
return targetFile;
}
void setTargetFile(File targetFile)
{
this.targetFile = targetFile;
}
public boolean isCreateSourceFileCalled()
{
return createSourceFileCalled;
}
public boolean isCreateTargetFileCalled()
{
return createTargetFileCalled;
}
@Override public File createSourceFile()
{
if (createSourceFileCalled)
{
throw new IllegalStateException("createSourceFile has already been called");
}
createSourceFileCalled = true;
if (sourceFile == null)
{
sourceFile = FileManager.createSourceFile(request, inputStream, sourceMimetype);
}
return sourceFile;
}
@Override public File createTargetFile()
{
if (createTargetFileCalled)
{
throw new IllegalStateException("createTargetFile has already been called");
}
createTargetFileCalled = true;
if (targetFile == null)
{
targetFile = FileManager.createTargetFile(request, sourceMimetype, targetMimetype);
targetFileCreated = true;
}
return targetFile;
}
public void ifUsedCopyTargetFileToOutputStream()
{
if (targetFileCreated)
{
FileManager.copyFileToOutputStream(targetFile, outputStream);
}
}
public void deleteSourceFileIfExists()
{
if (sourceFile != null && sourceFile.delete() == false)
{
logger.error("Failed to delete temporary source file "+sourceFile.getPath());
}
sourceFile = null;
}
public void deleteTargetFileIfExists()
{
if (targetFile != null && targetFile.delete() == false)
{
logger.error("Failed to delete temporary target file "+targetFile.getPath());
}
targetFile = null;
targetFileCreated = false;
}
@Override
public OutputStream respondWithFragment(Integer index)
{
if (request != null)
{
throw new IllegalStateException(
" Fragments may only be sent with asynchronous requests. This a synchronous http request");
}
throw new UnsupportedOperationException("Not currently supported");
}
public static Builder builder()
{
return new Builder();
}
public static class Builder
{
private final TransformManagerImpl transformManager = new TransformManagerImpl();
public TransformManagerImpl build()
{
return transformManager;
}
public Builder withSourceMimetype(String sourceMimetype)
{
transformManager.sourceMimetype = sourceMimetype;
return this;
}
public Builder withTargetMimetype(String targetMimetype)
{
transformManager.targetMimetype = targetMimetype;
return this;
}
public Builder withInputStream(InputStream inputStream)
{
transformManager.inputStream = inputStream;
return this;
}
public Builder withOutputStream(OutputStream outputStream)
{
transformManager.outputStream = outputStream;
return this;
}
public Builder withRequest(HttpServletRequest request)
{
transformManager.request = request;
return this;
}
public Builder withTargetFile(File targetFile)
{
transformManager.targetFile = targetFile;
return this;
}
}
}

View File

@@ -26,6 +26,8 @@
*/ */
package org.alfresco.transform.base.fs; package org.alfresco.transform.base.fs;
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
import static org.alfresco.transform.common.ExtensionService.getExtensionForMimetype;
import static org.springframework.http.HttpHeaders.CONTENT_DISPOSITION; import static org.springframework.http.HttpHeaders.CONTENT_DISPOSITION;
import static org.springframework.http.HttpStatus.BAD_REQUEST; import static org.springframework.http.HttpStatus.BAD_REQUEST;
import static org.springframework.http.HttpStatus.INSUFFICIENT_STORAGE; import static org.springframework.http.HttpStatus.INSUFFICIENT_STORAGE;
@@ -35,9 +37,11 @@ import static org.springframework.util.StringUtils.getFilenameExtension;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URL;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.Arrays; import java.util.Arrays;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
@@ -58,12 +62,44 @@ public class FileManager
public static final String TARGET_FILE = "targetFile"; public static final String TARGET_FILE = "targetFile";
private static final String FILENAME = "filename="; private static final String FILENAME = "filename=";
public static File createTargetFile(HttpServletRequest request, String filename) public static File createSourceFile(HttpServletRequest request, InputStream inputStream, String sourceMimetype)
{ {
File file = buildFile(filename); try
request.setAttribute(TARGET_FILE, file); {
String extension = "."+getExtensionForMimetype(sourceMimetype);
File file = TempFileProvider.createTempFile("source_", extension);
Files.copy(inputStream, file.toPath(), REPLACE_EXISTING);
if (request != null)
{
request.setAttribute(SOURCE_FILE, file);
}
LogEntry.setSource(file.getName(), file.length());
return file; return file;
} }
catch (Exception e)
{
throw new TransformException(INSUFFICIENT_STORAGE.value(), "Failed to store the source file", e);
}
}
public static File createTargetFile(HttpServletRequest request, String sourceMimetype, String targetMimetype)
{
try
{
String extension = "."+ExtensionService.getExtensionForTargetMimetype(targetMimetype, sourceMimetype);
File file = TempFileProvider.createTempFile("target_", extension);
if (request != null)
{
request.setAttribute(TARGET_FILE, file);
}
LogEntry.setTarget(file.getName());
return file;
}
catch (Exception e)
{
throw new TransformException(INSUFFICIENT_STORAGE.value(), "Failed to create the target file", e);
}
}
public static File buildFile(String filename) public static File buildFile(String filename)
{ {
@@ -97,8 +133,7 @@ public class FileManager
{ {
try try
{ {
Files.copy(multipartFile.getInputStream(), file.toPath(), Files.copy(multipartFile.getInputStream(), file.toPath(), REPLACE_EXISTING);
StandardCopyOption.REPLACE_EXISTING);
} }
catch (IOException e) catch (IOException e)
{ {
@@ -111,7 +146,7 @@ public class FileManager
{ {
try try
{ {
Files.copy(body.getInputStream(), file.toPath(), StandardCopyOption.REPLACE_EXISTING); Files.copy(body.getInputStream(), file.toPath(), REPLACE_EXISTING);
} }
catch (IOException e) catch (IOException e)
{ {
@@ -176,16 +211,46 @@ public class FileManager
return sourceFilename.substring(0, sourceFilename.length() - ext.length() - 1) + '.' + targetExtension; return sourceFilename.substring(0, sourceFilename.length() - ext.length() - 1) + '.' + targetExtension;
} }
public static File createSourceFile(HttpServletRequest request, MultipartFile multipartFile) public static InputStream getMultipartFileInputStream(MultipartFile sourceMultipartFile)
{ {
String filename = multipartFile.getOriginalFilename(); InputStream inputStream;
long size = multipartFile.getSize(); if (sourceMultipartFile == null)
filename = checkFilename(true, filename); {
File file = TempFileProvider.createTempFile("source_", "_" + filename); throw new TransformException(BAD_REQUEST.value(), "Required request part 'file' is not present");
request.setAttribute(SOURCE_FILE, file); }
save(multipartFile, file); try
LogEntry.setSource(filename, size); {
return file; inputStream = sourceMultipartFile.getInputStream();
}
catch (IOException e)
{
throw new TransformException(BAD_REQUEST.value(), "Unable to read the sourceMultipartFile.", e);
}
return inputStream;
}
public static InputStream getDirectAccessUrlInputStream(String directUrl)
{
try
{
return new URL(directUrl).openStream();
}
catch (IOException e)
{
throw new TransformException(BAD_REQUEST.value(), "Direct Access Url is invalid.", e);
}
}
public static void copyFileToOutputStream(File targetFile, OutputStream outputStream)
{
try
{
Files.copy(targetFile.toPath(), outputStream);
}
catch (IOException e)
{
throw new TransformException(INTERNAL_SERVER_ERROR.value(), "Failed to copy targetFile to outputStream.", e);
}
} }
@SuppressWarnings("ResultOfMethodCallIgnored") @SuppressWarnings("ResultOfMethodCallIgnored")

View File

@@ -30,7 +30,7 @@ import com.fasterxml.jackson.core.JsonProcessingException;
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.alfresco.transform.base.CustomTransformer; import org.alfresco.transform.base.CustomTransformer;
import org.alfresco.transform.common.TransformException; import org.alfresco.transform.base.TransformManager;
import org.slf4j.Logger; import org.slf4j.Logger;
import java.io.File; import java.io.File;
@@ -51,7 +51,7 @@ import java.util.Set;
import java.util.StringTokenizer; import java.util.StringTokenizer;
import java.util.TreeMap; import java.util.TreeMap;
import static org.alfresco.transform.base.metadataExtractors.AbstractMetadataExtractor.Type.EXTRACTOR; import static org.alfresco.transform.base.metadataExtractors.AbstractMetadataExtractor.Type.EMBEDDER;
/** /**
* Helper methods for metadata extract and embed. * Helper methods for metadata extract and embed.
@@ -151,16 +151,30 @@ public abstract class AbstractMetadataExtractor implements CustomTransformer
return getClass().getSimpleName(); return getClass().getSimpleName();
} }
public abstract Map<String, Serializable> extractMetadata(String sourceMimetype, Map<String, String> transformOptions, @Override
File sourceFile) throws Exception; public void transform(String sourceMimetype, InputStream inputStream,
String targetMimetype, OutputStream outputStream,
public void embedMetadata(String sourceMimetype, Map<String, String> transformOptions, Map<String, String> transformOptions, TransformManager transformManager) throws Exception
String sourceEncoding, InputStream inputStream,
String targetEncoding, OutputStream outputStream) throws Exception
{ {
// TODO if (type == EMBEDDER)
throw new TransformException(500, "TODO embedMetadata"); {
embedMetadata(sourceMimetype, inputStream, targetMimetype, outputStream, transformOptions, transformManager);
} }
else
{
extractMetadata(sourceMimetype, inputStream, targetMimetype, outputStream, transformOptions, transformManager);
}
}
public void embedMetadata(String sourceMimetype, InputStream inputStream,
String targetMimetype, OutputStream outputStream,
Map<String, String> transformOptions, TransformManager transformManager) throws Exception
{
File sourceFile = transformManager.createSourceFile();
File targetFile = transformManager.createTargetFile();
embedMetadata(sourceMimetype, targetMimetype, transformOptions, sourceFile, targetFile);
}
public void embedMetadata(String sourceMimetype, String targetMimetype, Map<String, String> transformOptions, public void embedMetadata(String sourceMimetype, String targetMimetype, Map<String, String> transformOptions,
File sourceFile, File targetFile) throws Exception File sourceFile, File targetFile) throws Exception
{ {
@@ -493,27 +507,13 @@ public abstract class AbstractMetadataExtractor implements CustomTransformer
return true; return true;
} }
@Override public void extractMetadata(String sourceMimetype, InputStream inputStream,
public void transform(String sourceMimetype, String sourceEncoding, InputStream inputStream, String targetMimetype, OutputStream outputStream,
String targetMimetype, String targetEncoding, OutputStream outputStream, Map<String, String> transformOptions, TransformManager transformManager) throws Exception
Map<String, String> transformOptions) throws Exception
{ {
if (type == EXTRACTOR) File sourceFile = transformManager.createSourceFile();
{ File targetFile = transformManager.createTargetFile();
extractMetadata(sourceMimetype, transformOptions, sourceEncoding, inputStream, targetEncoding, outputStream); extractMetadata(sourceMimetype, transformOptions, sourceFile, targetFile);
}
else
{
embedMetadata(sourceMimetype, transformOptions, sourceEncoding, inputStream, targetEncoding, outputStream);
}
}
public void extractMetadata(String sourceMimetype, Map<String, String> transformOptions,
String sourceEncoding, InputStream inputStream,
String targetEncoding, OutputStream outputStream) throws Exception
{
// TODO
throw new TransformException(500, "TODO extractMetadata");
} }
/** /**
@@ -539,6 +539,9 @@ public abstract class AbstractMetadataExtractor implements CustomTransformer
} }
} }
public abstract Map<String, Serializable> extractMetadata(String sourceMimetype, Map<String, String> transformOptions,
File sourceFile) throws Exception;
private Map<String, Set<String>> getExtractMappingFromOptions(Map<String, String> transformOptions, Map<String, private Map<String, Set<String>> getExtractMappingFromOptions(Map<String, String> transformOptions, Map<String,
Set<String>> defaultExtractMapping) Set<String>> defaultExtractMapping)
{ {

View File

@@ -0,0 +1,55 @@
/*
* #%L
* Alfresco Transform Core
* %%
* Copyright (C) 2005 - 2022 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.base.util;
import org.alfresco.transform.base.CustomTransformer;
import org.alfresco.transform.base.TransformManager;
import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Map;
/**
* Helper interface for older code that uses Files rather than InputStreams and OutputStreams.
* If you, can refactor your code to NOT use Files.
*/
public interface CustomTransformerFileAdaptor extends CustomTransformer
{
@Override
default void transform(String sourceMimetype, InputStream inputStream,
String targetMimetype, OutputStream outputStream,
Map<String, String> transformOptions, TransformManager transformManager) throws Exception
{
File sourceFile = transformManager.createSourceFile();
File targetFile = transformManager.createTargetFile();
transform(sourceMimetype, targetMimetype, transformOptions, sourceFile, targetFile);
}
void transform(String sourceMimetype, String targetMimetype, Map<String, String> transformOptions,
File sourceFile, File targetFile) throws Exception;
}

View File

@@ -24,15 +24,35 @@
* 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.transform; package org.alfresco.transform.base.util;
import java.io.InputStream; import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.Map;
public interface CustomTransformer public class OutputStreamLengthRecorder extends FilterOutputStream
{ {
void transform(String transformerName, String sourceMimetype, String targetMimetype, private long byteCount;
Map<String, String> transformOptions,
InputStream inputStream, OutputStream outputStream) throws Exception; public OutputStreamLengthRecorder(OutputStream outputStream)
{
super(outputStream);
}
public long getLength()
{
return byteCount;
}
public void write(int b) throws IOException
{
super.write(b);
byteCount++;
}
public void write(byte b[], int off, int len) throws IOException
{
super.write(b, off, len);
byteCount += len;
}
} }

View File

@@ -26,6 +26,9 @@
*/ */
package org.alfresco.transform.base.util; package org.alfresco.transform.base.util;
import java.io.File;
import java.io.InputStream;
public class Util public class Util
{ {
/** /**

View File

@@ -26,11 +26,12 @@
*/ */
package org.alfresco.transform.imagemagick.transformers; package org.alfresco.transform.imagemagick.transformers;
import org.alfresco.transform.base.CustomTransformer; import org.alfresco.transform.base.TransformManager;
import org.alfresco.transform.base.executors.AbstractCommandExecutor; import org.alfresco.transform.base.executors.AbstractCommandExecutor;
import org.alfresco.transform.base.executors.RuntimeExec; import org.alfresco.transform.base.executors.RuntimeExec;
import org.alfresco.transform.imagemagick.ImageMagickOptionsBuilder; import org.alfresco.transform.base.util.CustomTransformerFileAdaptor;
import org.alfresco.transform.common.TransformException; import org.alfresco.transform.common.TransformException;
import org.alfresco.transform.imagemagick.ImageMagickOptionsBuilder;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -63,7 +64,7 @@ import static org.alfresco.transform.common.RequestParamMap.THUMBNAIL;
import static org.alfresco.transform.common.RequestParamMap.TIMEOUT; import static org.alfresco.transform.common.RequestParamMap.TIMEOUT;
@Component @Component
public class ImageMagickTransformer extends AbstractCommandExecutor implements CustomTransformer public class ImageMagickTransformer extends AbstractCommandExecutor implements CustomTransformerFileAdaptor
{ {
@Value("${transform.core.imagemagick.exe}") @Value("${transform.core.imagemagick.exe}")
private String exe; private String exe;
@@ -150,14 +151,7 @@ public class ImageMagickTransformer extends AbstractCommandExecutor implements C
} }
@Override @Override
public void transform(String sourceMimetype, String sourceEncoding, InputStream inputStream, public void transform(String sourceMimetype, String targetMimetype, Map<String, String> transformOptions,
String targetMimetype, String targetEncoding, OutputStream outputStream,
Map<String, String> transformOptions) throws Exception
{
throw new TransformException(500, "TODO ImageMagick transform");
}
public void transform(String transformName, String sourceMimetype, String targetMimetype,
Map<String, String> transformOptions,
File sourceFile, File targetFile) throws TransformException File sourceFile, File targetFile) throws TransformException
{ {
final String options = ImageMagickOptionsBuilder final String options = ImageMagickOptionsBuilder

View File

@@ -28,7 +28,8 @@ package org.alfresco.transform.libreoffice.transformers;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.sun.star.task.ErrorCodeIOException; import com.sun.star.task.ErrorCodeIOException;
import org.alfresco.transform.base.CustomTransformer; import org.alfresco.transform.base.TransformManager;
import org.alfresco.transform.base.util.CustomTransformerFileAdaptor;
import org.alfresco.transform.common.TransformException; import org.alfresco.transform.common.TransformException;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDDocument;
@@ -58,7 +59,7 @@ import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR;
* transformation logic in the same JVM (check the {@link JodConverter} implementation). * transformation logic in the same JVM (check the {@link JodConverter} implementation).
*/ */
@Component @Component
public class LibreOfficeTransformer implements CustomTransformer public class LibreOfficeTransformer implements CustomTransformerFileAdaptor
{ {
private static final Logger logger = LoggerFactory.getLogger(LibreOfficeTransformer.class); private static final Logger logger = LoggerFactory.getLogger(LibreOfficeTransformer.class);
@@ -130,20 +131,8 @@ public class LibreOfficeTransformer implements CustomTransformer
} }
@Override @Override
public void transform(String sourceMimetype, String sourceEncoding, InputStream inputStream, public void transform(String sourceMimetype, String targetMimetype, Map<String, String> transformOptions,
String targetMimetype, String targetEncoding, OutputStream outputStream,
Map<String, String> transformOptions) throws Exception
{
throw new TransformException(500, "TODO LibreOffice transform");
}
public void transform(String transformName, String sourceMimetype, String targetMimetype, Map<String, String> transformOptions,
File sourceFile, File targetFile) File sourceFile, File targetFile)
{
call(sourceFile, targetFile);
}
public void call(File sourceFile, File targetFile, String... args)
{ {
try try
{ {

View File

@@ -27,6 +27,7 @@
package org.alfresco.transform.misc.metadataExtractors; package org.alfresco.transform.misc.metadataExtractors;
import org.alfresco.transform.base.CustomTransformer; import org.alfresco.transform.base.CustomTransformer;
import org.alfresco.transform.base.TransformManager;
import org.alfresco.transform.base.metadataExtractors.AbstractMetadataExtractor; import org.alfresco.transform.base.metadataExtractors.AbstractMetadataExtractor;
import org.alfresco.transform.common.TransformException; import org.alfresco.transform.common.TransformException;
import org.slf4j.Logger; import org.slf4j.Logger;
@@ -85,19 +86,6 @@ public class HtmlMetadataExtractor extends AbstractMetadataExtractor implements
return getClass().getSimpleName(); return getClass().getSimpleName();
} }
@Override public void transform(String sourceMimetype, String sourceEncoding, InputStream inputStream,
String targetMimetype, String targetEncoding, OutputStream outputStream,
Map<String, String> transformOptions) throws Exception
{
throw new TransformException(500, "TODO HtmlMetadataExtractor transform");
}
public void extractMetadata(String sourceMimetype, String targetMimetype, Map<String, String> transformOptions,
File sourceFile, File targetFile) throws Exception
{
extractMetadata(sourceMimetype, transformOptions, sourceFile, targetFile);
}
@Override @Override
public Map<String, Serializable> extractMetadata(String sourceMimetype, Map<String, String> transformOptions, public Map<String, Serializable> extractMetadata(String sourceMimetype, Map<String, String> transformOptions,
File sourceFile) throws Exception File sourceFile) throws Exception

View File

@@ -27,6 +27,7 @@
package org.alfresco.transform.misc.metadataExtractors; package org.alfresco.transform.misc.metadataExtractors;
import org.alfresco.transform.base.CustomTransformer; import org.alfresco.transform.base.CustomTransformer;
import org.alfresco.transform.base.TransformManager;
import org.alfresco.transform.base.metadataExtractors.AbstractMetadataExtractor; import org.alfresco.transform.base.metadataExtractors.AbstractMetadataExtractor;
import org.alfresco.transform.common.TransformException; import org.alfresco.transform.common.TransformException;
import org.slf4j.Logger; import org.slf4j.Logger;
@@ -87,19 +88,6 @@ public class RFC822MetadataExtractor extends AbstractMetadataExtractor implement
super(EXTRACTOR, logger); super(EXTRACTOR, logger);
} }
@Override public void transform(String sourceMimetype, String sourceEncoding, InputStream inputStream,
String targetMimetype, String targetEncoding, OutputStream outputStream,
Map<String, String> transformOptions) throws Exception
{
throw new TransformException(500, "TODO RFC822MetadataExtractor transform");
}
public void extractMetadata(String sourceMimetype, String targetMimetype, Map<String, String> transformOptions,
File sourceFile, File targetFile) throws Exception
{
extractMetadata(sourceMimetype, transformOptions, sourceFile, targetFile);
}
@Override @Override
public Map<String, Serializable> extractMetadata(String sourceMimetype, Map<String, String> transformOptions, public Map<String, Serializable> extractMetadata(String sourceMimetype, Map<String, String> transformOptions,
File sourceFile) throws Exception File sourceFile) throws Exception

View File

@@ -27,8 +27,8 @@
package org.alfresco.transform.misc.transformers; package org.alfresco.transform.misc.transformers;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import org.alfresco.transform.base.CustomTransformer; import org.alfresco.transform.base.TransformManager;
import org.alfresco.transform.common.TransformException; import org.alfresco.transform.base.util.CustomTransformerFileAdaptor;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream; import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
import org.slf4j.Logger; import org.slf4j.Logger;
@@ -64,7 +64,7 @@ import static org.alfresco.transform.common.Mimetype.MIMETYPE_IMAGE_JPEG;
* @since 4.0 * @since 4.0
*/ */
@Component @Component
public class AppleIWorksContentTransformer implements CustomTransformer public class AppleIWorksContentTransformer implements CustomTransformerFileAdaptor
{ {
private static final Logger logger = LoggerFactory.getLogger( private static final Logger logger = LoggerFactory.getLogger(
AppleIWorksContentTransformer.class); AppleIWorksContentTransformer.class);
@@ -84,15 +84,9 @@ public class AppleIWorksContentTransformer implements CustomTransformer
return "appleIWorks"; return "appleIWorks";
} }
@Override public void transform(String sourceMimetype, String sourceEncoding, InputStream inputStream, @Override
String targetMimetype, String targetEncoding, OutputStream outputStream, public void transform(String sourceMimetype, String targetMimetype, Map<String, String> transformOptions,
Map<String, String> transformOptions) throws Exception File sourceFile, File targetFile)
{
throw new TransformException(500, "TODO appleIWorks transform");
}
public void transform(final String sourceMimetype, final String targetMimetype, final Map<String, String> parameters,
final File sourceFile, final File targetFile)
{ {
logger.debug("Performing IWorks to jpeg transform with sourceMimetype={} targetMimetype={}", logger.debug("Performing IWorks to jpeg transform with sourceMimetype={} targetMimetype={}",
sourceMimetype, targetMimetype); sourceMimetype, targetMimetype);

View File

@@ -26,9 +26,9 @@
*/ */
package org.alfresco.transform.misc.transformers; package org.alfresco.transform.misc.transformers;
import org.alfresco.transform.base.CustomTransformer; import org.alfresco.transform.base.TransformManager;
import org.alfresco.transform.base.fs.FileManager; import org.alfresco.transform.base.fs.FileManager;
import org.alfresco.transform.common.TransformException; import org.alfresco.transform.base.util.CustomTransformerFileAdaptor;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -69,7 +69,7 @@ import static org.alfresco.transform.common.Mimetype.MIMETYPE_TEXT_PLAIN;
* </p> * </p>
*/ */
@Component @Component
public class EMLTransformer implements CustomTransformer public class EMLTransformer implements CustomTransformerFileAdaptor
{ {
private static final Logger logger = LoggerFactory.getLogger(EMLTransformer.class); private static final Logger logger = LoggerFactory.getLogger(EMLTransformer.class);
@@ -82,15 +82,9 @@ public class EMLTransformer implements CustomTransformer
return "rfc822"; return "rfc822";
} }
@Override public void transform(String sourceMimetype, String sourceEncoding, InputStream inputStream, @Override
String targetMimetype, String targetEncoding, OutputStream outputStream, public void transform(String sourceMimetype, String targetMimetype, Map<String, String> transformOptions,
Map<String, String> transformOptions) throws Exception File sourceFile, File targetFile) throws Exception
{
throw new TransformException(500, "TODO rfc822 transform");
}
public void transform(final String sourceMimetype, final String targetMimetype, final Map<String, String> parameters,
final File sourceFile, final File targetFile) throws Exception
{ {
logger.debug("Performing RFC822 to text transform."); logger.debug("Performing RFC822 to text transform.");
// Use try with resource // Use try with resource

View File

@@ -26,8 +26,7 @@
*/ */
package org.alfresco.transform.misc.transformers; package org.alfresco.transform.misc.transformers;
import org.alfresco.transform.base.CustomTransformer; import org.alfresco.transform.base.util.CustomTransformerFileAdaptor;
import org.alfresco.transform.common.TransformException;
import org.htmlparser.Parser; import org.htmlparser.Parser;
import org.htmlparser.beans.StringBean; import org.htmlparser.beans.StringBean;
import org.htmlparser.util.ParserException; import org.htmlparser.util.ParserException;
@@ -38,8 +37,6 @@ import org.springframework.stereotype.Component;
import java.io.BufferedWriter; import java.io.BufferedWriter;
import java.io.File; import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter; import java.io.OutputStreamWriter;
import java.io.Writer; import java.io.Writer;
import java.net.URLConnection; import java.net.URLConnection;
@@ -77,7 +74,7 @@ import static org.alfresco.transform.common.RequestParamMap.SOURCE_ENCODING;
* @see <a href="http://sourceforge.net/tracker/?func=detail&aid=1644504&group_id=24399&atid=381401">HTML Parser</a> * @see <a href="http://sourceforge.net/tracker/?func=detail&aid=1644504&group_id=24399&atid=381401">HTML Parser</a>
*/ */
@Component @Component
public class HtmlParserContentTransformer implements CustomTransformer public class HtmlParserContentTransformer implements CustomTransformerFileAdaptor
{ {
private static final Logger logger = LoggerFactory.getLogger( private static final Logger logger = LoggerFactory.getLogger(
HtmlParserContentTransformer.class); HtmlParserContentTransformer.class);
@@ -89,17 +86,11 @@ public class HtmlParserContentTransformer implements CustomTransformer
} }
@Override @Override
public void transform(String sourceMimetype, String sourceEncoding, InputStream inputStream, public void transform(final String sourceMimetype, final String targetMimetype,
String targetMimetype, String targetEncoding, OutputStream outputStream, final Map<String, String> transformOptions,
Map<String, String> transformOptions) throws Exception
{
throw new TransformException(500, "TODO html transform");
}
public void transform(final String sourceMimetype, final String targetMimetype, final Map<String, String> parameters,
final File sourceFile, final File targetFile) throws Exception final File sourceFile, final File targetFile) throws Exception
{ {
String sourceEncoding = parameters.get(SOURCE_ENCODING); String sourceEncoding = transformOptions.get(SOURCE_ENCODING);
checkEncodingParameter(sourceEncoding, SOURCE_ENCODING); checkEncodingParameter(sourceEncoding, SOURCE_ENCODING);
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())

View File

@@ -26,8 +26,8 @@
*/ */
package org.alfresco.transform.misc.transformers; package org.alfresco.transform.misc.transformers;
import org.alfresco.transform.base.CustomTransformer; import org.alfresco.transform.base.TransformManager;
import org.alfresco.transform.common.TransformException; import org.alfresco.transform.base.util.CustomTransformerFileAdaptor;
import org.apache.poi.openxml4j.opc.OPCPackage; import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.openxml4j.opc.PackagePart; import org.apache.poi.openxml4j.opc.PackagePart;
import org.apache.poi.openxml4j.opc.PackageRelationship; import org.apache.poi.openxml4j.opc.PackageRelationship;
@@ -58,7 +58,7 @@ import java.util.Map;
* @author eknizat * @author eknizat
*/ */
@Component @Component
public class OOXMLThumbnailContentTransformer implements CustomTransformer public class OOXMLThumbnailContentTransformer implements CustomTransformerFileAdaptor
{ {
private static final Logger logger = LoggerFactory.getLogger( private static final Logger logger = LoggerFactory.getLogger(
OOXMLThumbnailContentTransformer.class); OOXMLThumbnailContentTransformer.class);
@@ -69,13 +69,6 @@ public class OOXMLThumbnailContentTransformer implements CustomTransformer
} }
@Override @Override
public void transform(String sourceMimetype, String sourceEncoding, InputStream inputStream,
String targetMimetype, String targetEncoding, OutputStream outputStream,
Map<String, String> transformOptions) throws Exception
{
throw new TransformException(500, "TODO ooXmlThumbnail transform");
}
public void transform(final String sourceMimetype, final String targetMimetype, final Map<String, String> parameters, public void transform(final String sourceMimetype, final String targetMimetype, final Map<String, String> parameters,
final File sourceFile, final File targetFile) throws Exception final File sourceFile, final File targetFile) throws Exception
{ {

View File

@@ -26,8 +26,7 @@
*/ */
package org.alfresco.transform.misc.transformers; package org.alfresco.transform.misc.transformers;
import org.alfresco.transform.base.CustomTransformer; import org.alfresco.transform.base.util.CustomTransformerFileAdaptor;
import org.alfresco.transform.common.TransformException;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -37,9 +36,7 @@ import java.io.BufferedWriter;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter; import java.io.OutputStreamWriter;
import java.io.Reader; import java.io.Reader;
import java.io.Writer; import java.io.Writer;
@@ -64,7 +61,7 @@ import static org.alfresco.transform.common.RequestParamMap.TARGET_ENCODING;
* @author eknizat * @author eknizat
*/ */
@Component @Component
public class StringExtractingContentTransformer implements CustomTransformer public class StringExtractingContentTransformer implements CustomTransformerFileAdaptor
{ {
private static final Logger logger = LoggerFactory.getLogger(StringExtractingContentTransformer.class); private static final Logger logger = LoggerFactory.getLogger(StringExtractingContentTransformer.class);
@@ -82,18 +79,11 @@ public class StringExtractingContentTransformer implements CustomTransformer
* be unformatted but valid. * be unformatted but valid.
*/ */
@Override @Override
public void transform(String sourceMimetype, String sourceEncoding, InputStream inputStream, public void transform(final String sourceMimetype, final String targetMimetype, final Map<String, String> transformOptions,
String targetMimetype, String targetEncoding, OutputStream outputStream,
Map<String, String> transformOptions) throws Exception
{
throw new TransformException(500, "TODO string transform");
}
public void transform(final String sourceMimetype, final String targetMimetype, final Map<String, String> parameters,
final File sourceFile, final File targetFile) throws Exception final File sourceFile, final File targetFile) throws Exception
{ {
String sourceEncoding = parameters.get(SOURCE_ENCODING); String sourceEncoding = transformOptions.get(SOURCE_ENCODING);
String targetEncoding = parameters.get(TARGET_ENCODING); String targetEncoding = transformOptions.get(TARGET_ENCODING);
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
{ {

View File

@@ -26,8 +26,8 @@
*/ */
package org.alfresco.transform.misc.transformers; package org.alfresco.transform.misc.transformers;
import org.alfresco.transform.base.CustomTransformer; import org.alfresco.transform.base.TransformManager;
import org.alfresco.transform.common.TransformException; import org.alfresco.transform.base.util.CustomTransformerFileAdaptor;
import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream; import org.apache.pdfbox.pdmodel.PDPageContentStream;
@@ -66,7 +66,7 @@ import static org.alfresco.transform.common.RequestParamMap.SOURCE_ENCODING;
* @author eknizat * @author eknizat
*/ */
@Component @Component
public class TextToPdfContentTransformer implements CustomTransformer public class TextToPdfContentTransformer implements CustomTransformerFileAdaptor
{ {
private static final Logger logger = LoggerFactory.getLogger(TextToPdfContentTransformer.class); private static final Logger logger = LoggerFactory.getLogger(TextToPdfContentTransformer.class);
@@ -113,17 +113,13 @@ public class TextToPdfContentTransformer implements CustomTransformer
return "textToPdf"; return "textToPdf";
} }
@Override public void transform(String sourceMimetype, String sourceEncoding, InputStream inputStream, @Override
String targetMimetype, String targetEncoding, OutputStream outputStream, public void transform(final String sourceMimetype, final String targetMimetype, final Map<String,
Map<String, String> transformOptions) throws Exception String> transformOptions,
{
throw new TransformException(500, "TODO textToPdf transform");
}
public void transform(final String sourceMimetype, final String targetMimetype, final Map<String, String> parameters,
final File sourceFile, final File targetFile) throws Exception final File sourceFile, final File targetFile) throws Exception
{ {
String sourceEncoding = parameters.get(SOURCE_ENCODING); String sourceEncoding = transformOptions.get(SOURCE_ENCODING);
String stringPageLimit = parameters.get(PAGE_LIMIT); String stringPageLimit = transformOptions.get(PAGE_LIMIT);
int pageLimit = -1; int pageLimit = -1;
if (stringPageLimit != null) if (stringPageLimit != null)
{ {

View File

@@ -26,9 +26,10 @@
*/ */
package org.alfresco.transform.pdfrenderer.transformers; package org.alfresco.transform.pdfrenderer.transformers;
import org.alfresco.transform.base.CustomTransformer; import org.alfresco.transform.base.TransformManager;
import org.alfresco.transform.base.executors.AbstractCommandExecutor; import org.alfresco.transform.base.executors.AbstractCommandExecutor;
import org.alfresco.transform.base.executors.RuntimeExec; import org.alfresco.transform.base.executors.RuntimeExec;
import org.alfresco.transform.base.util.CustomTransformerFileAdaptor;
import org.alfresco.transform.common.TransformException; import org.alfresco.transform.common.TransformException;
import org.alfresco.transform.pdfrenderer.PdfRendererOptionsBuilder; import org.alfresco.transform.pdfrenderer.PdfRendererOptionsBuilder;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
@@ -54,7 +55,7 @@ import static org.alfresco.transform.common.RequestParamMap.WIDTH_REQUEST_PARAM;
* transformation logic as a separate Shell process. * transformation logic as a separate Shell process.
*/ */
@Component @Component
public class PdfRendererTransformer extends AbstractCommandExecutor implements CustomTransformer public class PdfRendererTransformer extends AbstractCommandExecutor implements CustomTransformerFileAdaptor
{ {
@Value("${transform.core.pdfrenderer.exe}") @Value("${transform.core.pdfrenderer.exe}")
private String exe; private String exe;
@@ -103,14 +104,7 @@ public class PdfRendererTransformer extends AbstractCommandExecutor implements C
} }
@Override @Override
public void transform(String sourceMimetype, String sourceEncoding, InputStream inputStream, public void transform(String sourceMimetype, String targetMimetype, Map<String, String> transformOptions,
String targetMimetype, String targetEncoding, OutputStream outputStream,
Map<String, String> transformOptions) throws Exception
{
throw new TransformException(500, "TODO PdfRenderer transform");
}
public void transform(String transformName, String sourceMimetype, String targetMimetype,
Map<String, String> transformOptions,
File sourceFile, File targetFile) throws TransformException File sourceFile, File targetFile) throws TransformException
{ {
final String options = PdfRendererOptionsBuilder final String options = PdfRendererOptionsBuilder

View File

@@ -26,9 +26,8 @@
*/ */
package org.alfresco.transform.tika.metadataExtractors; package org.alfresco.transform.tika.metadataExtractors;
import org.alfresco.transform.base.CustomTransformer; import org.alfresco.transform.base.TransformManager;
import org.alfresco.transform.base.metadataExtractors.AbstractMetadataExtractor; import org.alfresco.transform.base.metadataExtractors.AbstractMetadataExtractor;
import org.alfresco.transform.common.TransformException;
import org.apache.tika.embedder.Embedder; import org.apache.tika.embedder.Embedder;
import org.apache.tika.extractor.DocumentSelector; import org.apache.tika.extractor.DocumentSelector;
import org.apache.tika.metadata.DublinCore; import org.apache.tika.metadata.DublinCore;
@@ -54,7 +53,6 @@ import org.xml.sax.Locator;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.Serializable; import java.io.Serializable;
@@ -84,7 +82,7 @@ import java.util.stream.Stream;
* @author Nick Burch * @author Nick Burch
* @author adavis * @author adavis
*/ */
public abstract class AbstractTikaMetadataExtractor extends AbstractMetadataExtractor implements CustomTransformer public abstract class AbstractTikaMetadataExtractor extends AbstractMetadataExtractor
{ {
protected static final String KEY_AUTHOR = "author"; protected static final String KEY_AUTHOR = "author";
protected static final String KEY_TITLE = "title"; protected static final String KEY_TITLE = "title";
@@ -310,22 +308,15 @@ public abstract class AbstractTikaMetadataExtractor extends AbstractMetadataExtr
return rawProperties; return rawProperties;
} }
public void embedMetadata(String sourceMimetype, Map<String, String> transformOptions,
String sourceEncoding, InputStream inputStream,
String targetEncoding, OutputStream outputStream) throws Exception
{
// TODO
throw new TransformException(500, "TODO embedMetadata");
}
/** /**
* @deprecated The content repository's TikaPoweredMetadataExtracter provides no non test implementations. * @deprecated The content repository's TikaPoweredMetadataExtracter provides no non test implementations.
* This code exists in case there are custom implementations, that need to be converted to T-Engines. * This code exists in case there are custom implementations, that need to be converted to T-Engines.
* It is simply a copy and paste from the content repository and has received limited testing. * It is simply a copy and paste from the content repository and has received limited testing.
*/ */
@Override @Override
public void embedMetadata(String sourceMimetype, String targetMimetype, Map<String, String> transformOptions, public void embedMetadata(String sourceMimetype, InputStream inputStream,
File sourceFile, File targetFile) throws Exception String targetMimetype, OutputStream outputStream,
Map<String, String> transformOptions, TransformManager transformManager) throws Exception
{ {
Embedder embedder = getEmbedder(); Embedder embedder = getEmbedder();
if (embedder == null) if (embedder == null)
@@ -334,13 +325,8 @@ public abstract class AbstractTikaMetadataExtractor extends AbstractMetadataExtr
} }
Metadata metadataToEmbed = getTikaMetadata(transformOptions); Metadata metadataToEmbed = getTikaMetadata(transformOptions);
try (InputStream inputStream = new FileInputStream(sourceFile);
OutputStream outputStream = new FileOutputStream(targetFile))
{
embedder.embed(metadataToEmbed, inputStream, outputStream, null); embedder.embed(metadataToEmbed, inputStream, outputStream, null);
} }
}
private Metadata getTikaMetadata(Map<String, String> transformOptions) private Metadata getTikaMetadata(Map<String, String> transformOptions)
{ {

View File

@@ -26,10 +26,9 @@
*/ */
package org.alfresco.transform.tika.transformers; package org.alfresco.transform.tika.transformers;
import org.alfresco.transform.base.CustomTransformer;
import org.alfresco.transform.base.logging.LogEntry; import org.alfresco.transform.base.logging.LogEntry;
import org.alfresco.transform.base.util.CustomTransformerFileAdaptor;
import org.alfresco.transform.common.RequestParamMap; import org.alfresco.transform.common.RequestParamMap;
import org.alfresco.transform.common.TransformException;
import org.apache.tika.extractor.DocumentSelector; import org.apache.tika.extractor.DocumentSelector;
import org.apache.tika.parser.Parser; import org.apache.tika.parser.Parser;
import org.slf4j.Logger; import org.slf4j.Logger;
@@ -38,21 +37,18 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import java.io.File; import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Map; import java.util.Map;
import java.util.StringJoiner; import java.util.StringJoiner;
import static java.lang.Boolean.parseBoolean; import static java.lang.Boolean.parseBoolean;
public abstract class GenericTikaTransformer implements CustomTransformer public abstract class GenericTikaTransformer implements CustomTransformerFileAdaptor
{ {
private static final Logger logger = LoggerFactory.getLogger(GenericTikaTransformer.class); private static final Logger logger = LoggerFactory.getLogger(GenericTikaTransformer.class);
@Value("${transform.core.tika.pdfBox.notExtractBookmarksTextDefault:false}") @Value("${transform.core.tika.pdfBox.notExtractBookmarksTextDefault:false}")
boolean notExtractBookmarksTextDefault; boolean notExtractBookmarksTextDefault;
@Autowired @Autowired
protected Tika tika; protected Tika tika;
@@ -71,15 +67,7 @@ public abstract class GenericTikaTransformer implements CustomTransformer
} }
@Override @Override
public void transform(String sourceMimetype, String sourceEncoding, InputStream inputStream, public void transform(String sourceMimetype, String targetMimetype,
String targetMimetype, String targetEncoding, OutputStream outputStream,
Map<String, String> transformOptions) throws Exception
{
// TODO
throw new TransformException(500, "TODO GenericTikaTransformer transform with InputStreams");
}
public void transform(String transformName, String sourceMimetype, String targetMimetype,
Map<String, String> transformOptions, File sourceFile, File targetFile) Map<String, String> transformOptions, File sourceFile, File targetFile)
throws Exception throws Exception
{ {
@@ -92,7 +80,8 @@ public abstract class GenericTikaTransformer implements CustomTransformer
{ {
logger.trace("notExtractBookmarksText default value has been overridden to {}", notExtractBookmarksTextDefault); logger.trace("notExtractBookmarksText default value has been overridden to {}", notExtractBookmarksTextDefault);
} }
call(sourceFile, targetFile, transformName, String transformerName = getTransformerName();
call(sourceFile, targetFile, transformerName,
includeContents ? Tika.INCLUDE_CONTENTS : null, includeContents ? Tika.INCLUDE_CONTENTS : null,
notExtractBookmarksText ? Tika.NOT_EXTRACT_BOOKMARKS_TEXT : null, notExtractBookmarksText ? Tika.NOT_EXTRACT_BOOKMARKS_TEXT : null,
Tika.TARGET_MIMETYPE + targetMimetype, Tika.TARGET_ENCODING + targetEncoding); Tika.TARGET_MIMETYPE + targetMimetype, Tika.TARGET_ENCODING + targetEncoding);

View File

@@ -49,7 +49,7 @@ import org.mockito.junit.jupiter.MockitoExtension;
@ExtendWith(MockitoExtension.class) @ExtendWith(MockitoExtension.class)
public class GenericTikaTransformerTest public class GenericTikaTransformerTest
{ {
private class TikaTestTransformer extends GenericTikaTransformer private static class TikaTestTransformer extends GenericTikaTransformer
{ {
@Override @Override
protected Parser getParser() protected Parser getParser()
@@ -61,7 +61,7 @@ public class GenericTikaTransformerTest
{ {
this.notExtractBookmarksTextDefault = notExtractBookmarksTextDefault; this.notExtractBookmarksTextDefault = notExtractBookmarksTextDefault;
} }
}; }
@Test @Test
public void testNotExtractBookmarkTextDefault() throws Exception public void testNotExtractBookmarkTextDefault() throws Exception
@@ -83,9 +83,9 @@ public class GenericTikaTransformerTest
Map<String, String> transformOptions = new HashMap<>(); Map<String, String> transformOptions = new HashMap<>();
// use empty transformOptions to test defaults // use empty transformOptions to test defaults
executorSpyDefaultTrue.transform(transformName, sourceMimetype, targetMimetype, transformOptions, executorSpyDefaultTrue.transform(sourceMimetype, targetMimetype, transformOptions,
mockSourceFile, mockTargetFile); mockSourceFile, mockTargetFile);
executorSpyDefaultFalse.transform(transformName, sourceMimetype, targetMimetype, transformOptions, executorSpyDefaultFalse.transform(sourceMimetype, targetMimetype, transformOptions,
mockSourceFile, mockTargetFile); mockSourceFile, mockTargetFile);
// when default set to true, with no options passed we should get a call method with NOT_EXTRACT_BOOKMARKS_TEXT // when default set to true, with no options passed we should get a call method with NOT_EXTRACT_BOOKMARKS_TEXT
@@ -99,9 +99,9 @@ public class GenericTikaTransformerTest
// use transforms with notExtractBookmarksText set to true // use transforms with notExtractBookmarksText set to true
clearInvocations(executorSpyDefaultTrue, executorSpyDefaultFalse); clearInvocations(executorSpyDefaultTrue, executorSpyDefaultFalse);
transformOptions.put("notExtractBookmarksText", "true"); transformOptions.put("notExtractBookmarksText", "true");
executorSpyDefaultTrue.transform(transformName, sourceMimetype, targetMimetype, transformOptions, executorSpyDefaultTrue.transform(sourceMimetype, targetMimetype, transformOptions,
mockSourceFile, mockTargetFile); mockSourceFile, mockTargetFile);
executorSpyDefaultFalse.transform(transformName, sourceMimetype, targetMimetype, transformOptions, executorSpyDefaultFalse.transform(sourceMimetype, targetMimetype, transformOptions,
mockSourceFile, mockTargetFile); mockSourceFile, mockTargetFile);
// both call methods should have NOT_EXTRACT_BOOKMARKS_TEXT // both call methods should have NOT_EXTRACT_BOOKMARKS_TEXT
@@ -114,8 +114,8 @@ public class GenericTikaTransformerTest
// use transforms with notExtractBookmarksText set to false // use transforms with notExtractBookmarksText set to false
clearInvocations(executorSpyDefaultTrue, executorSpyDefaultFalse); clearInvocations(executorSpyDefaultTrue, executorSpyDefaultFalse);
transformOptions.replace("notExtractBookmarksText", "true", "false"); transformOptions.replace("notExtractBookmarksText", "true", "false");
executorSpyDefaultTrue.transform(transformName, sourceMimetype, targetMimetype, transformOptions, mockSourceFile, mockTargetFile); executorSpyDefaultTrue.transform(sourceMimetype, targetMimetype, transformOptions, mockSourceFile, mockTargetFile);
executorSpyDefaultFalse.transform(transformName, sourceMimetype, targetMimetype, transformOptions, mockSourceFile, mockTargetFile); executorSpyDefaultFalse.transform(sourceMimetype, targetMimetype, transformOptions, mockSourceFile, mockTargetFile);
// both call methods should have NOT_EXTRACT_BOOKMARKS_TEXT // both call methods should have NOT_EXTRACT_BOOKMARKS_TEXT
verify(executorSpyDefaultTrue, times(1)).call(mockSourceFile, mockTargetFile, transformName, null, null, verify(executorSpyDefaultTrue, times(1)).call(mockSourceFile, mockTargetFile, transformName, null, null,
@@ -124,11 +124,11 @@ public class GenericTikaTransformerTest
verify(executorSpyDefaultFalse, times(1)).call(mockSourceFile, mockTargetFile, transformName, null, null, verify(executorSpyDefaultFalse, times(1)).call(mockSourceFile, mockTargetFile, transformName, null, null,
TARGET_MIMETYPE + targetMimetype, TARGET_ENCODING + defaultEncoding); TARGET_MIMETYPE + targetMimetype, TARGET_ENCODING + defaultEncoding);
// use full set of pdfbox transformOptions just to be safe // useful set of pdfbox transformOptions just to be safe
clearInvocations(executorSpyDefaultTrue, executorSpyDefaultFalse); clearInvocations(executorSpyDefaultTrue, executorSpyDefaultFalse);
transformOptions.put("targetEncoding", "anyEncoding"); transformOptions.put("targetEncoding", "anyEncoding");
executorSpyDefaultTrue.transform(transformName, sourceMimetype, targetMimetype, transformOptions, mockSourceFile, mockTargetFile); executorSpyDefaultTrue.transform(sourceMimetype, targetMimetype, transformOptions, mockSourceFile, mockTargetFile);
executorSpyDefaultFalse.transform(transformName, sourceMimetype, targetMimetype, transformOptions, mockSourceFile, mockTargetFile); executorSpyDefaultFalse.transform(sourceMimetype, targetMimetype, transformOptions, mockSourceFile, mockTargetFile);
// both call methods should have NOT_EXTRACT_BOOKMARKS_TEXT but the encoding will change // both call methods should have NOT_EXTRACT_BOOKMARKS_TEXT but the encoding will change
verify(executorSpyDefaultTrue, times(1)).call(mockSourceFile, mockTargetFile, transformName, null, null, verify(executorSpyDefaultTrue, times(1)).call(mockSourceFile, mockTargetFile, transformName, null, null,

View File

@@ -79,10 +79,15 @@ public class TransformerDebug
} }
public void pushTransform(String reference, String sourceMimetype, String targetMimetype, File sourceFile, String transformerName) public void pushTransform(String reference, String sourceMimetype, String targetMimetype, File sourceFile, String transformerName)
{
final long sourceSizeInBytes = sourceFile.length();
pushTransform(reference, sourceMimetype, targetMimetype, sourceSizeInBytes, transformerName);
}
public void pushTransform(String reference, String sourceMimetype, String targetMimetype, long sourceSizeInBytes, String transformerName)
{ {
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
{ {
final long sourceSizeInBytes = sourceFile.length();
String message = getPaddedReference(reference) + String message = getPaddedReference(reference) +
getMimetypeExt(sourceMimetype) + getMimetypeExt(sourceMimetype) +
getTargetMimetypeExt(targetMimetype, sourceMimetype) + ' ' + getTargetMimetypeExt(targetMimetype, sourceMimetype) + ' ' +

View File

@@ -74,19 +74,19 @@ public class TransformCache
return transforms; return transforms;
} }
public void cache(final String transformerName, final String sourceMimetype, public void cache(final String renditionName, final String sourceMimetype,
final List<SupportedTransform> transformListBySize) final List<SupportedTransform> transformListBySize)
{ {
cachedSupportedTransformList cachedSupportedTransformList
.get(transformerName) .get(renditionName)
.put(sourceMimetype, transformListBySize); .put(sourceMimetype, transformListBySize);
} }
public List<SupportedTransform> retrieveCached(final String transformerName, public List<SupportedTransform> retrieveCached(final String renditionName,
final String sourceMimetype) final String sourceMimetype)
{ {
return cachedSupportedTransformList return cachedSupportedTransformList
.computeIfAbsent(transformerName, k -> new ConcurrentHashMap<>()) .computeIfAbsent(renditionName, k -> new ConcurrentHashMap<>())
.get(sourceMimetype); .get(sourceMimetype);
} }

View File

@@ -75,20 +75,20 @@ class TransformRegistryHelper
// been discarded. // been discarded.
static List<SupportedTransform> retrieveTransformListBySize(final TransformCache data, static List<SupportedTransform> retrieveTransformListBySize(final TransformCache data,
final String sourceMimetype, final String targetMimetype, final String sourceMimetype, final String targetMimetype,
Map<String, String> actualOptions, String transformerName) Map<String, String> actualOptions, String renditionName)
{ {
if (actualOptions == null) if (actualOptions == null)
{ {
actualOptions = emptyMap(); actualOptions = emptyMap();
} }
if (transformerName != null && transformerName.trim().isEmpty()) if (renditionName != null && renditionName.trim().isEmpty())
{ {
transformerName = null; renditionName = null;
} }
final List<SupportedTransform> cachedTransformList = final List<SupportedTransform> cachedTransformList =
transformerName == null ? null : renditionName == null ? null :
data.retrieveCached(transformerName, sourceMimetype); data.retrieveCached(renditionName, sourceMimetype);
if (cachedTransformList != null) if (cachedTransformList != null)
{ {
return cachedTransformList; return cachedTransformList;
@@ -99,9 +99,9 @@ class TransformRegistryHelper
targetMimetype, targetMimetype,
filterTimeout(actualOptions)); filterTimeout(actualOptions));
if (transformerName != null) if (renditionName != null)
{ {
data.cache(transformerName, sourceMimetype, builtTransformList); data.cache(renditionName, sourceMimetype, builtTransformList);
} }
return builtTransformList; return builtTransformList;
@@ -111,13 +111,12 @@ class TransformRegistryHelper
final TransformCache data, final String sourceMimetype, final String targetMimetype, final TransformCache data, final String sourceMimetype, final String targetMimetype,
final Map<String, String> actualOptions) final Map<String, String> actualOptions)
{ {
if (sourceMimetype == null)
if(sourceMimetype == null)
{ {
throw new TransformException(400, "Null value provided for sourceMimetype, please provide a value"); throw new TransformException(400, "Null value provided for sourceMimetype, please provide a value");
} }
if(targetMimetype == null) if (targetMimetype == null)
{ {
throw new TransformException(400, "Null value provided for tragetMimetype, please provide a value"); throw new TransformException(400, "Null value provided for tragetMimetype, please provide a value");
} }