mirror of
https://github.com/Alfresco/alfresco-transform-core.git
synced 2025-08-07 17:48:35 +00:00
feature/ATS-16
This commit is contained in:
@@ -111,6 +111,65 @@ public class AlfrescoPdfRendererController extends AbstractTransformerController
|
||||
}
|
||||
~~~
|
||||
|
||||
* *TransformerName*Controller#processTransform(File sourceFile, File targetFile, Map<String, String> transformOptions, Long timeout)
|
||||
|
||||
### /transform (Consumes: `application/json`, Produces: `application/json`)
|
||||
The new *consumes* and *produces* arguments have been specified in order to differentiate this endpoint from the previous one (which **consumes** `multipart/form-data`)
|
||||
|
||||
The endpoint should **always** receive a `TransformationRequest` and should **always** respond with a `TransformationReply`.
|
||||
|
||||
As specific transformers require specific arguments (e.g. `transform` for the **Tika transformer**) the request body should include this in the `transformRequestOptions` via the `Map<String,String> transformRequestOptions`.
|
||||
|
||||
**Example request body**
|
||||
```javascript
|
||||
var transformRequest = {
|
||||
"requestId": "1",
|
||||
"sourceReference": "2f9ed237-c734-4366-8c8b-6001819169a4",
|
||||
"sourceMediaType": "pdf",
|
||||
"sourceSize": 123456,
|
||||
"sourceExtension": "pdf",
|
||||
"targetMediaType": "txt",
|
||||
"targetExtension": "txt",
|
||||
"clientType": "ACS",
|
||||
"clientData": "Yo No Soy Marinero, Soy Capitan, Soy Capitan!",
|
||||
"schema": 1,
|
||||
"transformRequestOptions": {
|
||||
"targetMimetype": "text/plain",
|
||||
"targetEncoding": "UTF-8",
|
||||
"transform": "PdfBox"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Example response body**
|
||||
|
||||
```javascript
|
||||
var transformReply = {
|
||||
"requestId": "1",
|
||||
"status": 201,
|
||||
"errorDetails": null,
|
||||
"sourceReference": "2f9ed237-c734-4366-8c8b-6001819169a4",
|
||||
"targetReference": "34d69ff0-7eaa-4741-8a9f-e1915e6995bf",
|
||||
"clientType": "ACS",
|
||||
"clientData": "Yo No Soy Marinero, Soy Capitan, Soy Capitan!",
|
||||
"schema": 1
|
||||
}
|
||||
```
|
||||
|
||||
### processTransform method
|
||||
```java
|
||||
public abstract class AbstractTransformerController
|
||||
{
|
||||
void processTransform(File sourceFile, File targetFile, Map<String, String> transformOptions, Long timeout) { /* Perform the transformation*/ }
|
||||
}
|
||||
```
|
||||
|
||||
The **abstract** method is declared in the *AbstractTransformerController* and must be implemented by the specific controllers.
|
||||
|
||||
This method is called by the *AbstractTransformerController* directly in the **new** `/transform` endpoint which **consumes** `application/json` and **produces** `application/json`.
|
||||
|
||||
The method is responsible for performing the transformation. Upon a **successful** transformation it updates the `targetFile` parameter.
|
||||
|
||||
* Application.java - [Spring Boot](https://projects.spring.io/spring-boot/) expects to find an Application in
|
||||
a project's source files. The following may be used:
|
||||
|
||||
|
@@ -26,6 +26,10 @@
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-transform-data-model</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
@@ -25,34 +25,52 @@
|
||||
*/
|
||||
package org.alfresco.transformer;
|
||||
|
||||
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 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.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.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.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;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* <p>Abstract Controller, provides structure and helper methods to sub-class transformer controllers.</p>
|
||||
*
|
||||
@@ -85,6 +103,10 @@ public abstract class AbstractTransformerController
|
||||
{
|
||||
public static final String SOURCE_FILE = "sourceFile";
|
||||
public static final String TARGET_FILE = "targetFile";
|
||||
public static final String FILENAME = "filename=";
|
||||
|
||||
@Autowired
|
||||
private AlfrescoSharedFileStoreClient alfrescoSharedFileStoreClient;
|
||||
|
||||
protected static Log logger;
|
||||
|
||||
@@ -115,6 +137,125 @@ public abstract class AbstractTransformerController
|
||||
|
||||
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 timeout Transformation timeout
|
||||
* @return A transformation reply
|
||||
*/
|
||||
@PostMapping(value = "/transform", produces = APPLICATION_JSON_VALUE)
|
||||
@ResponseBody
|
||||
public ResponseEntity<TransformReply> transform(@RequestBody TransformRequest transformRequest,
|
||||
@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());
|
||||
|
||||
// Load the source file
|
||||
File sourceFile;
|
||||
try
|
||||
{
|
||||
sourceFile = loadSourceFile(transformRequest.getSourceReference());
|
||||
}
|
||||
catch (TransformException te)
|
||||
{
|
||||
transformReply.setStatus(te.getStatusCode());
|
||||
transformReply
|
||||
.setErrorDetails("Failed at reading the source file. " + te.getMessage());
|
||||
|
||||
return new ResponseEntity<>(transformReply, HttpStatus.valueOf(transformReply.getStatus()));
|
||||
}
|
||||
catch (HttpClientErrorException hcee)
|
||||
{
|
||||
transformReply.setStatus(hcee.getStatusCode().value());
|
||||
transformReply
|
||||
.setErrorDetails("Failed at reading the source file. " + hcee.getMessage());
|
||||
|
||||
return new ResponseEntity<>(transformReply, HttpStatus.valueOf(transformReply.getStatus()));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
transformReply.setStatus(500);
|
||||
transformReply.setErrorDetails("Failed at reading the source file. " + e.getMessage());
|
||||
|
||||
return new ResponseEntity<>(transformReply, HttpStatus.valueOf(transformReply.getStatus()));
|
||||
}
|
||||
|
||||
// Create local temp target file in order to run the transformation
|
||||
String targetFilename = createTargetFileName(sourceFile.getName(),
|
||||
transformRequest.getTargetExtension());
|
||||
File targetFile = buildFile(targetFilename);
|
||||
|
||||
// Run the transformation
|
||||
try
|
||||
{
|
||||
processTransform(sourceFile, targetFile,
|
||||
transformRequest.getTransformationRequestOptions(), timeout);
|
||||
}
|
||||
catch (TransformException te)
|
||||
{
|
||||
transformReply.setStatus(te.getStatusCode());
|
||||
transformReply
|
||||
.setErrorDetails("Failed at processing transformation. " + te.getMessage());
|
||||
|
||||
return new ResponseEntity<>(transformReply, HttpStatus.valueOf(transformReply.getStatus()));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
transformReply.setStatus(500);
|
||||
transformReply
|
||||
.setErrorDetails("Failed at processing transformation. " + e.getMessage());
|
||||
|
||||
return new ResponseEntity<>(transformReply, HttpStatus.valueOf(transformReply.getStatus()));
|
||||
}
|
||||
|
||||
// Write the target file
|
||||
FileRefResponse targetRef;
|
||||
try
|
||||
{
|
||||
targetRef = alfrescoSharedFileStoreClient.saveFile(targetFile);
|
||||
}
|
||||
catch (TransformException te)
|
||||
{
|
||||
transformReply.setStatus(te.getStatusCode());
|
||||
transformReply
|
||||
.setErrorDetails("Failed at writing the transformed file. " + te.getMessage());
|
||||
|
||||
return new ResponseEntity<>(transformReply, HttpStatus.valueOf(transformReply.getStatus()));
|
||||
}
|
||||
catch (HttpClientErrorException hcee)
|
||||
{
|
||||
transformReply.setStatus(hcee.getStatusCode().value());
|
||||
transformReply
|
||||
.setErrorDetails("Failed at writing the transformed file. " + hcee.getMessage());
|
||||
|
||||
return new ResponseEntity<>(transformReply, HttpStatus.valueOf(transformReply.getStatus()));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
transformReply.setStatus(500);
|
||||
transformReply
|
||||
.setErrorDetails("Failed at writing the transformed file. " + e.getMessage());
|
||||
|
||||
return new ResponseEntity<>(transformReply, HttpStatus.valueOf(transformReply.getStatus()));
|
||||
}
|
||||
|
||||
transformReply.setTargetReference(targetRef.getEntry().getFileRef());
|
||||
transformReply.setStatus(HttpStatus.CREATED.value());
|
||||
|
||||
return new ResponseEntity<>(transformReply, HttpStatus.valueOf(transformReply.getStatus()));
|
||||
}
|
||||
|
||||
protected abstract void processTransform(File sourceFile, File targetFile,
|
||||
Map<String, String> transformOptions, Long timeout);
|
||||
|
||||
@RequestMapping("/version")
|
||||
@ResponseBody
|
||||
protected String version()
|
||||
@@ -269,10 +410,71 @@ public abstract class AbstractTransformerController
|
||||
// return errorAttributes;
|
||||
// }
|
||||
|
||||
protected String createTargetFileName(MultipartFile sourceMultipartFile, String targetExtension)
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
|
||||
ResponseEntity<Resource> responseEntity = alfrescoSharedFileStoreClient
|
||||
.retrieveFile(sourceReference);
|
||||
getProbeTestTransformInternal().incrementTransformerCount();
|
||||
|
||||
HttpHeaders headers = responseEntity.getHeaders();
|
||||
String filename = getFilenameFromContentDisposition(headers);
|
||||
|
||||
String extension = StringUtils.getFilenameExtension(filename);
|
||||
MediaType contentType = headers.getContentType();
|
||||
long size = headers.getContentLength();
|
||||
|
||||
Resource body = responseEntity.getBody();
|
||||
File file = TempFileProvider.createTempFile("source_", "." + extension);
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug(
|
||||
"Read source content " + sourceReference + " length="
|
||||
+ size + " contentType=" + contentType);
|
||||
}
|
||||
save(body, file);
|
||||
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 = sourceMultipartFile.getOriginalFilename();
|
||||
String sourceFilename = fileName;
|
||||
sourceFilename = StringUtils.getFilename(sourceFilename);
|
||||
if (sourceFilename != null && !sourceFilename.isEmpty())
|
||||
{
|
||||
@@ -317,13 +519,18 @@ public abstract class AbstractTransformerController
|
||||
*/
|
||||
protected File createTargetFile(HttpServletRequest request, String filename)
|
||||
{
|
||||
filename = checkFilename( false, filename);
|
||||
LogEntry.setTarget(filename);
|
||||
File file = TempFileProvider.createTempFile("target_", "_" + 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.
|
||||
*
|
||||
@@ -355,6 +562,20 @@ public abstract class AbstractTransformerController
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
@@ -491,4 +712,37 @@ public abstract class AbstractTransformerController
|
||||
throw new TransformException(500, "Filename encoding error", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright 2005-2018 Alfresco Software, Ltd. All rights reserved.
|
||||
*
|
||||
* License rights for this program may be obtained from Alfresco Software, Ltd.
|
||||
* pursuant to a written agreement and any use of this program without such an
|
||||
* agreement is prohibited.
|
||||
*/
|
||||
package org.alfresco.transformer;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.alfresco.transformer.model.FileRefResponse;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.core.io.FileSystemResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.web.client.HttpClientErrorException;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
/**
|
||||
* Simple Rest client that call Alfresco Shared File Store
|
||||
*/
|
||||
public class AlfrescoSharedFileStoreClient
|
||||
{
|
||||
@Value("${fileStoreUrl}")
|
||||
private String fileStoreUrl;
|
||||
|
||||
@Autowired
|
||||
private RestTemplate restTemplate;
|
||||
|
||||
/**
|
||||
* Retrieves a file from Shared File Store using given file reference
|
||||
*
|
||||
* @param fileRef File reference
|
||||
* @return ResponseEntity<Resource>
|
||||
*/
|
||||
public ResponseEntity<Resource> retrieveFile(String fileRef)
|
||||
{
|
||||
try
|
||||
{
|
||||
return restTemplate.getForEntity(fileStoreUrl + "/" + fileRef,
|
||||
org.springframework.core.io.Resource.class);
|
||||
}
|
||||
catch (HttpClientErrorException e)
|
||||
{
|
||||
throw new TransformException(e.getStatusCode().value(), e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores given file in Shared File Store
|
||||
*
|
||||
* @param file File to be stored
|
||||
* @return A FileRefResponse containing detail about file's reference
|
||||
*/
|
||||
public FileRefResponse saveFile(File file)
|
||||
{
|
||||
try
|
||||
{
|
||||
FileSystemResource value = new FileSystemResource(file.getAbsolutePath());
|
||||
LinkedMultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
|
||||
map.add("file", value);
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
|
||||
HttpEntity<LinkedMultiValueMap<String, Object>> requestEntity = new HttpEntity<>(map,
|
||||
headers);
|
||||
ResponseEntity<FileRefResponse> responseEntity = restTemplate
|
||||
.exchange(fileStoreUrl, HttpMethod.POST, requestEntity, FileRefResponse.class);
|
||||
return responseEntity.getBody();
|
||||
}
|
||||
catch (HttpClientErrorException e)
|
||||
{
|
||||
throw new TransformException(e.getStatusCode().value(), e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
@@ -35,4 +35,5 @@ public class Application
|
||||
{
|
||||
SpringApplication.run(Application.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -27,6 +27,7 @@ package org.alfresco.transformer;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
|
||||
|
||||
@@ -42,4 +43,16 @@ public class WebApplicationConfig extends WebMvcConfigurerAdapter {
|
||||
public TransformInterceptor transformInterceptor() {
|
||||
return new TransformInterceptor();
|
||||
}
|
||||
|
||||
|
||||
@Bean
|
||||
public RestTemplate restTemplate()
|
||||
{
|
||||
return new RestTemplate();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public AlfrescoSharedFileStoreClient alfrescoSharedFileStoreClient(){
|
||||
return new AlfrescoSharedFileStoreClient();
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,57 @@
|
||||
package org.alfresco.transformer.model;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* TODO: Copied from org.alfresco.store.entity (alfresco-shared-file-store). To be discussed
|
||||
*
|
||||
* POJO that represents content reference ({@link java.util.UUID})
|
||||
*/
|
||||
public class FileRefEntity
|
||||
{
|
||||
private String fileRef;
|
||||
|
||||
public FileRefEntity()
|
||||
{
|
||||
}
|
||||
|
||||
public FileRefEntity(String fileRef)
|
||||
{
|
||||
this.fileRef = fileRef;
|
||||
}
|
||||
|
||||
public void setFileRef(String fileRef){
|
||||
this.fileRef = fileRef;
|
||||
}
|
||||
public String getFileRef()
|
||||
{
|
||||
return fileRef;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return fileRef;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
if (this == o)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
FileRefEntity fileRef = (FileRefEntity) o;
|
||||
return Objects.equals(this.fileRef, fileRef.fileRef);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return Objects.hash(fileRef);
|
||||
}
|
||||
}
|
@@ -0,0 +1,30 @@
|
||||
package org.alfresco.transformer.model;
|
||||
|
||||
/**
|
||||
* TODO: Copied from org.alfresco.store.entity (alfresco-shared-file-store). To be discussed
|
||||
*
|
||||
* POJO that describes the ContentRefEntry response, contains {@link FileRefEntity} according to API spec
|
||||
*/
|
||||
public class FileRefResponse
|
||||
{
|
||||
private FileRefEntity entry;
|
||||
|
||||
public FileRefResponse()
|
||||
{
|
||||
}
|
||||
|
||||
public FileRefResponse(FileRefEntity entry)
|
||||
{
|
||||
this.entry = entry;
|
||||
}
|
||||
|
||||
public FileRefEntity getEntry()
|
||||
{
|
||||
return entry;
|
||||
}
|
||||
|
||||
public void setEntry(FileRefEntity entry)
|
||||
{
|
||||
this.entry = entry;
|
||||
}
|
||||
}
|
@@ -1,10 +0,0 @@
|
||||
spring.http.multipart.max-file-size=8192MB
|
||||
spring.http.multipart.max-request-size=8192MB
|
||||
server.port = 8090
|
||||
|
||||
#logging.level.org.alfresco.util.exec.RuntimeExec=debug
|
||||
logging.level.org.alfresco.transformer.LibreOfficeController=debug
|
||||
logging.level.org.alfresco.transformer.JodConverterSharedInstance=debug
|
||||
logging.level.org.alfresco.transformer.AlfrescoPdfRendererController=debug
|
||||
logging.level.org.alfresco.transformer.ImageMagickController=debug
|
||||
logging.level.org.alfresco.transformer.TikaController=debug
|
@@ -0,0 +1,19 @@
|
||||
spring:
|
||||
http:
|
||||
multipart:
|
||||
max-file-size: 8192MB
|
||||
max-request-size: 8192MB
|
||||
|
||||
server:
|
||||
port: 8090
|
||||
|
||||
logging:
|
||||
level:
|
||||
#org.alfresco.util.exec.RuntimeExec: debug
|
||||
org.alfresco.transformer.LibreOfficeController: debug
|
||||
org.alfresco.transformer.JodConverterSharedInstance: debug
|
||||
org.alfresco.transformer.AlfrescoPdfRendererController: debug
|
||||
org.alfresco.transformer.ImageMagickController: debug
|
||||
org.alfresco.transformer.TikaController: debug
|
||||
|
||||
fileStoreUrl: ${FILE_STORE_URL:http://localhost:8099/alfresco/api/-default-/private/sfs/versions/1/file}
|
@@ -25,30 +25,54 @@
|
||||
*/
|
||||
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;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
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.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.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 java.io.*;
|
||||
import java.net.URL;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.file.Files;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.junit.Assert.*;
|
||||
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.*;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
/**
|
||||
* Super class for testing controllers without a server. Includes tests for the AbstractTransformerController itself.
|
||||
@@ -58,12 +82,18 @@ public abstract class AbstractTransformerControllerTest
|
||||
@Autowired
|
||||
protected MockMvc mockMvc;
|
||||
|
||||
@Autowired
|
||||
protected ObjectMapper objectMapper;
|
||||
|
||||
@Mock
|
||||
private RuntimeExec mockTransformCommand;
|
||||
|
||||
@Mock
|
||||
private RuntimeExec mockCheckCommand;
|
||||
|
||||
@Mock
|
||||
protected AlfrescoSharedFileStoreClient alfrescoSharedFileStoreClient;
|
||||
|
||||
@Mock
|
||||
private RuntimeExec.ExecutionResult mockExecutionResult;
|
||||
|
||||
@@ -80,6 +110,11 @@ public abstract class AbstractTransformerControllerTest
|
||||
|
||||
protected AbstractTransformerController controller;
|
||||
|
||||
@Before
|
||||
public void before() throws Exception
|
||||
{
|
||||
}
|
||||
|
||||
// Called by sub class
|
||||
public void mockTransformCommand(AbstractTransformerController controller, String sourceExtension,
|
||||
String targetExtension, String sourceMimetype,
|
||||
@@ -109,6 +144,7 @@ public abstract class AbstractTransformerControllerTest
|
||||
String actualOptions = actualProperties.get("options");
|
||||
String actualSource = actualProperties.get("source");
|
||||
String actualTarget = actualProperties.get("target");
|
||||
String actualTargetExtension = StringUtils.getFilenameExtension(actualTarget);
|
||||
|
||||
assertNotNull(actualSource);
|
||||
assertNotNull(actualTarget);
|
||||
@@ -137,13 +173,9 @@ public abstract class AbstractTransformerControllerTest
|
||||
{
|
||||
String testFilename = actualTarget.substring(i+1);
|
||||
File testFile = getTestFile(testFilename, false);
|
||||
if (testFile != null)
|
||||
{
|
||||
File targetFile = new File(actualTarget);
|
||||
FileChannel source = new FileInputStream(testFile).getChannel();
|
||||
FileChannel target = new FileOutputStream(targetFile).getChannel();
|
||||
target.transferFrom(source, 0, source.size());
|
||||
}
|
||||
File targetFile = new File(actualTarget);
|
||||
generateTargetFileFromResourceFile(actualTargetExtension, testFile,
|
||||
targetFile);
|
||||
}
|
||||
|
||||
// Check the supplied source file has not been changed.
|
||||
@@ -159,6 +191,37 @@ public abstract class AbstractTransformerControllerTest
|
||||
when(mockExecutionResult.getStdOut()).thenReturn("STDOUT");
|
||||
}
|
||||
|
||||
/**
|
||||
* This method ends up being the core of the mock.
|
||||
* It copies content from an existing file in the resources folder to the desired location
|
||||
* 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
|
||||
* @throws IOException in case of any errors.
|
||||
*/
|
||||
void generateTargetFileFromResourceFile(String actualTargetExtension, File testFile,
|
||||
File targetFile) throws IOException
|
||||
{
|
||||
if (testFile != null)
|
||||
{
|
||||
FileChannel source = new FileInputStream(testFile).getChannel();
|
||||
FileChannel target = new FileOutputStream(targetFile).getChannel();
|
||||
target.transferFrom(source, 0, source.size());
|
||||
}
|
||||
else
|
||||
{
|
||||
testFile = getTestFile("quick." + actualTargetExtension, false);
|
||||
if (testFile != null)
|
||||
{
|
||||
FileChannel source = new FileInputStream(testFile).getChannel();
|
||||
FileChannel target = new FileOutputStream(targetFile).getChannel();
|
||||
target.transferFrom(source, 0, source.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected byte[] readTestFile(String extension) throws IOException
|
||||
{
|
||||
return Files.readAllBytes(getTestFile("quick."+extension, true).toPath());
|
||||
@@ -329,4 +392,60 @@ public abstract class AbstractTransformerControllerTest
|
||||
assertEquals("", expectedMaxTime, probeTestTransform.maxTime);
|
||||
}
|
||||
}
|
||||
|
||||
@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.setTransformationRequestOptions(new HashMap<>());
|
||||
|
||||
transformRequest.setSourceReference(sourceFileRef);
|
||||
transformRequest.setSourceExtension(sourceExtension);
|
||||
// TODO: ATS-53
|
||||
transformRequest.setSourceMediaType("TODO");
|
||||
transformRequest.setSourceSize(sourceFile.length());
|
||||
|
||||
transformRequest.setTargetExtension(targetExtension);
|
||||
transformRequest.setTargetMediaType("TODO");
|
||||
|
||||
// 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());
|
||||
}
|
||||
|
||||
protected abstract void updateTransformRequestWithSpecificOptions(TransformRequest transformRequest);
|
||||
}
|
||||
|
Reference in New Issue
Block a user