mirror of
https://github.com/Alfresco/alfresco-transform-core.git
synced 2025-08-07 17:48:35 +00:00
ATS-175 : T-Engine code cleanup
This commit is contained in:
@@ -94,7 +94,7 @@ public class AlfrescoPdfRendererController extends AbstractTransformerController
|
||||
String options = args.toString();
|
||||
LogEntry.setOptions(options);
|
||||
|
||||
Map<String, String> properties = new HashMap<String, String>(5);
|
||||
Map<String, String> properties = new HashMap<>();
|
||||
properties.put("options", options);
|
||||
properties.put("source", sourceFile.getAbsolutePath());
|
||||
properties.put("target", targetFile.getAbsolutePath());
|
||||
|
@@ -25,55 +25,39 @@
|
||||
*/
|
||||
package org.alfresco.transformer;
|
||||
|
||||
import static org.alfresco.transformer.fs.FileManager.buildFile;
|
||||
import static org.alfresco.transformer.fs.FileManager.createTargetFileName;
|
||||
import static org.alfresco.transformer.fs.FileManager.getFilenameFromContentDisposition;
|
||||
import static org.alfresco.transformer.fs.FileManager.save;
|
||||
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.StringJoiner;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.alfresco.transform.client.model.TransformReply;
|
||||
import org.alfresco.transform.client.model.TransformRequest;
|
||||
import org.alfresco.transform.client.model.TransformRequestValidator;
|
||||
import org.alfresco.transformer.clients.AlfrescoSharedFileStoreClient;
|
||||
import org.alfresco.transformer.exceptions.TransformException;
|
||||
import org.alfresco.transformer.logging.LogEntry;
|
||||
import org.alfresco.transformer.model.FileRefResponse;
|
||||
import org.alfresco.util.TempFileProvider;
|
||||
import org.alfresco.util.exec.RuntimeExec;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.springframework.beans.TypeMismatchException;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.UrlResource;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.validation.DirectFieldBindingResult;
|
||||
import org.springframework.validation.Errors;
|
||||
import org.springframework.web.bind.MissingServletRequestParameterException;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.client.HttpClientErrorException;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import org.springframework.web.util.UriUtils;
|
||||
|
||||
/**
|
||||
* <p>Abstract Controller, provides structure and helper methods to sub-class transformer controllers.</p>
|
||||
@@ -103,11 +87,9 @@ import org.springframework.web.util.UriUtils;
|
||||
* <p>Provides methods to help super classes perform /transform requests. Also responses to /version, /ready and /live
|
||||
* requests.</p>
|
||||
*/
|
||||
public abstract class AbstractTransformerController
|
||||
public abstract class AbstractTransformerController implements TransformController
|
||||
{
|
||||
public static final String SOURCE_FILE = "sourceFile";
|
||||
public static final String TARGET_FILE = "targetFile";
|
||||
public static final String FILENAME = "filename=";
|
||||
private static final Log logger = LogFactory.getLog(AbstractTransformerController.class);
|
||||
|
||||
@Autowired
|
||||
private AlfrescoSharedFileStoreClient alfrescoSharedFileStoreClient;
|
||||
@@ -115,123 +97,90 @@ public abstract class AbstractTransformerController
|
||||
@Autowired
|
||||
private TransformRequestValidator transformRequestValidator;
|
||||
|
||||
protected static Log logger;
|
||||
|
||||
protected RuntimeExec transformCommand;
|
||||
private RuntimeExec checkCommand;
|
||||
|
||||
private ProbeTestTransform probeTestTransform = null;
|
||||
|
||||
public void setTransformCommand(RuntimeExec runtimeExec)
|
||||
{
|
||||
transformCommand = runtimeExec;
|
||||
}
|
||||
|
||||
public void setCheckCommand(RuntimeExec runtimeExec)
|
||||
{
|
||||
checkCommand = runtimeExec;
|
||||
}
|
||||
|
||||
protected void logEnterpriseLicenseMessage()
|
||||
{
|
||||
logger.info("This image is only intended to be used with the Alfresco Enterprise Content Repository which is covered by ");
|
||||
logger.info("https://www.alfresco.com/legal/agreements and https://www.alfresco.com/terms-use");
|
||||
logger.info("");
|
||||
logger.info("License rights for this program may be obtained from Alfresco Software, Ltd. pursuant to a written agreement");
|
||||
logger.info("and any use of this program without such an agreement is prohibited.");
|
||||
logger.info("");
|
||||
}
|
||||
|
||||
protected abstract String getTransformerName();
|
||||
|
||||
/**
|
||||
* '/transform' endpoint which consumes and produces 'application/json'
|
||||
*
|
||||
* This is the way to tell Spring to redirect the request to this endpoint
|
||||
* instead of the older one, which produces 'html'
|
||||
*
|
||||
* @param transformRequest The transformation request
|
||||
* @param request The transformation request
|
||||
* @param timeout Transformation timeout
|
||||
* @return A transformation reply
|
||||
*/
|
||||
@PostMapping(value = "/transform", produces = APPLICATION_JSON_VALUE)
|
||||
@ResponseBody
|
||||
public ResponseEntity<TransformReply> transform(@RequestBody TransformRequest transformRequest,
|
||||
public ResponseEntity<TransformReply> transform(@RequestBody TransformRequest request,
|
||||
@RequestParam(value = "timeout", required = false) Long timeout)
|
||||
{
|
||||
TransformReply transformReply = new TransformReply();
|
||||
transformReply.setRequestId(transformRequest.getRequestId());
|
||||
transformReply.setSourceReference(transformRequest.getSourceReference());
|
||||
transformReply.setSchema(transformRequest.getSchema());
|
||||
transformReply.setClientData(transformRequest.getClientData());
|
||||
final TransformReply reply = new TransformReply();
|
||||
reply.setRequestId(request.getRequestId());
|
||||
reply.setSourceReference(request.getSourceReference());
|
||||
reply.setSchema(request.getSchema());
|
||||
reply.setClientData(request.getClientData());
|
||||
|
||||
Errors errors = validateTransformRequest(transformRequest);
|
||||
final Errors errors = validateTransformRequest(request);
|
||||
if (!errors.getAllErrors().isEmpty())
|
||||
{
|
||||
transformReply.setStatus(HttpStatus.BAD_REQUEST.value());
|
||||
transformReply.setErrorDetails(errors.getAllErrors().stream().map(Object::toString)
|
||||
reply.setStatus(HttpStatus.BAD_REQUEST.value());
|
||||
reply.setErrorDetails(errors.getAllErrors().stream().map(Object::toString)
|
||||
.collect(Collectors.joining(", ")));
|
||||
|
||||
return new ResponseEntity<>(transformReply,
|
||||
HttpStatus.valueOf(transformReply.getStatus()));
|
||||
return new ResponseEntity<>(reply,
|
||||
HttpStatus.valueOf(reply.getStatus()));
|
||||
}
|
||||
|
||||
// Load the source file
|
||||
File sourceFile;
|
||||
try
|
||||
{
|
||||
sourceFile = loadSourceFile(transformRequest.getSourceReference());
|
||||
sourceFile = loadSourceFile(request.getSourceReference());
|
||||
}
|
||||
catch (TransformException te)
|
||||
{
|
||||
transformReply.setStatus(te.getStatusCode());
|
||||
transformReply
|
||||
.setErrorDetails("Failed at reading the source file. " + te.getMessage());
|
||||
reply.setStatus(te.getStatusCode());
|
||||
reply .setErrorDetails("Failed at reading the source file. " + te.getMessage());
|
||||
|
||||
return new ResponseEntity<>(transformReply, HttpStatus.valueOf(transformReply.getStatus()));
|
||||
return new ResponseEntity<>(reply, HttpStatus.valueOf(reply.getStatus()));
|
||||
}
|
||||
catch (HttpClientErrorException hcee)
|
||||
{
|
||||
transformReply.setStatus(hcee.getStatusCode().value());
|
||||
transformReply
|
||||
.setErrorDetails("Failed at reading the source file. " + hcee.getMessage());
|
||||
reply.setStatus(hcee.getStatusCode().value());
|
||||
reply .setErrorDetails("Failed at reading the source file. " + hcee.getMessage());
|
||||
|
||||
return new ResponseEntity<>(transformReply, HttpStatus.valueOf(transformReply.getStatus()));
|
||||
return new ResponseEntity<>(reply, HttpStatus.valueOf(reply.getStatus()));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
transformReply.setStatus(500);
|
||||
transformReply.setErrorDetails("Failed at reading the source file. " + e.getMessage());
|
||||
reply.setStatus(500);
|
||||
reply.setErrorDetails("Failed at reading the source file. " + e.getMessage());
|
||||
|
||||
return new ResponseEntity<>(transformReply, HttpStatus.valueOf(transformReply.getStatus()));
|
||||
return new ResponseEntity<>(reply, HttpStatus.valueOf(reply.getStatus()));
|
||||
}
|
||||
|
||||
// Create local temp target file in order to run the transformation
|
||||
String targetFilename = createTargetFileName(sourceFile.getName(),
|
||||
transformRequest.getTargetExtension());
|
||||
request.getTargetExtension());
|
||||
File targetFile = buildFile(targetFilename);
|
||||
|
||||
// Run the transformation
|
||||
try
|
||||
{
|
||||
processTransform(sourceFile, targetFile,
|
||||
transformRequest.getTransformRequestOptions(), timeout);
|
||||
request.getTransformRequestOptions(), timeout);
|
||||
}
|
||||
catch (TransformException te)
|
||||
{
|
||||
transformReply.setStatus(te.getStatusCode());
|
||||
transformReply
|
||||
.setErrorDetails("Failed at processing transformation. " + te.getMessage());
|
||||
reply.setStatus(te.getStatusCode());
|
||||
reply.setErrorDetails("Failed at processing transformation. " + te.getMessage());
|
||||
|
||||
return new ResponseEntity<>(transformReply, HttpStatus.valueOf(transformReply.getStatus()));
|
||||
return new ResponseEntity<>(reply, HttpStatus.valueOf(reply.getStatus()));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
transformReply.setStatus(500);
|
||||
transformReply
|
||||
.setErrorDetails("Failed at processing transformation. " + e.getMessage());
|
||||
reply.setStatus(500);
|
||||
reply.setErrorDetails("Failed at processing transformation. " + e.getMessage());
|
||||
|
||||
return new ResponseEntity<>(transformReply, HttpStatus.valueOf(transformReply.getStatus()));
|
||||
return new ResponseEntity<>(reply, HttpStatus.valueOf(reply.getStatus()));
|
||||
}
|
||||
|
||||
// Write the target file
|
||||
@@ -242,211 +191,50 @@ public abstract class AbstractTransformerController
|
||||
}
|
||||
catch (TransformException te)
|
||||
{
|
||||
transformReply.setStatus(te.getStatusCode());
|
||||
transformReply
|
||||
.setErrorDetails("Failed at writing the transformed file. " + te.getMessage());
|
||||
reply.setStatus(te.getStatusCode());
|
||||
reply.setErrorDetails("Failed at writing the transformed file. " + te.getMessage());
|
||||
|
||||
return new ResponseEntity<>(transformReply, HttpStatus.valueOf(transformReply.getStatus()));
|
||||
return new ResponseEntity<>(reply, HttpStatus.valueOf(reply.getStatus()));
|
||||
}
|
||||
catch (HttpClientErrorException hcee)
|
||||
{
|
||||
transformReply.setStatus(hcee.getStatusCode().value());
|
||||
transformReply
|
||||
.setErrorDetails("Failed at writing the transformed file. " + hcee.getMessage());
|
||||
reply.setStatus(hcee.getStatusCode().value());
|
||||
reply.setErrorDetails("Failed at writing the transformed file. " + hcee.getMessage());
|
||||
|
||||
return new ResponseEntity<>(transformReply, HttpStatus.valueOf(transformReply.getStatus()));
|
||||
return new ResponseEntity<>(reply, HttpStatus.valueOf(reply.getStatus()));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
transformReply.setStatus(500);
|
||||
transformReply
|
||||
.setErrorDetails("Failed at writing the transformed file. " + e.getMessage());
|
||||
reply.setStatus(500);
|
||||
reply.setErrorDetails("Failed at writing the transformed file. " + e.getMessage());
|
||||
|
||||
return new ResponseEntity<>(transformReply, HttpStatus.valueOf(transformReply.getStatus()));
|
||||
return new ResponseEntity<>(reply, HttpStatus.valueOf(reply.getStatus()));
|
||||
}
|
||||
|
||||
transformReply.setTargetReference(targetRef.getEntry().getFileRef());
|
||||
transformReply.setStatus(HttpStatus.CREATED.value());
|
||||
reply.setTargetReference(targetRef.getEntry().getFileRef());
|
||||
reply.setStatus(HttpStatus.CREATED.value());
|
||||
|
||||
return new ResponseEntity<>(transformReply, HttpStatus.valueOf(transformReply.getStatus()));
|
||||
return new ResponseEntity<>(reply, HttpStatus.valueOf(reply.getStatus()));
|
||||
}
|
||||
|
||||
private Errors validateTransformRequest(TransformRequest transformRequest)
|
||||
private Errors validateTransformRequest(final TransformRequest transformRequest)
|
||||
{
|
||||
DirectFieldBindingResult errors = new DirectFieldBindingResult(transformRequest, "request");
|
||||
transformRequestValidator.validate(transformRequest, errors);
|
||||
return errors;
|
||||
}
|
||||
|
||||
protected abstract void processTransform(File sourceFile, File targetFile,
|
||||
Map<String, String> transformOptions, Long timeout);
|
||||
|
||||
@RequestMapping("/version")
|
||||
@ResponseBody
|
||||
protected String version()
|
||||
{
|
||||
String version = "Version not checked";
|
||||
if (checkCommand != null)
|
||||
{
|
||||
RuntimeExec.ExecutionResult result = checkCommand.execute();
|
||||
if (result.getExitValue() != 0 && result.getStdErr() != null && result.getStdErr().length() > 0)
|
||||
{
|
||||
throw new TransformException(500, "Transformer version check exit code was not 0: \n" + result);
|
||||
}
|
||||
|
||||
version = result.getStdOut().trim();
|
||||
if (version.isEmpty())
|
||||
{
|
||||
throw new TransformException(500, "Transformer version check failed to create any output");
|
||||
}
|
||||
}
|
||||
|
||||
return version;
|
||||
}
|
||||
|
||||
@GetMapping("/ready")
|
||||
@ResponseBody
|
||||
public String ready(HttpServletRequest request)
|
||||
{
|
||||
return probe(request, false);
|
||||
}
|
||||
|
||||
@GetMapping("/live")
|
||||
@ResponseBody
|
||||
public String live(HttpServletRequest request)
|
||||
{
|
||||
return probe(request, true);
|
||||
}
|
||||
|
||||
private String probe(HttpServletRequest request, boolean isLiveProbe)
|
||||
{
|
||||
return getProbeTestTransformInternal().doTransformOrNothing(request, isLiveProbe);
|
||||
}
|
||||
|
||||
private ProbeTestTransform getProbeTestTransformInternal()
|
||||
{
|
||||
if (probeTestTransform == null)
|
||||
{
|
||||
probeTestTransform = getProbeTestTransform();
|
||||
}
|
||||
return probeTestTransform;
|
||||
}
|
||||
|
||||
abstract ProbeTestTransform getProbeTestTransform();
|
||||
|
||||
@GetMapping("/")
|
||||
public String transformForm(Model model)
|
||||
{
|
||||
return "transformForm"; // the name of the template
|
||||
}
|
||||
|
||||
@GetMapping("/log")
|
||||
public String log(Model model)
|
||||
{
|
||||
model.addAttribute("title", getTransformerName() + " Log Entries");
|
||||
Collection<LogEntry> log = LogEntry.getLog();
|
||||
if (!log.isEmpty())
|
||||
{
|
||||
model.addAttribute("log", log);
|
||||
}
|
||||
return "log"; // the name of the template
|
||||
}
|
||||
|
||||
@GetMapping("/error")
|
||||
public String error()
|
||||
{
|
||||
return "error"; // the name of the template
|
||||
}
|
||||
|
||||
@ExceptionHandler(TypeMismatchException.class)
|
||||
public void handleParamsTypeMismatch(HttpServletResponse response, MissingServletRequestParameterException e) throws IOException
|
||||
{
|
||||
String transformerName = getTransformerName();
|
||||
String name = e.getParameterName();
|
||||
String message = "Request parameter " + name + " is of the wrong type";
|
||||
int statusCode = 400;
|
||||
|
||||
if (logger != null && logger.isErrorEnabled())
|
||||
{
|
||||
logger.error(message);
|
||||
}
|
||||
|
||||
LogEntry.setStatusCodeAndMessage(statusCode, message);
|
||||
|
||||
response.sendError(statusCode, transformerName+" - "+message);
|
||||
}
|
||||
|
||||
@ExceptionHandler(MissingServletRequestParameterException.class)
|
||||
public void handleMissingParams(HttpServletResponse response, MissingServletRequestParameterException e) throws IOException
|
||||
{
|
||||
String transformerName = getTransformerName();
|
||||
String name = e.getParameterName();
|
||||
String message = "Request parameter " + name + " is missing";
|
||||
int statusCode = 400;
|
||||
|
||||
if (logger != null && logger.isErrorEnabled())
|
||||
{
|
||||
logger.error(message);
|
||||
}
|
||||
|
||||
LogEntry.setStatusCodeAndMessage(statusCode, message);
|
||||
|
||||
response.sendError(statusCode, transformerName+" - "+message);
|
||||
}
|
||||
|
||||
@ExceptionHandler(TransformException.class)
|
||||
public void transformExceptionWithMessage(HttpServletResponse response, TransformException e) throws IOException
|
||||
{
|
||||
String transformerName = getTransformerName();
|
||||
String message = e.getMessage();
|
||||
int statusCode = e.getStatusCode();
|
||||
|
||||
if (logger != null && logger.isErrorEnabled())
|
||||
{
|
||||
logger.error(message);
|
||||
}
|
||||
|
||||
long time = LogEntry.setStatusCodeAndMessage(statusCode, message);
|
||||
getProbeTestTransformInternal().recordTransformTime(time);
|
||||
|
||||
// Forced to include the transformer name in the message (see commented out version of this method)
|
||||
response.sendError(statusCode, transformerName+" - "+message);
|
||||
}
|
||||
|
||||
// Results in HTML rather than json but there is an error in the log about "template might not exist or might
|
||||
// not be accessible by any of the configured Template Resolvers" for the transformer.html (which is correct
|
||||
// because that failed). Looks like Spring only supports returning json or XML when returning an Object or even
|
||||
// a ResponseEntity without this logged exception, which is a shame as it would have been nicer to have just
|
||||
// added the transformerName to the Object.
|
||||
// @ExceptionHandler(TransformException.class)
|
||||
// public final Map<String, Object> transformExceptionWithMessage(HttpServletResponse response, TransformException e, WebRequest request)
|
||||
// {
|
||||
// String transformerName = getTransformerName();
|
||||
// String message = e.getMessage();
|
||||
// int statusCode = e.getStatusCode();
|
||||
//
|
||||
// LogEntry.setStatusCodeAndMessage(statusCode, message);
|
||||
//
|
||||
// Map<String, Object> errorAttributes = new HashMap<>();
|
||||
// errorAttributes.put("title", transformerName);
|
||||
// errorAttributes.put("message", message);
|
||||
// errorAttributes.put("status", Integer.toString(statusCode));
|
||||
// errorAttributes.put("error", HttpStatus.valueOf(statusCode).getReasonPhrase());
|
||||
// return errorAttributes;
|
||||
// }
|
||||
|
||||
/**
|
||||
* Loads the file with the specified sourceReference from Alfresco Shared File Store
|
||||
*
|
||||
* @param sourceReference reference to the file in Alfresco Shared File Store
|
||||
* @return the file containing the source content for the transformation
|
||||
*/
|
||||
protected File loadSourceFile(String sourceReference)
|
||||
private File loadSourceFile(final String sourceReference)
|
||||
{
|
||||
|
||||
ResponseEntity<Resource> responseEntity = alfrescoSharedFileStoreClient
|
||||
.retrieveFile(sourceReference);
|
||||
getProbeTestTransformInternal().incrementTransformerCount();
|
||||
getProbeTestTransform().incrementTransformerCount();
|
||||
|
||||
HttpHeaders headers = responseEntity.getHeaders();
|
||||
String filename = getFilenameFromContentDisposition(headers);
|
||||
@@ -468,299 +256,4 @@ public abstract class AbstractTransformerController
|
||||
LogEntry.setSource(filename, size);
|
||||
return file;
|
||||
}
|
||||
|
||||
|
||||
private String getFilenameFromContentDisposition(HttpHeaders headers)
|
||||
{
|
||||
String filename = "";
|
||||
String contentDisposition = headers.getFirst(HttpHeaders.CONTENT_DISPOSITION);
|
||||
if (contentDisposition != null)
|
||||
{
|
||||
String[] strings = contentDisposition.split("; *");
|
||||
for (String string: strings)
|
||||
{
|
||||
if (string.startsWith(FILENAME))
|
||||
{
|
||||
filename = string.substring(FILENAME.length());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the file name for the target file
|
||||
*
|
||||
* @param fileName Desired file name
|
||||
* @param targetExtension File extension
|
||||
* @return Target file name
|
||||
*/
|
||||
protected String createTargetFileName(String fileName, String targetExtension)
|
||||
{
|
||||
String targetFilename = null;
|
||||
String sourceFilename = fileName;
|
||||
sourceFilename = StringUtils.getFilename(sourceFilename);
|
||||
if (sourceFilename != null && !sourceFilename.isEmpty())
|
||||
{
|
||||
String ext = StringUtils.getFilenameExtension(sourceFilename);
|
||||
targetFilename = (ext != null && !ext.isEmpty()
|
||||
? sourceFilename.substring(0, sourceFilename.length()-ext.length()-1)
|
||||
: sourceFilename)+
|
||||
'.'+targetExtension;
|
||||
}
|
||||
return targetFilename;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a File that holds the source content for a transformation.
|
||||
*
|
||||
* @param request
|
||||
* @param multipartFile from the request
|
||||
* @return a temporary File.
|
||||
* @throws TransformException if there was no source filename.
|
||||
*/
|
||||
protected File createSourceFile(HttpServletRequest request, MultipartFile multipartFile)
|
||||
{
|
||||
getProbeTestTransformInternal().incrementTransformerCount();
|
||||
String filename = multipartFile.getOriginalFilename();
|
||||
long size = multipartFile.getSize();
|
||||
filename = checkFilename( true, filename);
|
||||
File file = TempFileProvider.createTempFile("source_", "_" + filename);
|
||||
request.setAttribute(SOURCE_FILE, file);
|
||||
save(multipartFile, file);
|
||||
LogEntry.setSource(filename, size);
|
||||
return file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a File to be used to store the result of a transformation.
|
||||
*
|
||||
* @param request
|
||||
* @param filename The targetFilename supplied in the request. Only the filename if a path is used as part of the
|
||||
* temporary filename.
|
||||
* @return a temporary File.
|
||||
* @throws TransformException if there was no target filename.
|
||||
*/
|
||||
protected File createTargetFile(HttpServletRequest request, String filename)
|
||||
{
|
||||
File file = buildFile(filename);
|
||||
request.setAttribute(TARGET_FILE, file);
|
||||
return file;
|
||||
}
|
||||
|
||||
private File buildFile(String filename)
|
||||
{
|
||||
filename = checkFilename( false, filename);
|
||||
LogEntry.setTarget(filename);
|
||||
return TempFileProvider.createTempFile("target_", "_" + filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the filename is okay to uses in a temporary file name.
|
||||
*
|
||||
* @param filename or path to be checked.
|
||||
* @return the filename part of the supplied filename if it was a path.
|
||||
* @throws TransformException if there was no target filename.
|
||||
*/
|
||||
private String checkFilename(boolean source, String filename)
|
||||
{
|
||||
filename = StringUtils.getFilename(filename);
|
||||
if (filename == null || filename.isEmpty())
|
||||
{
|
||||
String sourceOrTarget = source ? "source" : "target";
|
||||
int statusCode = source ? 400 : 500;
|
||||
throw new TransformException(statusCode, "The " + sourceOrTarget + " filename was not supplied");
|
||||
}
|
||||
return filename;
|
||||
}
|
||||
|
||||
private void save(MultipartFile multipartFile, File file)
|
||||
{
|
||||
try
|
||||
{
|
||||
Files.copy(multipartFile.getInputStream(), file.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new TransformException(507, "Failed to store the source file", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void save(Resource body, File file)
|
||||
{
|
||||
try
|
||||
{
|
||||
InputStream inputStream = body == null ? null : body.getInputStream();
|
||||
Files.copy(inputStream, file.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new TransformException(507, "Failed to store the source file", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private Resource load(File file)
|
||||
{
|
||||
try
|
||||
{
|
||||
Resource resource = new UrlResource(file.toURI());
|
||||
if (resource.exists() || resource.isReadable())
|
||||
{
|
||||
return resource;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new TransformException(500, "Could not read the target file: " + file.getPath());
|
||||
}
|
||||
}
|
||||
catch (MalformedURLException e)
|
||||
{
|
||||
throw new TransformException(500, "The target filename was malformed: " + file.getPath(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public void callTransform(File sourceFile, File targetFile, String... args) throws TransformException
|
||||
{
|
||||
args = buildArgs(sourceFile, targetFile, args);
|
||||
try
|
||||
{
|
||||
callTransform(args);
|
||||
}
|
||||
catch (IllegalArgumentException e)
|
||||
{
|
||||
throw new TransformException(400, getMessage(e));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new TransformException(500, getMessage(e));
|
||||
}
|
||||
if (!targetFile.exists() || targetFile.length() == 0)
|
||||
{
|
||||
throw new TransformException(500, "Transformer failed to create an output file");
|
||||
}
|
||||
}
|
||||
|
||||
private String getMessage(Exception e)
|
||||
{
|
||||
return e.getMessage() == null ? e.getClass().getSimpleName(): e.getMessage();
|
||||
}
|
||||
|
||||
protected void callTransform(String[] args)
|
||||
{
|
||||
// Overridden when the transform is done in the JVM rather than in an external command.
|
||||
}
|
||||
|
||||
protected String[] buildArgs(File sourceFile, File targetFile, String[] args)
|
||||
{
|
||||
ArrayList<String> methodArgs = new ArrayList<>(args.length+2);
|
||||
StringJoiner sj = new StringJoiner(" ");
|
||||
for (String arg: args)
|
||||
{
|
||||
addArg(methodArgs, sj, arg);
|
||||
}
|
||||
|
||||
addFileArg(methodArgs, sj, sourceFile);
|
||||
addFileArg(methodArgs, sj, targetFile);
|
||||
|
||||
LogEntry.setOptions(sj.toString());
|
||||
|
||||
return methodArgs.toArray(new String[methodArgs.size()]);
|
||||
}
|
||||
|
||||
private void addArg(ArrayList<String> methodArgs, StringJoiner sj, String arg)
|
||||
{
|
||||
if (arg != null)
|
||||
{
|
||||
sj.add(arg);
|
||||
methodArgs.add(arg);
|
||||
}
|
||||
}
|
||||
|
||||
private void addFileArg(ArrayList<String> methodArgs, StringJoiner sj, File arg)
|
||||
{
|
||||
if (arg != null)
|
||||
{
|
||||
String path = arg.getAbsolutePath();
|
||||
int i = path.lastIndexOf('.');
|
||||
String ext = i == -1 ? "???" : path.substring(i+1);
|
||||
sj.add(ext);
|
||||
methodArgs.add(path);
|
||||
}
|
||||
}
|
||||
|
||||
protected void executeTransformCommand(String options, File sourceFile, File targetFile, Long timeout)
|
||||
{
|
||||
LogEntry.setOptions(options);
|
||||
|
||||
Map<String, String> properties = new HashMap<String, String>(5);
|
||||
properties.put("options", options);
|
||||
properties.put("source", sourceFile.getAbsolutePath());
|
||||
properties.put("target", targetFile.getAbsolutePath());
|
||||
|
||||
executeTransformCommand(properties, targetFile, timeout);
|
||||
}
|
||||
|
||||
public void executeTransformCommand(Map<String, String> properties, File targetFile, Long timeout)
|
||||
{
|
||||
timeout = timeout != null && timeout > 0 ? timeout : 0;
|
||||
RuntimeExec.ExecutionResult result = transformCommand.execute(properties, timeout);
|
||||
|
||||
if (result.getExitValue() != 0 && result.getStdErr() != null && result.getStdErr().length() > 0)
|
||||
{
|
||||
throw new TransformException(400, "Transformer exit code was not 0: \n" + result.getStdErr());
|
||||
}
|
||||
|
||||
if (!targetFile.exists() || targetFile.length() == 0)
|
||||
{
|
||||
throw new TransformException(500, "Transformer failed to create an output file");
|
||||
}
|
||||
}
|
||||
|
||||
protected ResponseEntity<Resource> createAttachment(String targetFilename, File targetFile, Long testDelay)
|
||||
{
|
||||
Resource targetResource = load(targetFile);
|
||||
targetFilename = UriUtils.encodePath(StringUtils.getFilename(targetFilename), "UTF-8");
|
||||
ResponseEntity<Resource> body = ResponseEntity.ok().header(HttpHeaders.CONTENT_DISPOSITION,
|
||||
"attachment; filename*= UTF-8''" + targetFilename).body(targetResource);
|
||||
LogEntry.setTargetSize(targetFile.length());
|
||||
long time = LogEntry.setStatusCodeAndMessage(200, "Success");
|
||||
time += LogEntry.addDelay(testDelay);
|
||||
getProbeTestTransformInternal().recordTransformTime(time);
|
||||
return body;
|
||||
}
|
||||
|
||||
/**
|
||||
* Safely converts a {@link String} to an {@link Integer}
|
||||
*
|
||||
* @param param String to be converted
|
||||
* @return Null if param is null or converted value as {@link Integer}
|
||||
*/
|
||||
protected Integer stringToInteger(String param)
|
||||
{
|
||||
return param == null ? null : Integer.parseInt(param);
|
||||
}
|
||||
|
||||
/**
|
||||
* Safely converts a {@link String} to an {@link Integer}
|
||||
*
|
||||
* @param param String to be converted
|
||||
* @return Null if param is null or converted value as {@link Boolean}
|
||||
*/
|
||||
protected Boolean stringToBoolean(String param)
|
||||
{
|
||||
return param == null? null : Boolean.parseBoolean(param);
|
||||
}
|
||||
|
||||
public AlfrescoSharedFileStoreClient getAlfrescoSharedFileStoreClient()
|
||||
{
|
||||
return alfrescoSharedFileStoreClient;
|
||||
}
|
||||
|
||||
public void setAlfrescoSharedFileStoreClient(
|
||||
AlfrescoSharedFileStoreClient alfrescoSharedFileStoreClient)
|
||||
{
|
||||
this.alfrescoSharedFileStoreClient = alfrescoSharedFileStoreClient;
|
||||
}
|
||||
}
|
||||
|
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Repository
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* Alfresco is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.transformer;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class Application
|
||||
{
|
||||
public static void main(String[] args)
|
||||
{
|
||||
SpringApplication.run(Application.class, args);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,137 @@
|
||||
package org.alfresco.transformer;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.alfresco.transform.client.model.TransformReply;
|
||||
import org.alfresco.transform.client.model.TransformRequest;
|
||||
import org.alfresco.transformer.exceptions.TransformException;
|
||||
import org.alfresco.transformer.logging.LogEntry;
|
||||
import org.alfresco.transformer.probes.ProbeTestTransform;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.TypeMismatchException;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.MissingServletRequestParameterException;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
public interface TransformController
|
||||
{
|
||||
Log logger = LogFactory.getLog(TransformController.class);
|
||||
|
||||
ResponseEntity<TransformReply> transform(TransformRequest transformRequest, Long timeout);
|
||||
|
||||
void processTransform(File sourceFile, File targetFile, Map<String, String> transformOptions,
|
||||
Long timeout);
|
||||
|
||||
String getTransformerName();
|
||||
|
||||
ProbeTestTransform getProbeTestTransform();
|
||||
|
||||
default String probe(HttpServletRequest request, boolean isLiveProbe)
|
||||
{
|
||||
return getProbeTestTransform().doTransformOrNothing(request, isLiveProbe);
|
||||
}
|
||||
|
||||
@RequestMapping("/version")
|
||||
@ResponseBody
|
||||
String version();
|
||||
|
||||
@GetMapping("/")
|
||||
default String transformForm(Model model)
|
||||
{
|
||||
return "transformForm"; // the name of the template
|
||||
}
|
||||
|
||||
@GetMapping("/error")
|
||||
default String error()
|
||||
{
|
||||
return "error"; // the name of the template
|
||||
}
|
||||
|
||||
@GetMapping("/log")
|
||||
default String log(Model model)
|
||||
{
|
||||
model.addAttribute("title", getTransformerName() + " Log Entries");
|
||||
Collection<LogEntry> log = LogEntry.getLog();
|
||||
if (!log.isEmpty())
|
||||
{
|
||||
model.addAttribute("log", log);
|
||||
}
|
||||
return "log"; // the name of the template
|
||||
}
|
||||
|
||||
@GetMapping("/ready")
|
||||
@ResponseBody
|
||||
default String ready(HttpServletRequest request)
|
||||
{
|
||||
return probe(request, false);
|
||||
}
|
||||
|
||||
@GetMapping("/live")
|
||||
@ResponseBody
|
||||
default String live(HttpServletRequest request)
|
||||
{
|
||||
return probe(request, true);
|
||||
}
|
||||
|
||||
//region [Exception Handlers]
|
||||
@ExceptionHandler(TypeMismatchException.class)
|
||||
default void handleParamsTypeMismatch(HttpServletResponse response,
|
||||
MissingServletRequestParameterException e) throws IOException
|
||||
{
|
||||
String transformerName = getTransformerName();
|
||||
String name = e.getParameterName();
|
||||
String message = "Request parameter " + name + " is of the wrong type";
|
||||
int statusCode = 400;
|
||||
|
||||
logger.error(message);
|
||||
|
||||
LogEntry.setStatusCodeAndMessage(statusCode, message);
|
||||
|
||||
response.sendError(statusCode, transformerName + " - " + message);
|
||||
}
|
||||
|
||||
@ExceptionHandler(MissingServletRequestParameterException.class)
|
||||
default void handleMissingParams(HttpServletResponse response,
|
||||
MissingServletRequestParameterException e) throws IOException
|
||||
{
|
||||
String transformerName = getTransformerName();
|
||||
String name = e.getParameterName();
|
||||
String message = "Request parameter " + name + " is missing";
|
||||
int statusCode = 400;
|
||||
|
||||
logger.error(message);
|
||||
|
||||
LogEntry.setStatusCodeAndMessage(statusCode, message);
|
||||
|
||||
response.sendError(statusCode, transformerName + " - " + message);
|
||||
}
|
||||
|
||||
@ExceptionHandler(TransformException.class)
|
||||
default void transformExceptionWithMessage(HttpServletResponse response,
|
||||
TransformException e) throws IOException
|
||||
{
|
||||
String transformerName = getTransformerName();
|
||||
String message = e.getMessage();
|
||||
int statusCode = e.getStatusCode();
|
||||
|
||||
logger.error(message);
|
||||
|
||||
long time = LogEntry.setStatusCodeAndMessage(statusCode, message);
|
||||
getProbeTestTransform().recordTransformTime(time);
|
||||
|
||||
// Forced to include the transformer name in the message (see commented out version of this method)
|
||||
response.sendError(statusCode, transformerName + " - " + message);
|
||||
}
|
||||
//endregion
|
||||
}
|
@@ -25,18 +25,22 @@
|
||||
*/
|
||||
package org.alfresco.transformer;
|
||||
|
||||
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
|
||||
import static org.alfresco.transformer.fs.FileManager.SOURCE_FILE;
|
||||
import static org.alfresco.transformer.fs.FileManager.TARGET_FILE;
|
||||
import static org.alfresco.transformer.fs.FileManager.deleteFile;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.File;
|
||||
|
||||
import org.alfresco.transformer.logging.LogEntry;
|
||||
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
|
||||
|
||||
|
||||
public class TransformInterceptor extends HandlerInterceptorAdapter
|
||||
{
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request,
|
||||
HttpServletResponse response, Object handler) throws Exception
|
||||
HttpServletResponse response, Object handler)
|
||||
{
|
||||
LogEntry.start();
|
||||
return true;
|
||||
@@ -45,21 +49,11 @@ public class TransformInterceptor extends HandlerInterceptorAdapter
|
||||
@Override
|
||||
public void afterCompletion(HttpServletRequest request,
|
||||
HttpServletResponse response, Object handler, Exception ex)
|
||||
throws Exception
|
||||
{
|
||||
// TargetFile cannot be deleted until completion, otherwise 0 bytes are sent.
|
||||
deleteFile(request, AbstractTransformerController.SOURCE_FILE);
|
||||
deleteFile(request, AbstractTransformerController.TARGET_FILE);
|
||||
deleteFile(request, SOURCE_FILE);
|
||||
deleteFile(request, TARGET_FILE);
|
||||
|
||||
LogEntry.complete();
|
||||
}
|
||||
|
||||
private void deleteFile(HttpServletRequest request, String attributeName)
|
||||
{
|
||||
File file = (File) request.getAttribute(attributeName);
|
||||
if (file != null)
|
||||
{
|
||||
file.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -5,10 +5,11 @@
|
||||
* pursuant to a written agreement and any use of this program without such an
|
||||
* agreement is prohibited.
|
||||
*/
|
||||
package org.alfresco.transformer;
|
||||
package org.alfresco.transformer.clients;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.alfresco.transformer.exceptions.TransformException;
|
||||
import org.alfresco.transformer.model.FileRefResponse;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
@@ -23,8 +23,10 @@
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.transformer;
|
||||
package org.alfresco.transformer.config;
|
||||
|
||||
import org.alfresco.transformer.TransformInterceptor;
|
||||
import org.alfresco.transformer.clients.AlfrescoSharedFileStoreClient;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.client.RestTemplate;
|
@@ -23,11 +23,11 @@
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.transformer;
|
||||
package org.alfresco.transformer.exceptions;
|
||||
|
||||
public class TransformException extends RuntimeException
|
||||
{
|
||||
private int statusCode;
|
||||
private final int statusCode;
|
||||
|
||||
public TransformException(int statusCode, String message)
|
||||
{
|
@@ -0,0 +1,67 @@
|
||||
package org.alfresco.transformer.executors;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.transformer.exceptions.TransformException;
|
||||
import org.alfresco.util.exec.RuntimeExec;
|
||||
|
||||
/**
|
||||
*/
|
||||
public abstract class AbstractCommandExecutor implements CommandExecutor
|
||||
{
|
||||
private RuntimeExec transformCommand = createTransformCommand();
|
||||
private RuntimeExec checkCommand = createCheckCommand();
|
||||
|
||||
protected abstract RuntimeExec createTransformCommand();
|
||||
|
||||
protected abstract RuntimeExec createCheckCommand();
|
||||
|
||||
// todo remove these setters and and make the fields final
|
||||
public void setTransformCommand(RuntimeExec re) {
|
||||
transformCommand = re;
|
||||
}
|
||||
|
||||
public void setCheckCommand(RuntimeExec re) {
|
||||
checkCommand = re;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(Map<String, String> properties, File targetFile, Long timeout)
|
||||
{
|
||||
timeout = timeout != null && timeout > 0 ? timeout : 0;
|
||||
RuntimeExec.ExecutionResult result = transformCommand.execute(properties, timeout);
|
||||
|
||||
if (result.getExitValue() != 0 && result.getStdErr() != null && result.getStdErr().length() > 0)
|
||||
{
|
||||
throw new TransformException(400, "Transformer exit code was not 0: \n" + result.getStdErr());
|
||||
}
|
||||
|
||||
if (!targetFile.exists() || targetFile.length() == 0)
|
||||
{
|
||||
throw new TransformException(500, "Transformer failed to create an output file");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String version()
|
||||
{
|
||||
String version = "Version not checked";
|
||||
if (checkCommand != null)
|
||||
{
|
||||
RuntimeExec.ExecutionResult result = checkCommand.execute();
|
||||
if (result.getExitValue() != 0 && result.getStdErr() != null && result.getStdErr().length() > 0)
|
||||
{
|
||||
throw new TransformException(500, "Transformer version check exit code was not 0: \n" + result);
|
||||
}
|
||||
|
||||
version = result.getStdOut().trim();
|
||||
if (version.isEmpty())
|
||||
{
|
||||
throw new TransformException(500, "Transformer version check failed to create any output");
|
||||
}
|
||||
}
|
||||
|
||||
return version;
|
||||
}
|
||||
}
|
@@ -0,0 +1,45 @@
|
||||
package org.alfresco.transformer.executors;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.transformer.logging.LogEntry;
|
||||
|
||||
/**
|
||||
* Basic interface for executing transformations via Shell commands
|
||||
*
|
||||
* @author Cezar Leahu
|
||||
*/
|
||||
public interface CommandExecutor
|
||||
{
|
||||
void run(Map<String, String> properties, File targetFile, Long timeout);
|
||||
|
||||
String version();
|
||||
|
||||
default void run(String options, File sourceFile, File targetFile,
|
||||
Long timeout)
|
||||
{
|
||||
LogEntry.setOptions(options);
|
||||
|
||||
Map<String, String> properties = new HashMap<>();
|
||||
properties.put("options", options);
|
||||
properties.put("source", sourceFile.getAbsolutePath());
|
||||
properties.put("target", targetFile.getAbsolutePath());
|
||||
|
||||
run(properties, targetFile, timeout);
|
||||
}
|
||||
|
||||
default void run(String options, File sourceFile, String pageRange, File
|
||||
targetFile, Long timeout)
|
||||
{
|
||||
LogEntry.setOptions(pageRange + (pageRange.isEmpty() ? "" : " ") + options);
|
||||
|
||||
Map<String, String> properties = new HashMap<>();
|
||||
properties.put("options", options);
|
||||
properties.put("source", sourceFile.getAbsolutePath() + pageRange);
|
||||
properties.put("target", targetFile.getAbsolutePath());
|
||||
|
||||
run(properties, targetFile, timeout);
|
||||
}
|
||||
}
|
@@ -0,0 +1,15 @@
|
||||
package org.alfresco.transformer.executors;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.alfresco.transformer.exceptions.TransformException;
|
||||
|
||||
/**
|
||||
* Basic interface for executing transformations inside Java/JVM
|
||||
*
|
||||
* @author Cezar Leahu
|
||||
*/
|
||||
public interface JavaExecutor
|
||||
{
|
||||
void call(File sourceFile, File targetFile, String... args) throws TransformException;
|
||||
}
|
@@ -0,0 +1,195 @@
|
||||
package org.alfresco.transformer.fs;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.alfresco.transformer.exceptions.TransformException;
|
||||
import org.alfresco.transformer.logging.LogEntry;
|
||||
import org.alfresco.util.TempFileProvider;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.UrlResource;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import org.springframework.web.util.UriUtils;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class FileManager
|
||||
{
|
||||
public static final String SOURCE_FILE = "sourceFile";
|
||||
public static final String TARGET_FILE = "targetFile";
|
||||
private static final String FILENAME = "filename=";
|
||||
|
||||
/**
|
||||
* Returns a File to be used to store the result of a transformation.
|
||||
*
|
||||
* @param request
|
||||
* @param filename The targetFilename supplied in the request. Only the filename if a path is used as part of the
|
||||
* temporary filename.
|
||||
* @return a temporary File.
|
||||
* @throws TransformException if there was no target filename.
|
||||
*/
|
||||
public static File createTargetFile(HttpServletRequest request, String filename)
|
||||
{
|
||||
File file = buildFile(filename);
|
||||
request.setAttribute(TARGET_FILE, file);
|
||||
return file;
|
||||
}
|
||||
|
||||
public static File buildFile(String filename)
|
||||
{
|
||||
filename = checkFilename( false, filename);
|
||||
LogEntry.setTarget(filename);
|
||||
return TempFileProvider.createTempFile("target_", "_" + filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the filename is okay to uses in a temporary file name.
|
||||
*
|
||||
* @param filename or path to be checked.
|
||||
* @return the filename part of the supplied filename if it was a path.
|
||||
* @throws TransformException if there was no target filename.
|
||||
*/
|
||||
private static String checkFilename(boolean source, String filename)
|
||||
{
|
||||
filename = StringUtils.getFilename(filename);
|
||||
if (filename == null || filename.isEmpty())
|
||||
{
|
||||
String sourceOrTarget = source ? "source" : "target";
|
||||
int statusCode = source ? 400 : 500;
|
||||
throw new TransformException(statusCode, "The " + sourceOrTarget + " filename was not supplied");
|
||||
}
|
||||
return filename;
|
||||
}
|
||||
|
||||
private static void save(MultipartFile multipartFile, File file)
|
||||
{
|
||||
try
|
||||
{
|
||||
Files.copy(multipartFile.getInputStream(), file.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new TransformException(507, "Failed to store the source file", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void save(Resource body, File file)
|
||||
{
|
||||
try
|
||||
{
|
||||
Files.copy(body.getInputStream(), file.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new TransformException(507, "Failed to store the source file", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static Resource load(File file)
|
||||
{
|
||||
try
|
||||
{
|
||||
Resource resource = new UrlResource(file.toURI());
|
||||
if (resource.exists() || resource.isReadable())
|
||||
{
|
||||
return resource;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new TransformException(500, "Could not read the target file: " + file.getPath());
|
||||
}
|
||||
}
|
||||
catch (MalformedURLException e)
|
||||
{
|
||||
throw new TransformException(500, "The target filename was malformed: " + file.getPath(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public static String getFilenameFromContentDisposition(HttpHeaders headers)
|
||||
{
|
||||
String filename = "";
|
||||
String contentDisposition = headers.getFirst(HttpHeaders.CONTENT_DISPOSITION);
|
||||
if (contentDisposition != null)
|
||||
{
|
||||
String[] strings = contentDisposition.split("; *");
|
||||
filename = Arrays.stream(strings)
|
||||
.filter(s -> s.startsWith(FILENAME))
|
||||
.findFirst()
|
||||
.map(s -> s.substring(FILENAME.length()))
|
||||
.orElse("");
|
||||
}
|
||||
return filename;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the file name for the target file
|
||||
*
|
||||
* @param fileName Desired file name
|
||||
* @param targetExtension File extension
|
||||
* @return Target file name
|
||||
*/
|
||||
public static String createTargetFileName(String fileName, String targetExtension)
|
||||
{
|
||||
String targetFilename = null;
|
||||
String sourceFilename = fileName;
|
||||
sourceFilename = StringUtils.getFilename(sourceFilename);
|
||||
if (sourceFilename != null && !sourceFilename.isEmpty())
|
||||
{
|
||||
String ext = StringUtils.getFilenameExtension(sourceFilename);
|
||||
targetFilename = (ext != null && !ext.isEmpty()
|
||||
? sourceFilename.substring(0, sourceFilename.length()-ext.length()-1)
|
||||
: sourceFilename)+
|
||||
'.'+targetExtension;
|
||||
}
|
||||
return targetFilename;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a File that holds the source content for a transformation.
|
||||
*
|
||||
* @param request
|
||||
* @param multipartFile from the request
|
||||
* @return a temporary File.
|
||||
* @throws TransformException if there was no source filename.
|
||||
*/
|
||||
public static File createSourceFile(HttpServletRequest request, MultipartFile multipartFile)
|
||||
{
|
||||
String filename = multipartFile.getOriginalFilename();
|
||||
long size = multipartFile.getSize();
|
||||
filename = checkFilename( true, filename);
|
||||
File file = TempFileProvider.createTempFile("source_", "_" + filename);
|
||||
request.setAttribute(SOURCE_FILE, file);
|
||||
save(multipartFile, file);
|
||||
LogEntry.setSource(filename, size);
|
||||
return file;
|
||||
}
|
||||
|
||||
public static void deleteFile(HttpServletRequest request, String attributeName)
|
||||
{
|
||||
File file = (File) request.getAttribute(attributeName);
|
||||
if (file != null)
|
||||
{
|
||||
file.delete();
|
||||
}
|
||||
}
|
||||
|
||||
public static ResponseEntity<Resource> createAttachment(String targetFilename, File
|
||||
targetFile)
|
||||
{
|
||||
Resource targetResource = load(targetFile);
|
||||
targetFilename = UriUtils.encodePath(StringUtils.getFilename(targetFilename), "UTF-8");
|
||||
return ResponseEntity.ok().header(HttpHeaders
|
||||
.CONTENT_DISPOSITION,
|
||||
"attachment; filename*= UTF-8''" + targetFilename).body(targetResource);
|
||||
}
|
||||
}
|
@@ -23,7 +23,9 @@
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.transformer;
|
||||
package org.alfresco.transformer.logging;
|
||||
|
||||
import static java.lang.Math.max;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Collection;
|
||||
@@ -32,7 +34,8 @@ import java.util.Deque;
|
||||
import java.util.concurrent.ConcurrentLinkedDeque;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import static java.lang.Math.max;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* Provides setter and getter methods to allow the current Thread to set various log properties and for these
|
||||
@@ -40,8 +43,9 @@ import static java.lang.Math.max;
|
||||
* current entry to an internal log Collection of the latest entries. The {@link #getLog()} method is used to obtain
|
||||
* access to this collection.
|
||||
*/
|
||||
public class LogEntry
|
||||
public final class LogEntry
|
||||
{
|
||||
private static final Log logger = LogFactory.getLog(LogEntry.class);
|
||||
// TODO allow ProbeTestTransform to find out if there are any transforms running longer than the max time.
|
||||
|
||||
private static final AtomicInteger count = new AtomicInteger(0);
|
||||
@@ -49,20 +53,15 @@ public class LogEntry
|
||||
private static final int MAX_LOG_SIZE = 10;
|
||||
private static final SimpleDateFormat HH_MM_SS = new SimpleDateFormat("HH:mm:ss");
|
||||
|
||||
private static ThreadLocal<LogEntry> currentLogEntry = new ThreadLocal<LogEntry>()
|
||||
{
|
||||
@Override
|
||||
protected LogEntry initialValue()
|
||||
private static final ThreadLocal<LogEntry> currentLogEntry = ThreadLocal.withInitial(() -> {
|
||||
LogEntry logEntry = new LogEntry();
|
||||
if (log.size() >= MAX_LOG_SIZE)
|
||||
{
|
||||
LogEntry logEntry = new LogEntry();
|
||||
if (log.size() >= MAX_LOG_SIZE)
|
||||
{
|
||||
log.removeLast();
|
||||
}
|
||||
log.addFirst(logEntry);
|
||||
return logEntry;
|
||||
log.removeLast();
|
||||
}
|
||||
};
|
||||
log.addFirst(logEntry);
|
||||
return logEntry;
|
||||
});
|
||||
|
||||
private final int id = count.incrementAndGet();
|
||||
private final long start = System.currentTimeMillis();
|
||||
@@ -204,9 +203,9 @@ public class LogEntry
|
||||
}
|
||||
currentLogEntry.remove();
|
||||
|
||||
if (AbstractTransformerController.logger != null && AbstractTransformerController.logger.isDebugEnabled())
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
AbstractTransformerController.logger.debug(logEntry.toString());
|
||||
logger.debug(logEntry.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -279,6 +278,7 @@ public class LogEntry
|
||||
|
||||
private String size(long size)
|
||||
{
|
||||
// TODO fix numeric overflow in TB expression
|
||||
return size == -1 ? "" : size(size, "1 byte",
|
||||
new String[] { "bytes", " KB", " MB", " GB", " TB" },
|
||||
new long[] { 1024, 1024*1024, 1024*1024*1024, 1024*1024*1024*1024, Long.MAX_VALUE });
|
@@ -0,0 +1,12 @@
|
||||
package org.alfresco.transformer.logging;
|
||||
|
||||
public interface StandardMessages
|
||||
{
|
||||
String ENTERPRISE_LICENCE =
|
||||
"This image is only intended to be used with the Alfresco Enterprise Content Repository which is covered by\n"+
|
||||
"https://www.alfresco.com/legal/agreements and https://www.alfresco.com/terms-use\n" +
|
||||
"\n" +
|
||||
"License rights for this program may be obtained from Alfresco Software, Ltd. pursuant to a written agreement\n" +
|
||||
"and any use of this program without such an agreement is prohibited.\n" +
|
||||
"\n" ;
|
||||
}
|
@@ -23,7 +23,10 @@
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.transformer;
|
||||
package org.alfresco.transformer.probes;
|
||||
|
||||
import static org.alfresco.transformer.fs.FileManager.SOURCE_FILE;
|
||||
import static org.alfresco.transformer.fs.FileManager.TARGET_FILE;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@@ -35,6 +38,9 @@ import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.alfresco.transformer.AbstractTransformerController;
|
||||
import org.alfresco.transformer.exceptions.TransformException;
|
||||
import org.alfresco.transformer.logging.LogEntry;
|
||||
import org.alfresco.util.TempFileProvider;
|
||||
import org.apache.commons.logging.Log;
|
||||
|
||||
@@ -60,9 +66,9 @@ import org.apache.commons.logging.Log;
|
||||
* <li>maxTransformSeconds - the maximum time for a transformation, including failed ones.</li>
|
||||
* </ul>
|
||||
*/
|
||||
abstract class ProbeTestTransform
|
||||
public abstract class ProbeTestTransform
|
||||
{
|
||||
public static final int AVERAGE_OVER_TRANSFORMS = 5;
|
||||
private static final int AVERAGE_OVER_TRANSFORMS = 5;
|
||||
private final String sourceFilename;
|
||||
private final String targetFilename;
|
||||
private final long minExpectedLength;
|
||||
@@ -70,22 +76,32 @@ abstract class ProbeTestTransform
|
||||
|
||||
private final Log logger;
|
||||
|
||||
int livenessPercent;
|
||||
long probeCount;
|
||||
int transCount;
|
||||
long normalTime;
|
||||
long maxTime = Long.MAX_VALUE;
|
||||
long nextTransformTime;
|
||||
private int livenessPercent;
|
||||
private long probeCount;
|
||||
private int transCount;
|
||||
private long normalTime;
|
||||
private long maxTime = Long.MAX_VALUE;
|
||||
private long nextTransformTime;
|
||||
|
||||
private final boolean livenessTransformEnabled;
|
||||
private final long livenessTransformPeriod;
|
||||
private long maxTransformCount = Long.MAX_VALUE;
|
||||
private final long maxTransformCount;
|
||||
private long maxTransformTime;
|
||||
|
||||
private AtomicBoolean initialised = new AtomicBoolean(false);
|
||||
private AtomicBoolean readySent = new AtomicBoolean(false);
|
||||
private AtomicLong transformCount = new AtomicLong(0);
|
||||
private AtomicBoolean die = new AtomicBoolean(false);
|
||||
private final AtomicBoolean initialised = new AtomicBoolean(false);
|
||||
private final AtomicBoolean readySent = new AtomicBoolean(false);
|
||||
private final AtomicLong transformCount = new AtomicLong(0);
|
||||
private final AtomicBoolean die = new AtomicBoolean(false);
|
||||
|
||||
public int getLivenessPercent()
|
||||
{
|
||||
return livenessPercent;
|
||||
}
|
||||
|
||||
public long getMaxTime()
|
||||
{
|
||||
return maxTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* See Probes.md for more info.
|
||||
@@ -97,12 +113,12 @@ abstract class ProbeTestTransform
|
||||
* @param maxTransformSeconds default values normally supplied by helm. Not identical so we can be sure which value is used.
|
||||
* @param livenessTransformPeriodSeconds default values normally supplied by helm. Not identical so we can be sure which value is used.
|
||||
*/
|
||||
public ProbeTestTransform(AbstractTransformerController controller,
|
||||
public ProbeTestTransform(AbstractTransformerController controller, Log logger,
|
||||
String sourceFilename, String targetFilename, long expectedLength, long plusOrMinus,
|
||||
int livenessPercent, long maxTransforms, long maxTransformSeconds,
|
||||
long livenessTransformPeriodSeconds)
|
||||
{
|
||||
logger = controller.logger;
|
||||
this.logger = logger;
|
||||
|
||||
this.sourceFilename = sourceFilename;
|
||||
this.targetFilename = targetFilename;
|
||||
@@ -128,7 +144,7 @@ abstract class ProbeTestTransform
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
protected long getPositiveLongEnv(String name, long defaultValue)
|
||||
private long getPositiveLongEnv(String name, long defaultValue)
|
||||
{
|
||||
long l = -1;
|
||||
String env = System.getenv(name);
|
||||
@@ -171,7 +187,7 @@ abstract class ProbeTestTransform
|
||||
{
|
||||
String probeMessage = getProbeMessage(isLiveProbe);
|
||||
String message = "Success - No transform.";
|
||||
LogEntry.setStatusCodeAndMessage(200, probeMessage+message);
|
||||
LogEntry.setStatusCodeAndMessage(200, probeMessage + message);
|
||||
if (!isLiveProbe && !readySent.getAndSet(true))
|
||||
{
|
||||
logger.info(probeMessage+message);
|
||||
@@ -179,7 +195,7 @@ abstract class ProbeTestTransform
|
||||
return message;
|
||||
}
|
||||
|
||||
String doTransform(HttpServletRequest request, boolean isLiveProbe)
|
||||
private String doTransform(HttpServletRequest request, boolean isLiveProbe)
|
||||
{
|
||||
checkMaxTransformTimeAndCount(isLiveProbe);
|
||||
|
||||
@@ -207,9 +223,9 @@ abstract class ProbeTestTransform
|
||||
|
||||
if (time > maxTime)
|
||||
{
|
||||
throw new TransformException(500, getMessagePrefix(isLiveProbe)+
|
||||
message+" which is more than "+ livenessPercent +
|
||||
"% slower than the normal value of "+normalTime+"ms");
|
||||
throw new TransformException(500, getMessagePrefix(isLiveProbe) +
|
||||
message + " which is more than " + livenessPercent +
|
||||
"% slower than the normal value of " + normalTime + "ms");
|
||||
}
|
||||
|
||||
// We don't care if the ready or live probe works out if we are 'ready' to take requests.
|
||||
@@ -237,11 +253,11 @@ abstract class ProbeTestTransform
|
||||
}
|
||||
}
|
||||
|
||||
File getSourceFile(HttpServletRequest request, boolean isLiveProbe)
|
||||
private File getSourceFile(HttpServletRequest request, boolean isLiveProbe)
|
||||
{
|
||||
incrementTransformerCount();
|
||||
File sourceFile = TempFileProvider.createTempFile("source_", "_"+ sourceFilename);
|
||||
request.setAttribute(AbstractTransformerController.SOURCE_FILE, sourceFile);
|
||||
request.setAttribute(SOURCE_FILE, sourceFile);
|
||||
try (InputStream inputStream = this.getClass().getResourceAsStream('/'+sourceFilename))
|
||||
{
|
||||
Files.copy(inputStream, sourceFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
||||
@@ -256,15 +272,15 @@ abstract class ProbeTestTransform
|
||||
return sourceFile;
|
||||
}
|
||||
|
||||
File getTargetFile(HttpServletRequest request)
|
||||
private File getTargetFile(HttpServletRequest request)
|
||||
{
|
||||
File targetFile = TempFileProvider.createTempFile("target_", "_"+targetFilename);
|
||||
request.setAttribute(AbstractTransformerController.TARGET_FILE, targetFile);
|
||||
request.setAttribute(TARGET_FILE, targetFile);
|
||||
LogEntry.setTarget(targetFilename);
|
||||
return targetFile;
|
||||
}
|
||||
|
||||
void recordTransformTime(long time)
|
||||
public void recordTransformTime(long time)
|
||||
{
|
||||
if (maxTransformTime > 0 && time > maxTransformTime)
|
||||
{
|
||||
@@ -272,7 +288,7 @@ abstract class ProbeTestTransform
|
||||
}
|
||||
}
|
||||
|
||||
void calculateMaxTime(long time, boolean isLiveProbe)
|
||||
public void calculateMaxTime(long time, boolean isLiveProbe)
|
||||
{
|
||||
if (transCount <= AVERAGE_OVER_TRANSFORMS)
|
||||
{
|
||||
@@ -331,4 +347,15 @@ abstract class ProbeTestTransform
|
||||
{
|
||||
transformCount.incrementAndGet();
|
||||
}
|
||||
|
||||
public void setLivenessPercent(int livenessPercent)
|
||||
{
|
||||
this.livenessPercent = livenessPercent;
|
||||
}
|
||||
|
||||
public long getNormalTime()
|
||||
{
|
||||
|
||||
return normalTime;
|
||||
}
|
||||
}
|
@@ -0,0 +1,28 @@
|
||||
package org.alfresco.transformer.util;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class Util
|
||||
{
|
||||
/**
|
||||
* Safely converts a {@link String} to an {@link Integer}
|
||||
*
|
||||
* @param param String to be converted
|
||||
* @return Null if param is null or converted value as {@link Integer}
|
||||
*/
|
||||
public static Integer stringToInteger(String param)
|
||||
{
|
||||
return param == null ? null : Integer.parseInt(param);
|
||||
}
|
||||
|
||||
/**
|
||||
* Safely converts a {@link String} to an {@link Integer}
|
||||
*
|
||||
* @param param String to be converted
|
||||
* @return Null if param is null or converted value as {@link Boolean}
|
||||
*/
|
||||
public static Boolean stringToBoolean(String param)
|
||||
{
|
||||
return param == null? null : Boolean.parseBoolean(param);
|
||||
}
|
||||
}
|
@@ -32,8 +32,6 @@ import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
import org.springframework.http.*;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.springframework.test.util.AssertionErrors.assertTrue;
|
||||
|
||||
@@ -54,7 +52,7 @@ public abstract class AbstractHttpRequestTest
|
||||
protected abstract String getSourceExtension();
|
||||
|
||||
@Test
|
||||
public void testPageExists() throws Exception
|
||||
public void testPageExists()
|
||||
{
|
||||
String result = restTemplate.getForObject("http://localhost:" + port + "/", String.class);
|
||||
|
||||
@@ -63,7 +61,7 @@ public abstract class AbstractHttpRequestTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void logPageExists() throws Exception
|
||||
public void logPageExists()
|
||||
{
|
||||
String result = restTemplate.getForObject("http://localhost:" + port + "/log", String.class);
|
||||
|
||||
@@ -72,7 +70,7 @@ public abstract class AbstractHttpRequestTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void errorPageExists() throws Exception
|
||||
public void errorPageExists()
|
||||
{
|
||||
String result = restTemplate.getForObject("http://localhost:" + port + "/error", String.class);
|
||||
|
||||
@@ -81,7 +79,7 @@ public abstract class AbstractHttpRequestTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noFileError() throws Exception
|
||||
public void noFileError()
|
||||
{
|
||||
// Transformer name is not part of the title as this is checked by another handler
|
||||
assertTransformError(false,
|
||||
@@ -94,22 +92,22 @@ public abstract class AbstractHttpRequestTest
|
||||
assertMissingParameter("targetExtension");
|
||||
}
|
||||
|
||||
protected void assertMissingParameter(String name) throws IOException
|
||||
private void assertMissingParameter(String name)
|
||||
{
|
||||
assertTransformError(true,
|
||||
getTransformerName() + " - Request parameter " + name + " is missing");
|
||||
}
|
||||
|
||||
protected void assertTransformError(boolean addFile, String errorMessage) throws IOException
|
||||
private void assertTransformError(boolean addFile, String errorMessage)
|
||||
{
|
||||
LinkedMultiValueMap<String, Object> parameters = new LinkedMultiValueMap<String, Object>();
|
||||
LinkedMultiValueMap<String, Object> parameters = new LinkedMultiValueMap<>();
|
||||
if (addFile)
|
||||
{
|
||||
parameters.add("file", new org.springframework.core.io.ClassPathResource("quick."+getSourceExtension()));
|
||||
}
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
|
||||
HttpEntity<LinkedMultiValueMap<String, Object>> entity = new HttpEntity<LinkedMultiValueMap<String, Object>>(parameters, headers);
|
||||
HttpEntity<LinkedMultiValueMap<String, Object>> entity = new HttpEntity<>(parameters, headers);
|
||||
ResponseEntity<String> response = restTemplate.exchange("/transform", HttpMethod.POST, entity, String.class, "");
|
||||
assertEquals(errorMessage, getErrorMessage(response.getBody()));
|
||||
}
|
||||
@@ -117,7 +115,7 @@ public abstract class AbstractHttpRequestTest
|
||||
// Strip out just the error message from the returned json content body
|
||||
// Had been expecting the Error page to be returned, but we end up with the json in this test harness.
|
||||
// Is correct if run manually, so not worrying too much about this.
|
||||
private String getErrorMessage(String content) throws IOException
|
||||
private String getErrorMessage(String content)
|
||||
{
|
||||
String message = "";
|
||||
int i = content.indexOf("\"message\":\"");
|
||||
|
@@ -27,12 +27,7 @@ package org.alfresco.transformer;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.anyLong;
|
||||
import static org.mockito.Matchers.anyObject;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
@@ -44,33 +39,21 @@ import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.file.Files;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.alfresco.transform.client.model.TransformReply;
|
||||
import org.alfresco.transform.client.model.TransformRequest;
|
||||
import org.alfresco.transformer.model.FileRefEntity;
|
||||
import org.alfresco.transformer.model.FileRefResponse;
|
||||
import org.alfresco.util.exec.RuntimeExec;
|
||||
import org.junit.Before;
|
||||
import org.alfresco.transformer.clients.AlfrescoSharedFileStoreClient;
|
||||
import org.alfresco.transformer.probes.ProbeTestTransform;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.stubbing.Answer;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.core.io.FileSystemResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.mock.web.MockMultipartFile;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
@@ -85,18 +68,9 @@ public abstract class AbstractTransformerControllerTest
|
||||
@Autowired
|
||||
protected ObjectMapper objectMapper;
|
||||
|
||||
@Mock
|
||||
private RuntimeExec mockTransformCommand;
|
||||
|
||||
@Mock
|
||||
private RuntimeExec mockCheckCommand;
|
||||
|
||||
@Mock
|
||||
@MockBean
|
||||
protected AlfrescoSharedFileStoreClient alfrescoSharedFileStoreClient;
|
||||
|
||||
@Mock
|
||||
private RuntimeExec.ExecutionResult mockExecutionResult;
|
||||
|
||||
protected String sourceExtension;
|
||||
protected String targetExtension;
|
||||
protected String sourceMimetype;
|
||||
@@ -108,88 +82,14 @@ public abstract class AbstractTransformerControllerTest
|
||||
protected byte[] expectedSourceFileBytes;
|
||||
protected byte[] expectedTargetFileBytes;
|
||||
|
||||
protected AbstractTransformerController controller;
|
||||
|
||||
@Before
|
||||
public void before() throws Exception
|
||||
{
|
||||
}
|
||||
|
||||
// Called by sub class
|
||||
public void mockTransformCommand(AbstractTransformerController controller, String sourceExtension,
|
||||
String targetExtension, String sourceMimetype,
|
||||
boolean readTargetFileBytes) throws IOException
|
||||
{
|
||||
this.controller = controller;
|
||||
this.sourceExtension = sourceExtension;
|
||||
this.targetExtension = targetExtension;
|
||||
this.sourceMimetype = sourceMimetype;
|
||||
protected abstract void mockTransformCommand(String sourceExtension,
|
||||
String targetExtension, String sourceMimetype,
|
||||
boolean readTargetFileBytes) throws IOException;
|
||||
|
||||
expectedOptions = null;
|
||||
expectedSourceSuffix = null;
|
||||
expectedSourceFileBytes = readTestFile(sourceExtension);
|
||||
expectedTargetFileBytes = readTargetFileBytes ? readTestFile(targetExtension) : null;
|
||||
sourceFile = new MockMultipartFile("file", "quick."+sourceExtension, sourceMimetype, expectedSourceFileBytes);
|
||||
protected abstract AbstractTransformerController getController();
|
||||
|
||||
controller.setTransformCommand(mockTransformCommand);
|
||||
controller.setCheckCommand(mockCheckCommand);
|
||||
|
||||
when(mockTransformCommand.execute(anyObject(), anyLong())).thenAnswer(new Answer<RuntimeExec.ExecutionResult>()
|
||||
{
|
||||
public RuntimeExec.ExecutionResult answer(InvocationOnMock invocation) throws Throwable
|
||||
{
|
||||
Map<String, String> actualProperties = invocation.getArgument(0);
|
||||
assertEquals("There should be 3 properties", 3, actualProperties.size());
|
||||
|
||||
String actualOptions = actualProperties.get("options");
|
||||
String actualSource = actualProperties.get("source");
|
||||
String actualTarget = actualProperties.get("target");
|
||||
String actualTargetExtension = StringUtils.getFilenameExtension(actualTarget);
|
||||
|
||||
assertNotNull(actualSource);
|
||||
assertNotNull(actualTarget);
|
||||
if (expectedSourceSuffix != null)
|
||||
{
|
||||
assertTrue("The source file \""+actualSource+"\" should have ended in \""+expectedSourceSuffix+"\"", actualSource.endsWith(expectedSourceSuffix));
|
||||
actualSource = actualSource.substring(0, actualSource.length()-expectedSourceSuffix.length());
|
||||
}
|
||||
|
||||
assertNotNull(actualOptions);
|
||||
if (expectedOptions != null)
|
||||
{
|
||||
assertEquals("expectedOptions", expectedOptions, actualOptions);
|
||||
}
|
||||
|
||||
Long actualTimeout = invocation.getArgument(1);
|
||||
assertNotNull(actualTimeout);
|
||||
if (expectedTimeout != null)
|
||||
{
|
||||
assertEquals("expectedTimeout", expectedTimeout, actualTimeout);
|
||||
}
|
||||
|
||||
// Copy a test file into the target file location if it exists
|
||||
int i = actualTarget.lastIndexOf('_');
|
||||
if (i >= 0)
|
||||
{
|
||||
String testFilename = actualTarget.substring(i+1);
|
||||
File testFile = getTestFile(testFilename, false);
|
||||
File targetFile = new File(actualTarget);
|
||||
generateTargetFileFromResourceFile(actualTargetExtension, testFile,
|
||||
targetFile);
|
||||
}
|
||||
|
||||
// Check the supplied source file has not been changed.
|
||||
byte[] actualSourceFileBytes = Files.readAllBytes(new File(actualSource).toPath());
|
||||
assertTrue("Source file is not the same", Arrays.equals(expectedSourceFileBytes, actualSourceFileBytes));
|
||||
|
||||
return mockExecutionResult;
|
||||
}
|
||||
});
|
||||
|
||||
when(mockExecutionResult.getExitValue()).thenReturn(0);
|
||||
when(mockExecutionResult.getStdErr()).thenReturn("STDERROR");
|
||||
when(mockExecutionResult.getStdOut()).thenReturn("STDOUT");
|
||||
}
|
||||
protected abstract void updateTransformRequestWithSpecificOptions(TransformRequest transformRequest);
|
||||
|
||||
/**
|
||||
* This method ends up being the core of the mock.
|
||||
@@ -197,8 +97,8 @@ public abstract class AbstractTransformerControllerTest
|
||||
* in order to simulate a successful transformation.
|
||||
*
|
||||
* @param actualTargetExtension Requested extension.
|
||||
* @param testFile The test file (transformed) - basically the result.
|
||||
* @param targetFile The location where the content from the testFile should be copied
|
||||
* @param testFile The test file (transformed) - basically the result.
|
||||
* @param targetFile The location where the content from the testFile should be copied
|
||||
* @throws IOException in case of any errors.
|
||||
*/
|
||||
void generateTargetFileFromResourceFile(String actualTargetExtension, File testFile,
|
||||
@@ -224,7 +124,7 @@ public abstract class AbstractTransformerControllerTest
|
||||
|
||||
protected byte[] readTestFile(String extension) throws IOException
|
||||
{
|
||||
return Files.readAllBytes(getTestFile("quick."+extension, true).toPath());
|
||||
return Files.readAllBytes(getTestFile("quick." + extension, true).toPath());
|
||||
}
|
||||
|
||||
protected File getTestFile(String testFilename, boolean required) throws IOException
|
||||
@@ -233,22 +133,22 @@ public abstract class AbstractTransformerControllerTest
|
||||
URL testFileUrl = classLoader.getResource(testFilename);
|
||||
if (required && testFileUrl == null)
|
||||
{
|
||||
throw new IOException("The test file "+testFilename+" does not exist in the resources directory");
|
||||
throw new IOException("The test file " + testFilename + " does not exist in the resources directory");
|
||||
}
|
||||
return testFileUrl == null ? null : new File(testFileUrl.getFile());
|
||||
}
|
||||
|
||||
protected MockHttpServletRequestBuilder mockMvcRequest(String url, MockMultipartFile sourceFile, String... params)
|
||||
{
|
||||
MockHttpServletRequestBuilder builder = MockMvcRequestBuilders.fileUpload("/transform").file(sourceFile);
|
||||
MockHttpServletRequestBuilder builder = MockMvcRequestBuilders.multipart("/transform").file(sourceFile);
|
||||
|
||||
if (params.length % 2 != 0)
|
||||
{
|
||||
throw new IllegalArgumentException("each param should have a name and value.");
|
||||
}
|
||||
for (int i=0; i<params.length; i+=2)
|
||||
for (int i = 0; i < params.length; i += 2)
|
||||
{
|
||||
builder = builder.param(params[i], params[i+1]);
|
||||
builder = builder.param(params[i], params[i + 1]);
|
||||
}
|
||||
|
||||
return builder;
|
||||
@@ -258,9 +158,9 @@ public abstract class AbstractTransformerControllerTest
|
||||
public void simpleTransformTest() throws Exception
|
||||
{
|
||||
mockMvc.perform(mockMvcRequest("/transform", sourceFile, "targetExtension", targetExtension))
|
||||
.andExpect(status().is(200))
|
||||
.andExpect(content().bytes(expectedTargetFileBytes))
|
||||
.andExpect(header().string("Content-Disposition", "attachment; filename*= UTF-8''quick."+targetExtension));
|
||||
.andExpect(status().is(200))
|
||||
.andExpect(content().bytes(expectedTargetFileBytes))
|
||||
.andExpect(header().string("Content-Disposition", "attachment; filename*= UTF-8''quick." + targetExtension));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -268,42 +168,32 @@ public abstract class AbstractTransformerControllerTest
|
||||
{
|
||||
long start = System.currentTimeMillis();
|
||||
mockMvc.perform(mockMvcRequest("/transform", sourceFile, "targetExtension", targetExtension, "testDelay", "400"))
|
||||
.andExpect(status().is(200))
|
||||
.andExpect(content().bytes(expectedTargetFileBytes))
|
||||
.andExpect(header().string("Content-Disposition", "attachment; filename*= UTF-8''quick."+targetExtension));
|
||||
long ms = System.currentTimeMillis()- start;
|
||||
System.out.println("Transform incluing test delay was "+ms);
|
||||
assertTrue("Delay sending the result back was too small "+ms, ms >= 400);
|
||||
assertTrue("Delay sending the result back was too big "+ms, ms <= 500);
|
||||
.andExpect(status().is(200))
|
||||
.andExpect(content().bytes(expectedTargetFileBytes))
|
||||
.andExpect(header().string("Content-Disposition", "attachment; filename*= UTF-8''quick." + targetExtension));
|
||||
long ms = System.currentTimeMillis() - start;
|
||||
System.out.println("Transform incluing test delay was " + ms);
|
||||
assertTrue("Delay sending the result back was too small " + ms, ms >= 400);
|
||||
assertTrue("Delay sending the result back was too big " + ms, ms <= 500);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noTargetFileTest() throws Exception
|
||||
{
|
||||
mockMvc.perform(mockMvcRequest("/transform", sourceFile, "targetExtension", "xxx"))
|
||||
.andExpect(status().is(500));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void badExitCodeTest() throws Exception
|
||||
{
|
||||
when(mockExecutionResult.getExitValue()).thenReturn(1);
|
||||
|
||||
mockMvc.perform(mockMvcRequest("/transform", sourceFile, "targetExtension", "xxx"))
|
||||
.andExpect(status().is(400))
|
||||
.andExpect(status().reason(containsString("Transformer exit code was not 0: \nSTDERR")));
|
||||
.andExpect(status().is(500));
|
||||
}
|
||||
|
||||
@Test
|
||||
// Looks dangerous but is okay as we only use the final filename
|
||||
public void dotDotSourceFilenameTest() throws Exception
|
||||
{
|
||||
sourceFile = new MockMultipartFile("file", "../quick."+sourceExtension, sourceMimetype, expectedSourceFileBytes);
|
||||
sourceFile = new MockMultipartFile("file", "../quick." + sourceExtension, sourceMimetype, expectedSourceFileBytes);
|
||||
|
||||
mockMvc.perform(mockMvcRequest("/transform", sourceFile, "targetExtension", targetExtension))
|
||||
.andExpect(status().is(200))
|
||||
.andExpect(content().bytes(expectedTargetFileBytes))
|
||||
.andExpect(header().string("Content-Disposition", "attachment; filename*= UTF-8''quick."+targetExtension));
|
||||
.andExpect(status().is(200))
|
||||
.andExpect(content().bytes(expectedTargetFileBytes))
|
||||
.andExpect(header().string("Content-Disposition", "attachment; filename*= UTF-8''quick." + targetExtension));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -313,9 +203,9 @@ public abstract class AbstractTransformerControllerTest
|
||||
sourceFile = new MockMultipartFile("file", "../quick", sourceMimetype, expectedSourceFileBytes);
|
||||
|
||||
mockMvc.perform(mockMvcRequest("/transform", sourceFile, "targetExtension", targetExtension))
|
||||
.andExpect(status().is(200))
|
||||
.andExpect(content().bytes(expectedTargetFileBytes))
|
||||
.andExpect(header().string("Content-Disposition", "attachment; filename*= UTF-8''quick."+targetExtension));
|
||||
.andExpect(status().is(200))
|
||||
.andExpect(content().bytes(expectedTargetFileBytes))
|
||||
.andExpect(header().string("Content-Disposition", "attachment; filename*= UTF-8''quick." + targetExtension));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -325,8 +215,8 @@ public abstract class AbstractTransformerControllerTest
|
||||
sourceFile = new MockMultipartFile("file", "abc/", sourceMimetype, expectedSourceFileBytes);
|
||||
|
||||
mockMvc.perform(mockMvcRequest("/transform", sourceFile, "targetExtension", targetExtension))
|
||||
.andExpect(status().is(400))
|
||||
.andExpect(status().reason(containsString("The source filename was not supplied")));
|
||||
.andExpect(status().is(400))
|
||||
.andExpect(status().reason(containsString("The source filename was not supplied")));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -335,113 +225,47 @@ public abstract class AbstractTransformerControllerTest
|
||||
sourceFile = new MockMultipartFile("file", "", sourceMimetype, expectedSourceFileBytes);
|
||||
|
||||
mockMvc.perform(mockMvcRequest("/transform", sourceFile, "targetExtension", targetExtension))
|
||||
.andExpect(status().is(400))
|
||||
.andExpect(status().reason(containsString("The source filename was not supplied")));
|
||||
.andExpect(status().is(400))
|
||||
.andExpect(status().reason(containsString("The source filename was not supplied")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noTargetExtensionTest() throws Exception
|
||||
{
|
||||
mockMvc.perform(mockMvcRequest("/transform", sourceFile))
|
||||
.andExpect(status().is(400))
|
||||
.andExpect(status().reason(containsString("Request parameter targetExtension is missing")));
|
||||
.andExpect(status().is(400))
|
||||
.andExpect(status().reason(containsString("Request parameter targetExtension is missing")));
|
||||
}
|
||||
|
||||
// @Test
|
||||
// // Not a real test, but helpful for trying out the duration times in log code.
|
||||
// public void testTimes() throws InterruptedException
|
||||
// {
|
||||
// LogEntry.start();
|
||||
// Thread.sleep(50);
|
||||
// LogEntry.setSource("test File", 1234);
|
||||
// Thread.sleep(200);
|
||||
// LogEntry.setStatusCodeAndMessage(200, "Success");
|
||||
// LogEntry.addDelay(2000L);
|
||||
// for (LogEntry logEntry: LogEntry.getLog())
|
||||
// {
|
||||
// String str = logEntry.getDuration();
|
||||
// System.out.println(str);
|
||||
// }
|
||||
// }
|
||||
|
||||
@Test
|
||||
public void calculateMaxTime() throws Exception
|
||||
{
|
||||
ProbeTestTransform probeTestTransform = controller.getProbeTestTransform();
|
||||
probeTestTransform.livenessPercent = 110;
|
||||
ProbeTestTransform probeTestTransform = getController().getProbeTestTransform();
|
||||
probeTestTransform.setLivenessPercent(110);
|
||||
|
||||
long [][] values = new long[][] {
|
||||
{5000, 0, Long.MAX_VALUE}, // 1st transform is ignored
|
||||
{1000, 1000, 2100}, // 1000 + 1000*1.1
|
||||
{3000, 2000, 4200}, // 2000 + 2000*1.1
|
||||
{2000, 2000, 4200},
|
||||
{6000, 3000, 6300},
|
||||
{8000, 4000, 8400},
|
||||
{4444, 4000, 8400}, // no longer in the first few, so normal and max times don't change
|
||||
{5555, 4000, 8400}
|
||||
long[][] values = new long[][]{
|
||||
{5000, 0, Long.MAX_VALUE}, // 1st transform is ignored
|
||||
{1000, 1000, 2100}, // 1000 + 1000*1.1
|
||||
{3000, 2000, 4200}, // 2000 + 2000*1.1
|
||||
{2000, 2000, 4200},
|
||||
{6000, 3000, 6300},
|
||||
{8000, 4000, 8400},
|
||||
{4444, 4000, 8400}, // no longer in the first few, so normal and max times don't change
|
||||
{5555, 4000, 8400}
|
||||
};
|
||||
|
||||
for (long[] v: values)
|
||||
for (long[] v : values)
|
||||
{
|
||||
long time = v[0];
|
||||
long expectedNormalTime = v[1];
|
||||
long expectedMaxTime = v[2];
|
||||
|
||||
probeTestTransform.calculateMaxTime(time, true);
|
||||
assertEquals("", expectedNormalTime, probeTestTransform.normalTime);
|
||||
assertEquals("", expectedMaxTime, probeTestTransform.maxTime);
|
||||
assertEquals("", expectedNormalTime, probeTestTransform.getNormalTime());
|
||||
assertEquals("", expectedMaxTime, probeTestTransform.getMaxTime());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPojoTransform() throws Exception
|
||||
{
|
||||
// Files
|
||||
String sourceFileRef = UUID.randomUUID().toString();
|
||||
File sourceFile = getTestFile("quick." + sourceExtension, true);
|
||||
String targetFileRef = UUID.randomUUID().toString();
|
||||
|
||||
|
||||
// Transformation Request POJO
|
||||
TransformRequest transformRequest = new TransformRequest();
|
||||
transformRequest.setRequestId("1");
|
||||
transformRequest.setSchema(1);
|
||||
transformRequest.setClientData("Alfresco Digital Business Platform");
|
||||
transformRequest.setTransformRequestOptions(new HashMap<>());
|
||||
transformRequest.setSourceReference(sourceFileRef);
|
||||
transformRequest.setSourceExtension(sourceExtension);
|
||||
transformRequest.setSourceSize(sourceFile.length());
|
||||
transformRequest.setTargetExtension(targetExtension);
|
||||
|
||||
// HTTP Request
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.set(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=quick." + sourceExtension);
|
||||
ResponseEntity<Resource> response = new ResponseEntity<>(new FileSystemResource(
|
||||
sourceFile), headers, HttpStatus.OK);
|
||||
|
||||
when(alfrescoSharedFileStoreClient.retrieveFile(sourceFileRef)).thenReturn(response);
|
||||
when(alfrescoSharedFileStoreClient.saveFile(any())).thenReturn(new FileRefResponse(new FileRefEntity(targetFileRef)));
|
||||
when(mockExecutionResult.getExitValue()).thenReturn(0);
|
||||
|
||||
// Update the Transformation Request with any specific params before sending it
|
||||
updateTransformRequestWithSpecificOptions(transformRequest);
|
||||
|
||||
// Serialize and call the transformer
|
||||
String tr = objectMapper.writeValueAsString(transformRequest);
|
||||
String transformationReplyAsString = mockMvc.perform(MockMvcRequestBuilders.post("/transform")
|
||||
.header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)
|
||||
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE).content(tr))
|
||||
.andExpect(status().is(HttpStatus.CREATED.value()))
|
||||
.andReturn().getResponse().getContentAsString();
|
||||
|
||||
TransformReply transformReply = objectMapper.readValue(transformationReplyAsString, TransformReply.class);
|
||||
|
||||
// Assert the reply
|
||||
assertEquals(transformRequest.getRequestId(), transformReply.getRequestId());
|
||||
assertEquals(transformRequest.getClientData(), transformReply.getClientData());
|
||||
assertEquals(transformRequest.getSchema(), transformReply.getSchema());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmptyPojoTransform() throws Exception
|
||||
{
|
||||
@@ -450,9 +274,12 @@ public abstract class AbstractTransformerControllerTest
|
||||
|
||||
// Serialize and call the transformer
|
||||
String tr = objectMapper.writeValueAsString(transformRequest);
|
||||
String transformationReplyAsString = mockMvc.perform(MockMvcRequestBuilders.post("/transform")
|
||||
.header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)
|
||||
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE).content(tr))
|
||||
String transformationReplyAsString = mockMvc
|
||||
.perform(MockMvcRequestBuilders
|
||||
.post("/transform")
|
||||
.header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)
|
||||
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
|
||||
.content(tr))
|
||||
.andExpect(status().is(HttpStatus.BAD_REQUEST.value()))
|
||||
.andReturn().getResponse().getContentAsString();
|
||||
|
||||
@@ -461,6 +288,4 @@ public abstract class AbstractTransformerControllerTest
|
||||
// Assert the reply
|
||||
assertEquals(HttpStatus.BAD_REQUEST.value(), transformReply.getStatus());
|
||||
}
|
||||
|
||||
protected abstract void updateTransformRequestWithSpecificOptions(TransformRequest transformRequest);
|
||||
}
|
||||
|
Reference in New Issue
Block a user