alfresco-transform-core/alfresco-transformer-base
eknizat af77d429e7
ATS-675:Add All-In-One transformer (#200)
* ATS-695/ATS-675 Add aio boot project

- Added the bare bones of a spring boot project to be used by aio. Currently based loosely on transform-misc.

* ATS-674/ATS-695 Add forms for each transformer.

* ATS-675/ATS-695 add empty test to pass build during dev

* ATS-695 remove maven profile to fix build

* ATS-675 Define interface and the aio transformer

* Fix formatting and rename the module as per review comments

* ATS-675/ATS-695 Add ProbeTestTransformation

Currenly uses MiscController implementation.

* ATS-675/ATS-695 Add logger method,

This will be code repeated in the local transform method and the processTransform method

* ATS-675/ATS-695 Implement local transform method

Minimum implementation for transform method.

* ATS-675/ATS-695  Implement processTransform

* ATS-675/ATS-695 Rename project to alfresco-transform-core-aio-boot

Add alfresco-transform-core-aio dependencies

* ATS-675/ATS-695 Fix build

Update project location
Update imports and variable declarations in TODOs
Add error handling.
Formatting.

* ATS-693: Update transform-misc Dockerfile with newly reserved uid

* Revert "ATS-691: Combine the win/linux pathToFile logic"

This reverts commit 61fe4820

* ATS-693: Update transform-misc Dockerfile with newly reserved uid

* "ATS-693: Add Dockerfile to aio-boot module"

* ATS-675/ATS-695 Add resource required for ProbeTestTrasform

* ATS-675/ATS-695 Remove test resources, to be added in test implementation

* ATS-693: Fix path to jar resources

* ATS-675/ATS-703 Moved Options builder to non boot jar.

* ATS-675/ATS-703 Rename OptionsBuilder to PdfRendererOptionsBuilder

This is to avoid confilct with OptionsBuilders in other T-engines.

* ATS-675/ATS-695 Added PdfRendererApadpter.java

Added dependency to pom.xml
Required transformation of String to Long, method added to Util.java

* ATS-675/ ATS-704

Implemented LibreOfficeAdapter

* ATS-675 Parity with base aio naming convention

* ATS-675/ATS-705 Implemented ImageMagickAdapter

Moved and renamed OptionsBuilder. Moved to alfresco-transform-imagemagick, renamed ImageMagickOptionsBuilder.
Added dependencies to pom.xml

* ATS-693: Implement maven docker build

* Initial tests
* Add initial tests for config aggregation
* Update AbstractTransformerControllerTest to use the new engine config names

* Fix up controller

* Fix travis tests  (#205)

* Fix engine specific properties for engine config location
* Temporarily add engine configs to test resources for the boot modules.  Will need to fix this properly

* Resolve some review comments

* ATS-675 - Move static strings to util class

* Refactor classes for simpler design (#210)

* ATS-702 Fix error handling

(cherry picked from commit e30cb5fda6ba2ae09c91ef61e69cba4689bcc8d9)

* ATS-675 Rename test class (fixes typo)

* ATS-675: Add aio transformer to static scan
2020-04-08 17:40:34 +01:00
..
2019-05-22 11:49:35 +03:00

Common code for Docker based ACS transformers

This project contains code that is common between all the ACS transformers that run within their own Docker containers. It performs common actions such as logging, throttling requests and handling the streaming of content to and from the container. It also provides structure and hook points to allow specific transformers to simply check request parameter and perform the transformation using either files or a pair of InputStream and OutputStream.

A transformer project is expected to provide the following files:

src/main/resources/templates/transformForm.html
src/main/java/org/alfresco/transformer/<XXX>Controller.java
src/main/java/org/alfresco/transformer/Application.java
  • transformerForm.html - A simple test page using thymeleaf that gathers request parameters so they may be used to test the transformer.
<html xmlns:th="http://www.thymeleaf.org">
<body>
  <div>
    <h2>Test Transformation</h2>
    <form method="POST" enctype="multipart/form-data" action="/transform">
      <table>
        <tr><td><div style="text-align:right">file *</div></td><td><input type="file" name="file" /></td></tr>
        <tr><td><div style="text-align:right">targetFilename *</div></td><td><input type="text" name="targetFilename" value="" /></td></tr>
        <tr><td><div style="text-align:right">width</div></td><td><input type="text" name="width" value="" /></td></tr>
        <tr><td><div style="text-align:right">height</div></td><td><input type="text" name="height" value="" /></td></tr>
        <tr><td><div style="text-align:right">allowPdfEnlargement</div></td><td><input type="checkbox" name="allowPdfEnlargement" value="true" /></td></tr>
        <tr><td><div style="text-align:right">maintainPdfAspectRatio</div></td><td><input type="checkbox" name="maintainPdfAspectRatio" value="true" /></td></tr>
        <tr><td><div style="text-align:right">page</div></td><td><input type="text" name="page" value="" /></td></tr>
        <tr><td><div style="text-align:right">timeout</div></td><td><input type="text" name="timeout" value="" /></td></tr>
        <tr><td></td><td><input type="submit" value="Transform" /></td></tr>
	  </table>
	</form>
  </div>
  <div>
    <a href="/log">Log entries</a>
  </div>
</body>
</html>
  • TransformerNameController.java - A Spring Boot Controller that extends AbstractTransformerController to handel a POST request to "/transform".
...
@Controller
public class AlfrescoPdfRendererController extends AbstractTransformerController
{
    ...

    @PostMapping("/transform")
    public ResponseEntity<Resource> transform(HttpServletRequest request,
                                              @RequestParam("file") MultipartFile sourceMultipartFile,
                                              @RequestParam("targetFilename") String targetFilename,
                                              @RequestParam(value = "width", required = false) Integer width,
                                              @RequestParam(value = "height", required = false) Integer height,
                                              @RequestParam(value = "allowPdfEnlargement", required = false) Boolean allowPdfEnlargement,
                                              @RequestParam(value = "maintainPdfAspectRatio", required = false) Boolean maintainPdfAspectRatio,
                                              @RequestParam(value = "page", required = false) Integer page,
                                              @RequestParam(value = "timeout", required = false) Long timeout)
    {
        try
        {
            File sourceFile = createSourceFile(request, sourceMultipartFile);
            File targetFile = createTargetFile(request, targetFilename);
            // Both files are deleted by TransformInterceptor.afterCompletion

            StringJoiner args = new StringJoiner(" ");
            if (width != null)
            {
                args.add("--width=" + width);
            }
            if (height != null)
            {
                args.add("--height=" + height);
            }
            if (allowPdfEnlargement != null && allowPdfEnlargement)
            {
                args.add("--allow-enlargement");
            }
            if (maintainPdfAspectRatio != null && maintainPdfAspectRatio)
            {
                args.add("--maintain-aspect-ratio");
            }
            if (page != null)
            {
                args.add("--page=" + page);
            }
            String options = args.toString();
            LogEntry.setOptions(options);

            Map<String, String> properties = new HashMap<>();
            properties.put("options", options);
            properties.put("source", sourceFile.getAbsolutePath());
            properties.put("target", targetFile.getAbsolutePath());

            executeTransformCommand(properties, targetFile, timeout);

            return createAttachment(targetFilename, targetFile);
        }
        catch (UnsupportedEncodingException e)
        {
            throw new TransformException(500, "Filename encoding error", e);
        }
    }
}
  • TransformerNameController#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

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

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

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 expects to find an Application in a project's source files. The following may be used:
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);
    }
}

Building and testing

The project can be built by running the Maven command:

mvn clean install

Artifacts

The artifacts can be obtained by:

<dependency>
  <groupId>org.alfresco</groupId>
  <artifactId>alfresco-transformer-base</artifactId>
  <version>1.0</version>
</dependency>

and the Alfresco Maven repository:

<repository>
  <id>alfresco-maven-repo</id>
  <url>https://artifacts.alfresco.com/nexus/content/groups/public</url>
</repository>

The build plan is available in TravisCI.

Contributing guide

Please use this guide to make a contribution to the project.