mirror of
https://github.com/Alfresco/alfresco-transform-core.git
synced 2025-07-31 17:38:33 +00:00
ACS-2718 Streamline ATS t-model/t-core (#586)
* Merge alfresco-transform-model project into alfresco-transform-core - WITHOUT the git history * Simplify Maven dependencies and build project * Unify release process of combined t-model and t-core
This commit is contained in:
4
alfresco-transform-model/README.md
Normal file
4
alfresco-transform-model/README.md
Normal file
@@ -0,0 +1,4 @@
|
||||
# alfresco-transform-model
|
||||
Alfresco Transform Model - Contains the data model of json configuration files
|
||||
and messages sent between clients, T-Engines and T-Router. Also contains code to
|
||||
work out which transform should be used for a combination of configuration files.
|
152
alfresco-transform-model/pom.xml
Normal file
152
alfresco-transform-model/pom.xml
Normal file
@@ -0,0 +1,152 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<name>Alfresco Transform Model</name>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-transform-model</artifactId>
|
||||
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-transform-core</artifactId>
|
||||
<version>2.6.0-A2-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven</groupId>
|
||||
<artifactId>maven-artifact</artifactId>
|
||||
<version>3.8.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-annotations</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-junit-jupiter</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-release-plugin</artifactId>
|
||||
<version>2.5.3</version>
|
||||
<configuration>
|
||||
<tagNameFormat>@{project.version}</tagNameFormat>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<forkCount>1</forkCount>
|
||||
<reuseForks>true</reuseForks>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>default-test</id>
|
||||
<goals>
|
||||
<goal>test</goal>
|
||||
</goals>
|
||||
<phase>test</phase>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-failsafe-plugin</artifactId>
|
||||
<configuration>
|
||||
<forkCount>1</forkCount>
|
||||
<reuseForks>true</reuseForks>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>integration-test</goal>
|
||||
<goal>verify</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>license-maven-plugin</artifactId>
|
||||
<version>2.0.1.alfresco-2</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>third-party-licenses</id>
|
||||
<goals>
|
||||
<goal>add-third-party</goal>
|
||||
<goal>download-licenses</goal>
|
||||
</goals>
|
||||
<phase>generate-resources</phase>
|
||||
<configuration>
|
||||
<failOnMissing>true</failOnMissing>
|
||||
<excludedScopes>provided,test</excludedScopes>
|
||||
<excludedGroups>org.alfresco</excludedGroups>
|
||||
<failIfWarning>true</failIfWarning>
|
||||
<includedLicenses>https://raw.githubusercontent.com/Alfresco/third-party-license-overrides/master/includedLicenses.txt</includedLicenses>
|
||||
<licenseMergesUrl>https://raw.githubusercontent.com/Alfresco/third-party-license-overrides/master/licenseMerges.txt</licenseMergesUrl>
|
||||
<overrideUrl>https://raw.githubusercontent.com/Alfresco/third-party-license-overrides/master/override-THIRD-PARTY.properties</overrideUrl>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>license-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>3.2.2</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>test-jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Transform Model
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2022 Alfresco Software Limited
|
||||
* %%
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 General Lesser Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Lesser Public
|
||||
* License along with this program. If not, see
|
||||
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.transform.client.model;
|
||||
|
||||
import org.alfresco.transform.router.TransformStack;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Holds required contextual information.
|
||||
*
|
||||
* @author Denis Ungureanu
|
||||
* created on 10/01/2019
|
||||
*/
|
||||
public class InternalContext implements Serializable
|
||||
{
|
||||
private MultiStep multiStep;
|
||||
private int attemptedRetries;
|
||||
private String currentSourceMediaType;
|
||||
private String currentTargetMediaType;
|
||||
private String replyToDestination;
|
||||
private Long currentSourceSize;
|
||||
private Map<String, String> transformRequestOptions = new HashMap<>();
|
||||
|
||||
public MultiStep getMultiStep()
|
||||
{
|
||||
return multiStep;
|
||||
}
|
||||
|
||||
public void setMultiStep(MultiStep multiStep)
|
||||
{
|
||||
this.multiStep = multiStep;
|
||||
}
|
||||
|
||||
public int getAttemptedRetries()
|
||||
{
|
||||
return attemptedRetries;
|
||||
}
|
||||
|
||||
public void setAttemptedRetries(int attemptedRetries)
|
||||
{
|
||||
this.attemptedRetries = attemptedRetries;
|
||||
}
|
||||
|
||||
public String getCurrentSourceMediaType()
|
||||
{
|
||||
return currentSourceMediaType;
|
||||
}
|
||||
|
||||
public void setCurrentSourceMediaType(String currentSourceMediaType)
|
||||
{
|
||||
this.currentSourceMediaType = currentSourceMediaType;
|
||||
}
|
||||
|
||||
public String getCurrentTargetMediaType()
|
||||
{
|
||||
return currentTargetMediaType;
|
||||
}
|
||||
|
||||
public void setCurrentTargetMediaType(String currentTargetMediaType)
|
||||
{
|
||||
this.currentTargetMediaType = currentTargetMediaType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the reply to destination name.
|
||||
*
|
||||
* @return replyToDestination
|
||||
*/
|
||||
public String getReplyToDestination()
|
||||
{
|
||||
return replyToDestination;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the reply to destination name.
|
||||
* Note: replyToDestination is populated from jmsMessage replyTo field sent by T-Client
|
||||
*
|
||||
* @param replyToDestination reply to destination name
|
||||
*/
|
||||
public void setReplyToDestination(String replyToDestination)
|
||||
{
|
||||
this.replyToDestination = replyToDestination;
|
||||
}
|
||||
|
||||
public Long getCurrentSourceSize()
|
||||
{
|
||||
return currentSourceSize;
|
||||
}
|
||||
|
||||
public void setCurrentSourceSize(Long currentSourceSize)
|
||||
{
|
||||
this.currentSourceSize = currentSourceSize;
|
||||
}
|
||||
|
||||
public Map<String, String> getTransformRequestOptions()
|
||||
{
|
||||
return transformRequestOptions;
|
||||
}
|
||||
|
||||
public void setTransformRequestOptions(
|
||||
Map<String, String> transformRequestOptions)
|
||||
{
|
||||
this.transformRequestOptions = transformRequestOptions;
|
||||
}
|
||||
|
||||
@Override public String toString()
|
||||
{
|
||||
return "InternalContext{" +
|
||||
"multiStep=" + multiStep +
|
||||
", attemptedRetries=" + attemptedRetries +
|
||||
", currentSourceMediaType='" + currentSourceMediaType + '\'' +
|
||||
", currentTargetMediaType='" + currentTargetMediaType + '\'' +
|
||||
", replyToDestination='" + replyToDestination + '\'' +
|
||||
", currentSourceSize=" + currentSourceSize +
|
||||
", transformRequestOptions=" + transformRequestOptions +
|
||||
'}';
|
||||
}
|
||||
|
||||
// To avoid NPE checks, initialise expected bits of the structure
|
||||
public static InternalContext initialise(InternalContext internalContext)
|
||||
{
|
||||
if (internalContext == null)
|
||||
{
|
||||
internalContext = new InternalContext();
|
||||
}
|
||||
if (internalContext.getMultiStep() == null)
|
||||
{
|
||||
internalContext.setMultiStep(new MultiStep());
|
||||
}
|
||||
if (internalContext.getMultiStep().getTransformsToBeDone() == null ||
|
||||
internalContext.getMultiStep().getTransformsToBeDone().isEmpty()) // might be immutable
|
||||
{
|
||||
internalContext.getMultiStep().setTransformsToBeDone(new ArrayList<>());
|
||||
}
|
||||
return internalContext;
|
||||
}
|
||||
|
||||
// To avoid additional checks
|
||||
public static String checkForBasicErrors(InternalContext internalContext, String type)
|
||||
{
|
||||
return internalContext == null
|
||||
? type + " InternalContext was null"
|
||||
: internalContext.getMultiStep() == null
|
||||
? type + " InternalContext did not have the MultiStep set"
|
||||
: internalContext.getMultiStep().getTransformsToBeDone() == null
|
||||
? type + " InternalContext did not have the TransformsToBeDone set"
|
||||
: internalContext.getMultiStep().getInitialRequestId() == null
|
||||
? type + " InternalContext did not have the InitialRequestId set"
|
||||
: TransformStack.checkStructure(internalContext, type);
|
||||
}
|
||||
}
|
@@ -0,0 +1,364 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Transform Model
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2019 Alfresco Software Limited
|
||||
* %%
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 General Lesser Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Lesser Public
|
||||
* License along with this program. If not, see
|
||||
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.transform.client.model;
|
||||
|
||||
import static java.util.Arrays.stream;
|
||||
import static java.util.Collections.unmodifiableSet;
|
||||
import static java.util.stream.Collectors.toSet;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Mimetype
|
||||
* <p>
|
||||
* The same mimetypes defined in org.alfresco.repo.content.MimetypeMap
|
||||
*/
|
||||
public class Mimetype
|
||||
{
|
||||
//region Prefixes
|
||||
public static final String PREFIX_APPLICATION = "application/";
|
||||
|
||||
public static final String PREFIX_AUDIO = "audio/";
|
||||
|
||||
public static final String PREFIX_IMAGE = "image/";
|
||||
|
||||
public static final String PREFIX_MESSAGE = "message/";
|
||||
|
||||
public static final String PREFIX_MODEL = "model/";
|
||||
|
||||
public static final String PREFIX_MULTIPART = "multipart/";
|
||||
|
||||
public static final String PREFIX_TEXT = "text/";
|
||||
|
||||
public static final String PREFIX_VIDEO = "video/";
|
||||
|
||||
public static final String EXTENSION_BINARY = "bin";
|
||||
|
||||
public static final String MACOS_RESOURCE_FORK_FILE_NAME_PREFIX = "._";
|
||||
//endregion
|
||||
|
||||
//region Misc
|
||||
public static final String MIMETYPE_MULTIPART_ALTERNATIVE = "multipart/alternative";
|
||||
|
||||
public static final String MIMETYPE_TEXT_PLAIN = "text/plain";
|
||||
|
||||
public static final String MIMETYPE_TEXT_MEDIAWIKI = "text/mediawiki";
|
||||
|
||||
public static final String MIMETYPE_TEXT_CSS = "text/css";
|
||||
|
||||
public static final String MIMETYPE_TEXT_CSV = "text/csv";
|
||||
|
||||
public static final String MIMETYPE_TEXT_JAVASCRIPT = "text/javascript";
|
||||
|
||||
public static final String MIMETYPE_XML = "text/xml";
|
||||
|
||||
public static final String MIMETYPE_HTML = "text/html";
|
||||
|
||||
public static final String MIMETYPE_XHTML = "application/xhtml+xml";
|
||||
|
||||
public static final String MIMETYPE_PDF = "application/pdf";
|
||||
|
||||
public static final String MIMETYPE_JSON = "application/json";
|
||||
|
||||
public static final String MIMETYPE_WORD = "application/msword";
|
||||
|
||||
public static final String MIMETYPE_EXCEL = "application/vnd.ms-excel";
|
||||
|
||||
public static final String MIMETYPE_BINARY = "application/octet-stream";
|
||||
|
||||
public static final String MIMETYPE_PPT = "application/vnd.ms-powerpoint";
|
||||
|
||||
public static final String MIMETYPE_APP_DWG = "application/dwg";
|
||||
|
||||
public static final String MIMETYPE_IMG_DWG = "image/vnd.dwg";
|
||||
|
||||
public static final String MIMETYPE_VIDEO_AVI = "video/x-msvideo";
|
||||
|
||||
public static final String MIMETYPE_VIDEO_QUICKTIME = "video/quicktime";
|
||||
|
||||
public static final String MIMETYPE_VIDEO_WMV = "video/x-ms-wmv";
|
||||
|
||||
public static final String MIMETYPE_VIDEO_3GP = "video/3gpp";
|
||||
|
||||
public static final String MIMETYPE_VIDEO_3GP2 = "video/3gpp2";
|
||||
|
||||
public static final String MIMETYPE_DITA = "application/dita+xml";
|
||||
//endregion
|
||||
|
||||
//region Flash
|
||||
public static final String MIMETYPE_FLASH = "application/x-shockwave-flash";
|
||||
|
||||
public static final String MIMETYPE_VIDEO_FLV = "video/x-flv";
|
||||
|
||||
public static final String MIMETYPE_APPLICATION_FLA = "application/x-fla";
|
||||
|
||||
public static final String MIMETYPE_VIDEO_MPG = "video/mpeg";
|
||||
|
||||
public static final String MIMETYPE_VIDEO_MP4 = "video/mp4";
|
||||
|
||||
public static final String MIMETYPE_IMAGE_GIF = "image/gif";
|
||||
|
||||
public static final String MIMETYPE_IMAGE_JPEG = "image/jpeg";
|
||||
|
||||
public static final String MIMETYPE_IMAGE_RGB = "image/x-rgb";
|
||||
|
||||
public static final String MIMETYPE_IMAGE_SVG = "image/svg+xml";
|
||||
|
||||
public static final String MIMETYPE_IMAGE_PNG = "image/png";
|
||||
|
||||
public static final String MIMETYPE_IMAGE_TIFF = "image/tiff";
|
||||
|
||||
public static final String MIMETYPE_IMAGE_RAW_DNG = "image/x-raw-adobe";
|
||||
|
||||
public static final String MIMETYPE_IMAGE_RAW_3FR = "image/x-raw-hasselblad";
|
||||
|
||||
public static final String MIMETYPE_IMAGE_RAW_RAF = "image/x-raw-fuji";
|
||||
|
||||
public static final String MIMETYPE_IMAGE_RAW_CR2 = "image/x-raw-canon";
|
||||
|
||||
public static final String MIMETYPE_IMAGE_RAW_K25 = "image/x-raw-kodak";
|
||||
|
||||
public static final String MIMETYPE_IMAGE_RAW_MRW = "image/x-raw-minolta";
|
||||
|
||||
public static final String MIMETYPE_IMAGE_RAW_NEF = "image/x-raw-nikon";
|
||||
|
||||
public static final String MIMETYPE_IMAGE_RAW_ORF = "image/x-raw-olympus";
|
||||
|
||||
public static final String MIMETYPE_IMAGE_RAW_PEF = "image/x-raw-pentax";
|
||||
|
||||
public static final String MIMETYPE_IMAGE_RAW_ARW = "image/x-raw-sony";
|
||||
|
||||
public static final String MIMETYPE_IMAGE_RAW_X3F = "image/x-raw-sigma";
|
||||
|
||||
public static final String MIMETYPE_IMAGE_RAW_RW2 = "image/x-raw-panasonic";
|
||||
|
||||
public static final String MIMETYPE_IMAGE_RAW_RWL = "image/x-raw-leica";
|
||||
|
||||
public static final String MIMETYPE_IMAGE_RAW_R3D = "image/x-raw-red";
|
||||
|
||||
public static final String MIMETYPE_IMAGE_DWT = "image/x-dwt";
|
||||
|
||||
public static final String MIMETYPE_APPLICATION_EPS = "application/eps";
|
||||
|
||||
public static final String MIMETYPE_APPLICATION_PS = "application/postscript";
|
||||
|
||||
public static final String MIMETYPE_JAVASCRIPT = "application/x-javascript";
|
||||
|
||||
public static final String MIMETYPE_ZIP = "application/zip";
|
||||
|
||||
public static final String MIMETYPE_OPENSEARCH_DESCRIPTION = "application/opensearchdescription+xml";
|
||||
|
||||
public static final String MIMETYPE_ATOM = "application/atom+xml";
|
||||
|
||||
public static final String MIMETYPE_RSS = "application/rss+xml";
|
||||
|
||||
public static final String MIMETYPE_RFC822 = "message/rfc822";
|
||||
|
||||
public static final String MIMETYPE_OUTLOOK_MSG = "application/vnd.ms-outlook";
|
||||
|
||||
public static final String MIMETYPE_VISIO = "application/vnd.visio";
|
||||
|
||||
public static final String MIMETYPE_VISIO_2013 = "application/vnd.visio2013";
|
||||
//endregion
|
||||
|
||||
//region Adobe
|
||||
public static final String MIMETYPE_APPLICATION_ILLUSTRATOR = "application/illustrator";
|
||||
|
||||
public static final String MIMETYPE_APPLICATION_PHOTOSHOP = "image/vnd.adobe.photoshop";
|
||||
//endregion
|
||||
|
||||
//region Encrypted office document
|
||||
public static final String MIMETYPE_ENCRYPTED_OFFICE = "application/x-tika-ooxml-protected";
|
||||
//endregion
|
||||
|
||||
//region Open Document
|
||||
public static final String MIMETYPE_OPENDOCUMENT_TEXT = "application/vnd.oasis.opendocument.text";
|
||||
|
||||
public static final String MIMETYPE_OPENDOCUMENT_TEXT_TEMPLATE = "application/vnd.oasis.opendocument.text-template";
|
||||
|
||||
public static final String MIMETYPE_OPENDOCUMENT_GRAPHICS = "application/vnd.oasis.opendocument.graphics";
|
||||
|
||||
public static final String MIMETYPE_OPENDOCUMENT_GRAPHICS_TEMPLATE = "application/vnd.oasis.opendocument.graphics-template";
|
||||
|
||||
public static final String MIMETYPE_OPENDOCUMENT_PRESENTATION = "application/vnd.oasis.opendocument.presentation";
|
||||
|
||||
public static final String MIMETYPE_OPENDOCUMENT_PRESENTATION_TEMPLATE = "application/vnd.oasis.opendocument.presentation-template";
|
||||
|
||||
public static final String MIMETYPE_OPENDOCUMENT_SPREADSHEET = "application/vnd.oasis.opendocument.spreadsheet";
|
||||
|
||||
public static final String MIMETYPE_OPENDOCUMENT_SPREADSHEET_TEMPLATE = "application/vnd.oasis.opendocument.spreadsheet-template";
|
||||
|
||||
public static final String MIMETYPE_OPENDOCUMENT_CHART = "application/vnd.oasis.opendocument.chart";
|
||||
|
||||
public static final String MIMETYPE_OPENDOCUMENT_CHART_TEMPLATE = "applicationvnd.oasis.opendocument.chart-template";
|
||||
|
||||
public static final String MIMETYPE_OPENDOCUMENT_IMAGE = "application/vnd.oasis.opendocument.image";
|
||||
|
||||
public static final String MIMETYPE_OPENDOCUMENT_IMAGE_TEMPLATE = "applicationvnd.oasis.opendocument.image-template";
|
||||
|
||||
public static final String MIMETYPE_OPENDOCUMENT_FORMULA = "application/vnd.oasis.opendocument.formula";
|
||||
|
||||
public static final String MIMETYPE_OPENDOCUMENT_FORMULA_TEMPLATE = "applicationvnd.oasis.opendocument.formula-template";
|
||||
|
||||
public static final String MIMETYPE_OPENDOCUMENT_TEXT_MASTER = "application/vnd.oasis.opendocument.text-master";
|
||||
|
||||
public static final String MIMETYPE_OPENDOCUMENT_TEXT_WEB = "application/vnd.oasis.opendocument.text-web";
|
||||
|
||||
public static final String MIMETYPE_OPENDOCUMENT_DATABASE = "application/vnd.oasis.opendocument.database";
|
||||
//endregion
|
||||
|
||||
//region Open Office
|
||||
public static final String MIMETYPE_OPENOFFICE1_WRITER = "application/vnd.sun.xml.writer";
|
||||
|
||||
public static final String MIMETYPE_OPENOFFICE1_CALC = "application/vnd.sun.xml.calc";
|
||||
|
||||
public static final String MIMETYPE_OPENOFFICE1_DRAW = "application/vnd.sun.xml.draw";
|
||||
|
||||
public static final String MIMETYPE_OPENOFFICE1_IMPRESS = "application/vnd.sun.xml.impress";
|
||||
//endregion
|
||||
|
||||
//region Open XML
|
||||
public static final String MIMETYPE_OPENXML_WORDPROCESSING = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
|
||||
public static final String MIMETYPE_OPENXML_WORDPROCESSING_MACRO = "application/vnd.ms-word.document.macroenabled.12";
|
||||
public static final String MIMETYPE_OPENXML_WORD_TEMPLATE = "application/vnd.openxmlformats-officedocument.wordprocessingml.template";
|
||||
public static final String MIMETYPE_OPENXML_WORD_TEMPLATE_MACRO = "application/vnd.ms-word.template.macroenabled.12";
|
||||
public static final String MIMETYPE_OPENXML_SPREADSHEET = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
|
||||
public static final String MIMETYPE_OPENXML_SPREADSHEET_TEMPLATE = "application/vnd.openxmlformats-officedocument.spreadsheetml.template";
|
||||
public static final String MIMETYPE_OPENXML_SPREADSHEET_MACRO = "application/vnd.ms-excel.sheet.macroenabled.12";
|
||||
public static final String MIMETYPE_OPENXML_SPREADSHEET_TEMPLATE_MACRO = "application/vnd.ms-excel.template.macroenabled.12";
|
||||
public static final String MIMETYPE_OPENXML_SPREADSHEET_ADDIN_MACRO = "application/vnd.ms-excel.addin.macroenabled.12";
|
||||
public static final String MIMETYPE_OPENXML_SPREADSHEET_BINARY_MACRO = "application/vnd.ms-excel.sheet.binary.macroenabled.12";
|
||||
public static final String MIMETYPE_OPENXML_PRESENTATION = "application/vnd.openxmlformats-officedocument.presentationml.presentation";
|
||||
public static final String MIMETYPE_OPENXML_PRESENTATION_MACRO = "application/vnd.ms-powerpoint.presentation.macroenabled.12";
|
||||
public static final String MIMETYPE_OPENXML_PRESENTATION_SLIDESHOW = "application/vnd.openxmlformats-officedocument.presentationml.slideshow";
|
||||
public static final String MIMETYPE_OPENXML_PRESENTATION_SLIDESHOW_MACRO = "application/vnd.ms-powerpoint.slideshow.macroenabled.12";
|
||||
public static final String MIMETYPE_OPENXML_PRESENTATION_TEMPLATE = "application/vnd.openxmlformats-officedocument.presentationml.template";
|
||||
public static final String MIMETYPE_OPENXML_PRESENTATION_TEMPLATE_MACRO = "application/vnd.ms-powerpoint.template.macroenabled.12";
|
||||
public static final String MIMETYPE_OPENXML_PRESENTATION_ADDIN = "application/vnd.ms-powerpoint.addin.macroenabled.12";
|
||||
public static final String MIMETYPE_OPENXML_PRESENTATION_SLIDE = "application/vnd.openxmlformats-officedocument.presentationml.slide";
|
||||
public static final String MIMETYPE_OPENXML_PRESENTATION_SLIDE_MACRO = "application/vnd.ms-powerpoint.slide.macroenabled.12";
|
||||
//endregion
|
||||
|
||||
//region Star Office
|
||||
public static final String MIMETYPE_STAROFFICE5_DRAW = "application/vnd.stardivision.draw";
|
||||
|
||||
public static final String MIMETYPE_STAROFFICE5_CALC = "application/vnd.stardivision.calc";
|
||||
|
||||
public static final String MIMETYPE_STAROFFICE5_IMPRESS = "application/vnd.stardivision.impress";
|
||||
|
||||
public static final String MIMETYPE_STAROFFICE5_IMPRESS_PACKED = "application/vnd.stardivision.impress-packed";
|
||||
|
||||
public static final String MIMETYPE_STAROFFICE5_CHART = "application/vnd.stardivision.chart";
|
||||
|
||||
public static final String MIMETYPE_STAROFFICE5_WRITER = "application/vnd.stardivision.writer";
|
||||
|
||||
public static final String MIMETYPE_STAROFFICE5_WRITER_GLOBAL = "application/vnd.stardivision.writer-global";
|
||||
|
||||
public static final String MIMETYPE_STAROFFICE5_MATH = "application/vnd.stardivision.math";
|
||||
//endregion
|
||||
|
||||
//region Apple iWorks
|
||||
public static final String MIMETYPE_IWORK_KEYNOTE = "application/vnd.apple.keynote";
|
||||
|
||||
public static final String MIMETYPE_IWORK_NUMBERS = "application/vnd.apple.numbers";
|
||||
|
||||
public static final String MIMETYPE_IWORK_PAGES = "application/vnd.apple.pages";
|
||||
//endregion
|
||||
|
||||
//region MACOS
|
||||
public static final String MIMETYPE_APPLEFILE = "application/applefile";
|
||||
//endregion
|
||||
|
||||
//region WordPerfect
|
||||
public static final String MIMETYPE_WORDPERFECT = "application/wordperfect";
|
||||
//endregion
|
||||
|
||||
//region Audio
|
||||
public static final String MIMETYPE_MP3 = "audio/mpeg";
|
||||
|
||||
public static final String MIMETYPE_AUDIO_MP4 = "audio/mp4";
|
||||
|
||||
public static final String MIMETYPE_VORBIS = "audio/vorbis";
|
||||
|
||||
public static final String MIMETYPE_FLAC = "audio/x-flac";
|
||||
//endregion
|
||||
|
||||
//region Alfresco
|
||||
public static final String MIMETYPE_ACP = "application/acp";
|
||||
|
||||
//region other
|
||||
public static final String MIMETYPE_PBM = "image/x-portable-bitmap";
|
||||
|
||||
public static final String MIMETYPE_PNM = "image/x-portable-anymap";
|
||||
|
||||
public static final String MIMETYPE_XBM = "image/x-xbitmap";
|
||||
|
||||
public static final String MIMETYPE_XPM = "image/x-xpixmap";
|
||||
|
||||
public static final String MIMETYPE_Z = "application/x-compress";
|
||||
|
||||
public static final String MIMETYPE_PPM = "image/x-portable-pixmap";
|
||||
|
||||
public static final String MIMETYPE_TAR = "application/x-tar";
|
||||
|
||||
public static final String MIMETYPE_OGG = "application/ogg";
|
||||
//endregion
|
||||
|
||||
private static final Set<String> ALL_MIMETYPES;
|
||||
|
||||
static
|
||||
{
|
||||
ALL_MIMETYPES = unmodifiableSet(stream(Mimetype.class.getDeclaredFields())
|
||||
.filter(f -> Modifier.isPublic(f.getModifiers()))
|
||||
.filter(f -> Modifier.isStatic(f.getModifiers()))
|
||||
.filter(f -> Modifier.isFinal(f.getModifiers()))
|
||||
.filter(f -> f.getType().isAssignableFrom(String.class))
|
||||
.filter(f -> f.getName().startsWith("MIMETYPE_"))
|
||||
.peek(f -> f.setAccessible(true))
|
||||
.map(Mimetype::getFieldValue)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(toSet()));
|
||||
}
|
||||
|
||||
private static String getFieldValue(final Field f)
|
||||
{
|
||||
try
|
||||
{
|
||||
return (String) f.get(null);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static Set<String> matchMimetypes(final String regex)
|
||||
{
|
||||
return unmodifiableSet(ALL_MIMETYPES
|
||||
.stream()
|
||||
.filter(t -> t.matches(regex))
|
||||
.collect(toSet()));
|
||||
}
|
||||
}
|
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Transform Model
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2019 Alfresco Software Limited
|
||||
* %%
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 General Lesser Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Lesser Public
|
||||
* License along with this program. If not, see
|
||||
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.transform.client.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Holds required contextual information for a multi-step transform.
|
||||
*
|
||||
* @author Lucian Tuca
|
||||
* created on 19/12/2018
|
||||
*/
|
||||
public class MultiStep implements Serializable
|
||||
{
|
||||
private String initialRequestId;
|
||||
private String initialSourceMediaType;
|
||||
private List<String> transformsToBeDone = new ArrayList<>();
|
||||
|
||||
// regions [Accessors]
|
||||
|
||||
public String getInitialSourceMediaType()
|
||||
{
|
||||
return initialSourceMediaType;
|
||||
}
|
||||
|
||||
public void setInitialSourceMediaType(String initialSourceMediaType)
|
||||
{
|
||||
this.initialSourceMediaType = initialSourceMediaType;
|
||||
}
|
||||
|
||||
public String getInitialRequestId()
|
||||
{
|
||||
return initialRequestId;
|
||||
}
|
||||
|
||||
public void setInitialRequestId(String initialRequestId)
|
||||
{
|
||||
this.initialRequestId = initialRequestId;
|
||||
}
|
||||
|
||||
public List<String> getTransformsToBeDone()
|
||||
{
|
||||
return transformsToBeDone;
|
||||
}
|
||||
|
||||
public void setTransformsToBeDone(List<String> transformsToBeDone)
|
||||
{
|
||||
this.transformsToBeDone = transformsToBeDone;
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
@Override public String toString()
|
||||
{
|
||||
return "MultiStep{" +
|
||||
"initialRequestId='" + initialRequestId + '\'' +
|
||||
", initialSourceMediaType='" + initialSourceMediaType + '\'' +
|
||||
", transformsToBeDone=" + transformsToBeDone +
|
||||
'}';
|
||||
}
|
||||
}
|
@@ -0,0 +1,216 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Transform Model
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2019 Alfresco Software Limited
|
||||
* %%
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 General Lesser Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Lesser Public
|
||||
* License along with this program. If not, see
|
||||
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.transform.client.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Objects;
|
||||
|
||||
public class TransformReply implements Serializable
|
||||
{
|
||||
private String requestId;
|
||||
private int status;
|
||||
private String errorDetails;
|
||||
private String sourceReference;
|
||||
private String targetReference;
|
||||
private String clientData;
|
||||
private int schema;
|
||||
private InternalContext internalContext;
|
||||
|
||||
//region [Accessors]
|
||||
public String getRequestId()
|
||||
{
|
||||
return requestId;
|
||||
}
|
||||
|
||||
public void setRequestId(String requestId)
|
||||
{
|
||||
this.requestId = requestId;
|
||||
}
|
||||
|
||||
public int getStatus()
|
||||
{
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(int status)
|
||||
{
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public String getErrorDetails()
|
||||
{
|
||||
return errorDetails;
|
||||
}
|
||||
|
||||
public void setErrorDetails(String errorDetails)
|
||||
{
|
||||
this.errorDetails = errorDetails;
|
||||
}
|
||||
|
||||
public String getSourceReference()
|
||||
{
|
||||
return sourceReference;
|
||||
}
|
||||
|
||||
public void setSourceReference(String sourceReference)
|
||||
{
|
||||
this.sourceReference = sourceReference;
|
||||
}
|
||||
|
||||
public String getTargetReference()
|
||||
{
|
||||
return targetReference;
|
||||
}
|
||||
|
||||
public void setTargetReference(String targetReference)
|
||||
{
|
||||
this.targetReference = targetReference;
|
||||
}
|
||||
|
||||
public String getClientData()
|
||||
{
|
||||
return clientData;
|
||||
}
|
||||
|
||||
public void setClientData(String clientData)
|
||||
{
|
||||
this.clientData = clientData;
|
||||
}
|
||||
|
||||
public int getSchema()
|
||||
{
|
||||
return schema;
|
||||
}
|
||||
|
||||
public void setSchema(int schema)
|
||||
{
|
||||
this.schema = schema;
|
||||
}
|
||||
|
||||
public InternalContext getInternalContext()
|
||||
{
|
||||
return internalContext;
|
||||
}
|
||||
|
||||
public void setInternalContext(InternalContext internalContext)
|
||||
{
|
||||
this.internalContext = internalContext;
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
if (this == o)
|
||||
return true;
|
||||
if (o == null || getClass() != o.getClass())
|
||||
return false;
|
||||
TransformReply that = (TransformReply) o;
|
||||
return Objects.equals(requestId, that.requestId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return Objects.hash(requestId);
|
||||
}
|
||||
|
||||
@Override public String toString()
|
||||
{
|
||||
return "TransformReply{" +
|
||||
"requestId='" + requestId + '\'' +
|
||||
", status=" + status +
|
||||
", errorDetails='" + errorDetails + '\'' +
|
||||
", sourceReference='" + sourceReference + '\'' +
|
||||
", targetReference='" + targetReference + '\'' +
|
||||
", clientData='" + clientData + '\'' +
|
||||
", schema=" + schema +
|
||||
", internalContext=" + internalContext +
|
||||
'}';
|
||||
}
|
||||
|
||||
public static Builder builder()
|
||||
{
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
public static class Builder
|
||||
{
|
||||
private final TransformReply reply = new TransformReply();
|
||||
|
||||
private Builder() {}
|
||||
|
||||
public Builder withRequestId(final String requestId)
|
||||
{
|
||||
reply.requestId = requestId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withStatus(final int status)
|
||||
{
|
||||
reply.status = status;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withErrorDetails(final String errorDetails)
|
||||
{
|
||||
reply.errorDetails = errorDetails;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withSourceReference(final String sourceReference)
|
||||
{
|
||||
reply.sourceReference = sourceReference;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withTargetReference(final String targetReference)
|
||||
{
|
||||
reply.targetReference = targetReference;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withClientData(final String clientData)
|
||||
{
|
||||
reply.clientData = clientData;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withSchema(final int schema)
|
||||
{
|
||||
reply.schema = schema;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withInternalContext(final InternalContext internalContext)
|
||||
{
|
||||
reply.internalContext = internalContext;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TransformReply build()
|
||||
{
|
||||
return reply;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,273 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Transform Model
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2019 Alfresco Software Limited
|
||||
* %%
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 General Lesser Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Lesser Public
|
||||
* License along with this program. If not, see
|
||||
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.transform.client.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
public class TransformRequest implements Serializable
|
||||
{
|
||||
private String requestId;
|
||||
private String sourceReference;
|
||||
private String sourceMediaType;
|
||||
private Long sourceSize;
|
||||
private String sourceExtension;
|
||||
private String targetMediaType;
|
||||
private String targetExtension;
|
||||
private String clientData;
|
||||
private int schema;
|
||||
private Map<String, String> transformRequestOptions = new HashMap<>();
|
||||
private InternalContext internalContext;
|
||||
|
||||
// regions [Accessors]
|
||||
public String getRequestId()
|
||||
{
|
||||
return requestId;
|
||||
}
|
||||
|
||||
public void setRequestId(String requestId)
|
||||
{
|
||||
this.requestId = requestId;
|
||||
}
|
||||
|
||||
public String getSourceReference()
|
||||
{
|
||||
return sourceReference;
|
||||
}
|
||||
|
||||
public void setSourceReference(String sourceReference)
|
||||
{
|
||||
this.sourceReference = sourceReference;
|
||||
}
|
||||
|
||||
public String getSourceMediaType()
|
||||
{
|
||||
return sourceMediaType;
|
||||
}
|
||||
|
||||
public void setSourceMediaType(String sourceMediaType)
|
||||
{
|
||||
this.sourceMediaType = sourceMediaType;
|
||||
}
|
||||
|
||||
public Long getSourceSize()
|
||||
{
|
||||
return sourceSize;
|
||||
}
|
||||
|
||||
public void setSourceSize(Long sourceSize)
|
||||
{
|
||||
this.sourceSize = sourceSize;
|
||||
}
|
||||
|
||||
public String getSourceExtension()
|
||||
{
|
||||
return sourceExtension;
|
||||
}
|
||||
|
||||
public void setSourceExtension(String sourceExtension)
|
||||
{
|
||||
this.sourceExtension = sourceExtension;
|
||||
}
|
||||
|
||||
public String getTargetMediaType()
|
||||
{
|
||||
return targetMediaType;
|
||||
}
|
||||
|
||||
public void setTargetMediaType(String targetMediaType)
|
||||
{
|
||||
this.targetMediaType = targetMediaType;
|
||||
}
|
||||
|
||||
public String getTargetExtension()
|
||||
{
|
||||
return targetExtension;
|
||||
}
|
||||
|
||||
public void setTargetExtension(String targetExtension)
|
||||
{
|
||||
this.targetExtension = targetExtension;
|
||||
}
|
||||
|
||||
public String getClientData()
|
||||
{
|
||||
return clientData;
|
||||
}
|
||||
|
||||
public void setClientData(String clientData)
|
||||
{
|
||||
this.clientData = clientData;
|
||||
}
|
||||
|
||||
public int getSchema()
|
||||
{
|
||||
return schema;
|
||||
}
|
||||
|
||||
public void setSchema(int schema)
|
||||
{
|
||||
this.schema = schema;
|
||||
}
|
||||
|
||||
public Map<String, String> getTransformRequestOptions()
|
||||
{
|
||||
return transformRequestOptions;
|
||||
}
|
||||
|
||||
public void setTransformRequestOptions(Map<String, String> transformRequestOptions)
|
||||
{
|
||||
this.transformRequestOptions = transformRequestOptions;
|
||||
}
|
||||
|
||||
public InternalContext getInternalContext()
|
||||
{
|
||||
return internalContext;
|
||||
}
|
||||
|
||||
public void setInternalContext(InternalContext internalContext)
|
||||
{
|
||||
this.internalContext = internalContext;
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
if (this == o)
|
||||
return true;
|
||||
if (o == null || getClass() != o.getClass())
|
||||
return false;
|
||||
TransformRequest that = (TransformRequest) o;
|
||||
return Objects.equals(requestId, that.requestId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return Objects.hash(requestId);
|
||||
}
|
||||
|
||||
@Override public String toString()
|
||||
{
|
||||
return "TransformRequest{" +
|
||||
"requestId='" + requestId + '\'' +
|
||||
", sourceReference='" + sourceReference + '\'' +
|
||||
", sourceMediaType='" + sourceMediaType + '\'' +
|
||||
", sourceSize=" + sourceSize +
|
||||
", sourceExtension='" + sourceExtension + '\'' +
|
||||
", targetMediaType='" + targetMediaType + '\'' +
|
||||
", targetExtension='" + targetExtension + '\'' +
|
||||
", clientData='" + clientData + '\'' +
|
||||
", schema=" + schema +
|
||||
", transformRequestOptions=" + transformRequestOptions +
|
||||
", internalContext=" + internalContext +
|
||||
'}';
|
||||
}
|
||||
|
||||
public static Builder builder()
|
||||
{
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
public static class Builder
|
||||
{
|
||||
private final TransformRequest request = new TransformRequest();
|
||||
|
||||
private Builder() {}
|
||||
|
||||
public Builder withRequestId(final String requestId)
|
||||
{
|
||||
request.requestId = requestId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withInternalContext(final InternalContext internalContext)
|
||||
{
|
||||
request.internalContext = internalContext;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withSourceReference(final String sourceReference)
|
||||
{
|
||||
request.sourceReference = sourceReference;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withSourceMediaType(final String sourceMediaType)
|
||||
{
|
||||
request.sourceMediaType = sourceMediaType;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withSourceSize(final Long sourceSize)
|
||||
{
|
||||
request.sourceSize = sourceSize;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withSourceExtension(final String sourceExtension)
|
||||
{
|
||||
request.sourceExtension = sourceExtension;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withTargetMediaType(final String targetMediaType)
|
||||
{
|
||||
request.targetMediaType = targetMediaType;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withTargetExtension(final String targetExtension)
|
||||
{
|
||||
request.targetExtension = targetExtension;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withClientData(final String clientData)
|
||||
{
|
||||
request.clientData = clientData;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withTransformRequestOptions(
|
||||
final Map<String, String> transformRequestOptions)
|
||||
{
|
||||
request.transformRequestOptions = transformRequestOptions;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withSchema(final int schema)
|
||||
{
|
||||
request.schema = schema;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TransformRequest build()
|
||||
{
|
||||
return request;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Transform Model
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2022 Alfresco Software Limited
|
||||
* %%
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 General Lesser Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Lesser Public
|
||||
* License along with this program. If not, see
|
||||
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.transform.client.model;
|
||||
|
||||
import org.springframework.validation.Errors;
|
||||
import org.springframework.validation.Validator;
|
||||
|
||||
/**
|
||||
* TransformRequestValidator
|
||||
* <p>
|
||||
* Transform request validator
|
||||
*/
|
||||
public class TransformRequestValidator implements Validator
|
||||
{
|
||||
@Override
|
||||
public boolean supports(Class<?> aClass)
|
||||
{
|
||||
return aClass.isAssignableFrom(TransformRequest.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate(Object o, Errors errors)
|
||||
{
|
||||
final TransformRequest request = (TransformRequest) o;
|
||||
|
||||
if (request == null)
|
||||
{
|
||||
errors.reject(null, "request cannot be null");
|
||||
}
|
||||
else
|
||||
{
|
||||
String requestId = request.getRequestId();
|
||||
if (requestId == null || requestId.isEmpty())
|
||||
{
|
||||
errors.rejectValue("requestId", null, "requestId cannot be null or empty");
|
||||
}
|
||||
Long sourceSize = request.getSourceSize();
|
||||
if (sourceSize == null || sourceSize <= 0)
|
||||
{
|
||||
errors.rejectValue("sourceSize", null,
|
||||
"sourceSize cannot be null or have its value smaller than 0");
|
||||
}
|
||||
String sourceMediaType = request.getSourceMediaType();
|
||||
if (sourceMediaType == null || sourceMediaType.isEmpty())
|
||||
{
|
||||
errors.rejectValue("sourceMediaType", null,
|
||||
"sourceMediaType cannot be null or empty");
|
||||
}
|
||||
String targetMediaType = request.getTargetMediaType();
|
||||
if (targetMediaType == null || targetMediaType.isEmpty())
|
||||
{
|
||||
errors.rejectValue("targetMediaType", null,
|
||||
"targetMediaType cannot be null or empty");
|
||||
}
|
||||
String targetExtension = request.getTargetExtension();
|
||||
if (targetExtension == null || targetExtension.isEmpty())
|
||||
{
|
||||
errors.rejectValue("targetExtension", null,
|
||||
"targetExtension cannot be null or empty");
|
||||
}
|
||||
String clientData = request.getClientData();
|
||||
if (clientData == null || clientData.isEmpty())
|
||||
{
|
||||
errors.rejectValue("clientData", String.valueOf(request.getSchema()),
|
||||
"clientData cannot be null or empty");
|
||||
}
|
||||
if (request.getSchema() < 0)
|
||||
{
|
||||
errors.rejectValue("schema", String.valueOf(request.getSchema()),
|
||||
"schema cannot be less than 0");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Transform Model
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2019 Alfresco Software Limited
|
||||
* %%
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 General Lesser Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Lesser Public
|
||||
* License along with this program. If not, see
|
||||
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.transform.client.model.config;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Abstract implementation of TransformOption.
|
||||
*/
|
||||
public abstract class AbstractTransformOption implements TransformOption
|
||||
{
|
||||
private boolean required;
|
||||
|
||||
public AbstractTransformOption()
|
||||
{
|
||||
}
|
||||
|
||||
public AbstractTransformOption(boolean required)
|
||||
{
|
||||
this.required = required;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRequired()
|
||||
{
|
||||
return required;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRequired(boolean required)
|
||||
{
|
||||
this.required = required;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
AbstractTransformOption that = (AbstractTransformOption) o;
|
||||
return required == that.required;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return Objects.hash(required);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "AbstractTransformOption{" +
|
||||
"required=" + required +
|
||||
'}';
|
||||
}
|
||||
}
|
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Transform Model
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2021 Alfresco Software Limited
|
||||
* %%
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 General Lesser Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Lesser Public
|
||||
* License along with this program. If not, see
|
||||
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.transform.client.model.config;
|
||||
|
||||
/**
|
||||
* Holds information to add new {@link SupportedSourceAndTarget} objects to an existing {@link Transformer}.<p><br>
|
||||
*
|
||||
* <pre>
|
||||
* "addSupported": [
|
||||
* {
|
||||
* "transformerName": "Archive",
|
||||
* "sourceMediaType": "application/zip",
|
||||
* "targetMediaType": "text/xml",
|
||||
* "priority": 60,
|
||||
* "maxSourceSizeBytes": 18874368
|
||||
* }
|
||||
* ]
|
||||
* </pre>
|
||||
*/
|
||||
public class AddSupported extends TransformerTypesSizeAndPriority
|
||||
{
|
||||
public static Builder builder()
|
||||
{
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
public static class Builder extends TransformerTypesSizeAndPriority.Builder<Builder, AddSupported>
|
||||
{
|
||||
private Builder()
|
||||
{
|
||||
super(new AddSupported());
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Transform Model
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2022 Alfresco Software Limited
|
||||
* %%
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 General Lesser Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Lesser Public
|
||||
* License along with this program. If not, see
|
||||
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.transform.client.model.config;
|
||||
|
||||
import org.apache.maven.artifact.versioning.ComparableVersion;
|
||||
|
||||
import static org.alfresco.transform.client.model.config.CoreFunction.Constants.NO_UPPER_VERSION;
|
||||
import static org.alfresco.transform.client.model.config.CoreFunction.Constants.NO_VERSION;
|
||||
|
||||
/**
|
||||
* Provides a mapping between a transform {@code coreVersion} and functionality (such as the use of Direct Access URLs)
|
||||
* supported in that version of the {@code alfresco-transform-base}, so that clients know if they may use it.
|
||||
*/
|
||||
public enum CoreFunction
|
||||
{
|
||||
/** May provide a Direct Access URL rather than upload a file **/
|
||||
DIRECT_ACCESS_URL("2.5.7", null),
|
||||
|
||||
/** May request a transform via ActiveMQ **/
|
||||
// Original version was HTTP only. However none of these are still operational
|
||||
ACTIVE_MQ("1", null),
|
||||
|
||||
/** Original way to talk to a T-Engine **/
|
||||
// The toValue really should be null rather than "9999" but gives us an upper test value
|
||||
HTTP(null, "99999");
|
||||
|
||||
private final ComparableVersion fromVersion;
|
||||
private final ComparableVersion toVersion;
|
||||
|
||||
public boolean isSupported(String version)
|
||||
{
|
||||
ComparableVersion comparableVersion = newComparableVersion(version, Constants.NO_VERSION);
|
||||
return comparableVersion.compareTo(fromVersion) >= 0 && comparableVersion.compareTo(toVersion) <= 0;
|
||||
}
|
||||
|
||||
CoreFunction(String fromVersion, String toVersion)
|
||||
{
|
||||
this.fromVersion = newComparableVersion(fromVersion, NO_VERSION);
|
||||
this.toVersion = newComparableVersion(toVersion, NO_UPPER_VERSION);
|
||||
}
|
||||
|
||||
static ComparableVersion newComparableVersion(String version, ComparableVersion defaultValue)
|
||||
{
|
||||
if (version == null)
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
int i = version.indexOf('-');
|
||||
version = i > 0
|
||||
? version.substring(0, i)
|
||||
: version;
|
||||
|
||||
return new ComparableVersion(version);
|
||||
}
|
||||
|
||||
static class Constants
|
||||
{
|
||||
static final ComparableVersion NO_VERSION = new ComparableVersion("");
|
||||
static final ComparableVersion NO_UPPER_VERSION = new ComparableVersion(Integer.toString(Integer.MAX_VALUE));
|
||||
}
|
||||
}
|
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Transform Model
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2022 Alfresco Software Limited
|
||||
* %%
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 General Lesser Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Lesser Public
|
||||
* License along with this program. If not, see
|
||||
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.transform.client.model.config;
|
||||
|
||||
import org.apache.maven.artifact.versioning.ComparableVersion;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static java.util.function.Predicate.not;
|
||||
import static org.alfresco.transform.client.model.config.CoreFunction.Constants.NO_VERSION;
|
||||
import static org.alfresco.transform.client.model.config.CoreFunction.newComparableVersion;
|
||||
import static org.alfresco.transform.client.util.RequestParamMap.DIRECT_ACCESS_URL;
|
||||
|
||||
/**
|
||||
* <p>Class sets or clears the {@code coreVersion} property of {@link Transformer}s in a {@link TransformConfig}<p/>
|
||||
*
|
||||
* <p>Since alfresco-transform-core 5.2.7, the config returned by T-Engines and T-Router via their
|
||||
* {@code "/transform/config"} endpoint has been decorated with an {@code coreVersion} element, indicating what core
|
||||
* functionality is provided by each transformer as a result of extending the {@code AbstractTransformerController} in
|
||||
* the {@code alfresco-transform-base}. This is automatically added, so need not be specified by the T-Engine developer.
|
||||
* It was originally added to indicate that it was possible to use Direct Access URLs (DAU).</p>
|
||||
*
|
||||
* <p>This class provides methods to sets or clear the field with the version number of the
|
||||
* {@code alfresco-transform-base}. No value indicates 5.2.6 or earlier.</p>
|
||||
*
|
||||
* <p>To allow older and newer version of the Repository, T-Router and T-Engines to work together, this field is only
|
||||
* returned if requested by a client that also knows about the field. An optional {@code "configVersion"} parameter
|
||||
* has been added to the endpoint. The config for T-Engines need only add the field to single-step-transforms. When
|
||||
* configs are combined it is then possible to add this field to pipeline and failover transforms by using the lowest
|
||||
* core value of any step transform.</p>
|
||||
*
|
||||
* <p>If the field is not requested in the T-Router or the all-in-one transformer endpoint, it may need to be stripped
|
||||
* from the {@link TransformConfig} as some of the T-Engines may have supplied it.</p>
|
||||
*
|
||||
* @see CoreFunction
|
||||
*/
|
||||
public class CoreVersionDecorator
|
||||
{
|
||||
public static final int CONFIG_VERSION_INCLUDES_CORE_VERSION = 2;
|
||||
|
||||
private static final Set<TransformOption> DIRECT_ACCESS_URL_TRANSFORM_OPTIONS =
|
||||
Set.of(new TransformOptionValue(false, DIRECT_ACCESS_URL));
|
||||
|
||||
/**
|
||||
* Returns a {@link TransformConfig} that includes or excludes the {@code coreVersion} field.
|
||||
*/
|
||||
public static TransformConfig setOrClearCoreVersion(TransformConfig transformConfig, int configVersion)
|
||||
{
|
||||
boolean includeCoreVersion = configVersion >= 2;
|
||||
|
||||
Map<String, Set<TransformOption>> transformOptions = new HashMap<>(transformConfig.getTransformOptions());
|
||||
return TransformConfig.builder()
|
||||
// We may need to create new Transformers as we must not change the original.
|
||||
.withTransformers(transformConfig.getTransformers().stream()
|
||||
.map(transformer -> {
|
||||
if (( includeCoreVersion && transformer.getCoreVersion() == null) ||
|
||||
(!includeCoreVersion && transformer.getCoreVersion() != null))
|
||||
{
|
||||
transformer = Transformer.builder()
|
||||
.withCoreVersion(includeCoreVersion ? transformer.getCoreVersion() : null)
|
||||
.withTransformOptions(setOrClearCoreTransformOptions(
|
||||
includeCoreVersion ? transformer.getCoreVersion() : null,
|
||||
transformOptions, transformer.getTransformOptions()))
|
||||
// Original values
|
||||
.withTransformerName(transformer.getTransformerName())
|
||||
.withTransformerPipeline(transformer.getTransformerPipeline())
|
||||
.withTransformerFailover(transformer.getTransformerFailover())
|
||||
.withSupportedSourceAndTargetList(transformer.getSupportedSourceAndTargetList())
|
||||
.build();
|
||||
}
|
||||
return transformer;
|
||||
})
|
||||
.collect(Collectors.toList()))
|
||||
.withTransformOptions(transformOptions)
|
||||
// Original values
|
||||
.withRemoveTransformers(transformConfig.getRemoveTransformers())
|
||||
.withAddSupported(transformConfig.getAddSupported())
|
||||
.withRemoveSupported(transformConfig.getRemoveSupported())
|
||||
.withOverrideSupported(transformConfig.getOverrideSupported())
|
||||
.withSupportedDefaults(transformConfig.getSupportedDefaults())
|
||||
.build();
|
||||
}
|
||||
|
||||
public static void setCoreVersionOnSingleStepTransformers(TransformConfig transformConfig, String coreVersion)
|
||||
{
|
||||
Map<String, Set<TransformOption>> transformOptions = transformConfig.getTransformOptions();
|
||||
List<Transformer> transformers = transformConfig.getTransformers();
|
||||
transformers.stream()
|
||||
.filter(CoreVersionDecorator::isSingleStep)
|
||||
.forEach(transformer -> {
|
||||
transformer.setCoreVersion(coreVersion);
|
||||
transformer.setTransformOptions(setOrClearCoreTransformOptions(coreVersion,
|
||||
transformOptions, transformer.getTransformOptions()));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* The list of {@code transformers} must not contain forward references
|
||||
*/
|
||||
public static void setCoreVersionOnMultiStepTransformers(Map<String, Set<TransformOption>> transformOptions,
|
||||
List<Transformer> transformers)
|
||||
{
|
||||
Map<String, Transformer> transformersByName = transformers.stream()
|
||||
.collect(Collectors.toMap(Transformer::getTransformerName, Function.identity()));
|
||||
|
||||
transformers.stream()
|
||||
.filter(not(CoreVersionDecorator::isSingleStep))
|
||||
.forEach(transformer -> {
|
||||
|
||||
// Create a list of step transformers
|
||||
List<String> namesOfStepTransformers = transformer.getTransformerFailover().isEmpty()
|
||||
? transformer.getTransformerPipeline().stream()
|
||||
.map(TransformStep::getTransformerName)
|
||||
.collect(Collectors.toList())
|
||||
: transformer.getTransformerFailover();
|
||||
|
||||
// Set the coreVersion to the lowest step transformer value
|
||||
ComparableVersion minCoreVersion = namesOfStepTransformers.stream()
|
||||
.map(transformerName -> transformersByName.get(transformerName).getCoreVersion())
|
||||
.map(coreVersion -> newComparableVersion(coreVersion, NO_VERSION))
|
||||
.min(ComparableVersion::compareTo).orElse(NO_VERSION);
|
||||
String coreVersion = NO_VERSION.equals(minCoreVersion) ? null : minCoreVersion.toString();
|
||||
transformer.setCoreVersion(coreVersion);
|
||||
transformer.setTransformOptions(setOrClearCoreTransformOptions(transformer.getCoreVersion(),
|
||||
transformOptions, transformer.getTransformOptions()));
|
||||
});
|
||||
}
|
||||
|
||||
private static Set<String> setOrClearCoreTransformOptions(String coreVersion, Map<String,
|
||||
Set<TransformOption>> transformOptions, Set<String> transformerTransformOptions)
|
||||
{
|
||||
// If we have more options being added in future, consider adding an interface that will be implemented by
|
||||
// different implementations for each coreVersion and then iterate over them here.
|
||||
transformerTransformOptions = new HashSet<>(transformerTransformOptions);
|
||||
if (CoreFunction.DIRECT_ACCESS_URL.isSupported(coreVersion))
|
||||
{
|
||||
// Added to the Transform config if any Transformers support it.
|
||||
transformOptions.put(DIRECT_ACCESS_URL, DIRECT_ACCESS_URL_TRANSFORM_OPTIONS);
|
||||
|
||||
// Add DIRECT_ACCESS_URL to a copy of this Transformer's transform options.
|
||||
transformerTransformOptions.add(DIRECT_ACCESS_URL);
|
||||
}
|
||||
else
|
||||
{
|
||||
transformOptions.remove(DIRECT_ACCESS_URL);
|
||||
transformerTransformOptions.remove(DIRECT_ACCESS_URL);
|
||||
}
|
||||
|
||||
return transformerTransformOptions;
|
||||
}
|
||||
|
||||
private static boolean isSingleStep(Transformer transformer)
|
||||
{
|
||||
return (transformer.getTransformerFailover() == null || transformer.getTransformerFailover().isEmpty()) &&
|
||||
(transformer.getTransformerPipeline() == null || transformer.getTransformerPipeline().isEmpty());
|
||||
}
|
||||
}
|
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Transform Model
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2021 Alfresco Software Limited
|
||||
* %%
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 General Lesser Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Lesser Public
|
||||
* License along with this program. If not, see
|
||||
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.transform.client.model.config;
|
||||
|
||||
/**
|
||||
* Holds information to overriding existing {@link SupportedSourceAndTarget} objects with new {@code priority} and
|
||||
* {@code maxSourceSizeBytes} values.<p><br>
|
||||
*
|
||||
* <pre>
|
||||
* "overrideSupported" : [
|
||||
* {
|
||||
* "transformerName": "Archive", // override and existing entry
|
||||
* "sourceMediaType": "application/zip",
|
||||
* "targetMediaType": "text/html",
|
||||
* "priority": 60,
|
||||
* "maxSourceSizeBytes": 18874368
|
||||
* }
|
||||
* ]
|
||||
* </pre>
|
||||
*/
|
||||
public class OverrideSupported extends TransformerTypesSizeAndPriority
|
||||
{
|
||||
public static Builder builder()
|
||||
{
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
public static class Builder extends TransformerTypesSizeAndPriority.Builder<Builder, OverrideSupported>
|
||||
{
|
||||
private Builder()
|
||||
{
|
||||
super(new OverrideSupported());
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Transform Model
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2021 Alfresco Software Limited
|
||||
* %%
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 General Lesser Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Lesser Public
|
||||
* License along with this program. If not, see
|
||||
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.transform.client.model.config;
|
||||
|
||||
/**
|
||||
* Holds information about existing {@link SupportedSourceAndTarget} objects that should be removed.<p><br>
|
||||
*
|
||||
* <pre>
|
||||
* "removeSupported" : [
|
||||
* {
|
||||
* "transformerName": "Archive",
|
||||
* "sourceMediaType": "application/zip",
|
||||
* "targetMediaType": "text/xml"
|
||||
* }
|
||||
* ]
|
||||
* </pre>
|
||||
*/
|
||||
public class RemoveSupported extends TransformerAndTypes
|
||||
{
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "{"+super.toString()+"}";
|
||||
}
|
||||
public static Builder builder()
|
||||
{
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
public static class Builder extends TransformerAndTypes.Builder<Builder, RemoveSupported>
|
||||
{
|
||||
private Builder()
|
||||
{
|
||||
super(new RemoveSupported());
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Transform Model
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2021 Alfresco Software Limited
|
||||
* %%
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 General Lesser Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Lesser Public
|
||||
* License along with this program. If not, see
|
||||
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.transform.client.model.config;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.StringJoiner;
|
||||
|
||||
/**
|
||||
* Holds information to provide default {@code priority} and / or {@code maxSourceSizeBytes} defaults. In precedence
|
||||
* order from most specific to most general these are defined by combinations of {@code transformerName} and
|
||||
* {@code sourceMediaType}:<p><br>
|
||||
* <ul>
|
||||
* <li><b>transformer and source media type default</b> {@code transformerName} + {@code sourceMediaType}</li>
|
||||
* <li><b>transformer default</b> {@code transformerName}</li>
|
||||
* <li><b>source media type default</b> {@code sourceMediaType}</li>
|
||||
* <li><b>system wide default</b> none</li>
|
||||
* </ul><br>
|
||||
*
|
||||
* Both {@code maxSourceSizeBytes} and {@code priority} may be specified in a {@code "supportedDefaults"} element, but
|
||||
* if only one is specified it is only that value that is being defaulted at the level specified by the combination of
|
||||
* {@code transformerName} and {@code sourceMediaType}.<p><br>
|
||||
*
|
||||
* <pre>
|
||||
* "supportedDefaults" : [
|
||||
* {
|
||||
* "transformerName": "Office", // default for a source type within a transformer
|
||||
* "sourceMediaType": "application/zip",
|
||||
* "maxSourceSizeBytes": 18874368
|
||||
* },
|
||||
* {
|
||||
* "sourceMediaType": "application/msword", // defaults for a source type
|
||||
* "maxSourceSizeBytes": 4194304,
|
||||
* "priority": 45
|
||||
* },
|
||||
* {
|
||||
* "priority": 60 // system default
|
||||
* }
|
||||
* {
|
||||
* "maxSourceSizeBytes": -1 // system default
|
||||
* }
|
||||
* ]
|
||||
* </pre>
|
||||
*/
|
||||
public class SupportedDefaults
|
||||
{
|
||||
String transformerName;
|
||||
String sourceMediaType;
|
||||
Long maxSourceSizeBytes = null;
|
||||
Integer priority = null;
|
||||
|
||||
public String getTransformerName()
|
||||
{
|
||||
return transformerName;
|
||||
}
|
||||
|
||||
public void setTransformerName(String transformerName)
|
||||
{
|
||||
this.transformerName = transformerName;
|
||||
}
|
||||
|
||||
public String getSourceMediaType()
|
||||
{
|
||||
return sourceMediaType;
|
||||
}
|
||||
|
||||
public void setSourceMediaType(String sourceMediaType)
|
||||
{
|
||||
this.sourceMediaType = sourceMediaType;
|
||||
}
|
||||
|
||||
public Long getMaxSourceSizeBytes()
|
||||
{
|
||||
return maxSourceSizeBytes;
|
||||
}
|
||||
|
||||
public void setMaxSourceSizeBytes(long maxSourceSizeBytes)
|
||||
{
|
||||
this.maxSourceSizeBytes = maxSourceSizeBytes;
|
||||
}
|
||||
|
||||
public Integer getPriority()
|
||||
{
|
||||
return priority;
|
||||
}
|
||||
|
||||
public void setPriority(int priority)
|
||||
{
|
||||
this.priority = priority;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
SupportedDefaults that = (SupportedDefaults)o;
|
||||
return Objects.equals(transformerName, that.transformerName) &&
|
||||
Objects.equals(sourceMediaType, that.sourceMediaType) &&
|
||||
Objects.equals(maxSourceSizeBytes, that.maxSourceSizeBytes) &&
|
||||
Objects.equals(priority, that.priority);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return Objects.hash(transformerName, sourceMediaType, maxSourceSizeBytes, priority);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
StringJoiner sj = new StringJoiner(", ");
|
||||
if (transformerName != null) sj.add("\"transformerName\": \""+transformerName+'"');
|
||||
if (sourceMediaType != null) sj.add("\"sourceMediaType\": \""+sourceMediaType+'"');
|
||||
if (maxSourceSizeBytes != null) sj.add("\"maxSourceSizeBytes\": \""+maxSourceSizeBytes+'"');
|
||||
if (priority != null) sj.add("\"priority\": \""+priority+'"');
|
||||
return "{" + sj.toString() + "}";
|
||||
}
|
||||
|
||||
public static Builder builder()
|
||||
{
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
public static class Builder
|
||||
{
|
||||
final SupportedDefaults supportedDefaults;
|
||||
|
||||
protected Builder()
|
||||
{
|
||||
this.supportedDefaults = new SupportedDefaults();
|
||||
}
|
||||
|
||||
public SupportedDefaults build()
|
||||
{
|
||||
return supportedDefaults;
|
||||
}
|
||||
|
||||
public Builder withTransformerName(final String transformerName)
|
||||
{
|
||||
supportedDefaults.transformerName = transformerName;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withSourceMediaType(final String sourceMediaType)
|
||||
{
|
||||
supportedDefaults.sourceMediaType = sourceMediaType;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withMaxSourceSizeBytes(final Long maxSourceSizeBytes)
|
||||
{
|
||||
supportedDefaults.maxSourceSizeBytes = maxSourceSizeBytes;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withPriority(final Integer priority)
|
||||
{
|
||||
supportedDefaults.priority = priority;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Transform Model
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2021 Alfresco Software Limited
|
||||
* %%
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 General Lesser Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Lesser Public
|
||||
* License along with this program. If not, see
|
||||
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.transform.client.model.config;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.StringJoiner;
|
||||
|
||||
/**
|
||||
* Represents a single source and target combination supported by a transformer. Each combination has an optional
|
||||
* maximum size and priority.
|
||||
*/
|
||||
public class SupportedSourceAndTarget extends Types
|
||||
{
|
||||
Long maxSourceSizeBytes = null;
|
||||
Integer priority = null;
|
||||
|
||||
public SupportedSourceAndTarget()
|
||||
{
|
||||
}
|
||||
|
||||
public Long getMaxSourceSizeBytes()
|
||||
{
|
||||
return maxSourceSizeBytes;
|
||||
}
|
||||
|
||||
public void setMaxSourceSizeBytes(Long maxSourceSizeBytes)
|
||||
{
|
||||
this.maxSourceSizeBytes = maxSourceSizeBytes;
|
||||
}
|
||||
|
||||
public Integer getPriority()
|
||||
{
|
||||
return priority;
|
||||
}
|
||||
|
||||
public void setPriority(Integer priority)
|
||||
{
|
||||
this.priority = priority;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
if (!super.equals(o)) return false;
|
||||
SupportedSourceAndTarget that = (SupportedSourceAndTarget)o;
|
||||
return Objects.equals(maxSourceSizeBytes, that.maxSourceSizeBytes) &&
|
||||
Objects.equals(priority, that.priority);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return Objects.hash(super.hashCode(), maxSourceSizeBytes, priority);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
StringJoiner sj = new StringJoiner(", ");
|
||||
String superToString = super.toString();
|
||||
if (superToString != null) sj.add(superToString);
|
||||
if (maxSourceSizeBytes != null) sj.add("\"maxSourceSizeBytes\": \""+maxSourceSizeBytes+'"');
|
||||
if (priority != null) sj.add("\"priority\": \""+priority+'"');
|
||||
return "{" + sj.toString() + "}";
|
||||
}
|
||||
|
||||
public static Builder builder()
|
||||
{
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
public static class Builder extends Types.Builder<SupportedSourceAndTarget.Builder, SupportedSourceAndTarget>
|
||||
{
|
||||
private Builder()
|
||||
{
|
||||
super(new SupportedSourceAndTarget());
|
||||
}
|
||||
|
||||
public Builder withMaxSourceSizeBytes(final Long maxSourceSizeBytes)
|
||||
{
|
||||
t.setMaxSourceSizeBytes(maxSourceSizeBytes);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withPriority(final Integer priority)
|
||||
{
|
||||
t.setPriority(priority);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Transform Model
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2021 Alfresco Software Limited
|
||||
* %%
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 General Lesser Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Lesser Public
|
||||
* License along with this program. If not, see
|
||||
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.transform.client.model.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Transform Configuration with multiple {@link Transformer}s and {@link TransformOption}s.
|
||||
* It can be used for one or more Transformers.
|
||||
*/
|
||||
public class TransformConfig
|
||||
{
|
||||
private Map<String, Set<TransformOption>> transformOptions = new HashMap<>();
|
||||
|
||||
private List<Transformer> transformers = new ArrayList<>();
|
||||
|
||||
private Set<String> removeTransformers = new HashSet<>();
|
||||
|
||||
private Set<AddSupported> addSupported = new HashSet<>();
|
||||
|
||||
private Set<RemoveSupported> removeSupported = new HashSet<>();
|
||||
|
||||
private Set<OverrideSupported> overrideSupported = new HashSet<>();
|
||||
|
||||
private Set<SupportedDefaults> supportedDefaults = new HashSet<>();
|
||||
|
||||
public Map<String, Set<TransformOption>> getTransformOptions()
|
||||
{
|
||||
return transformOptions;
|
||||
}
|
||||
|
||||
public void setTransformOptions(Map<String, Set<TransformOption>> transformOptions)
|
||||
{
|
||||
this.transformOptions = transformOptions;
|
||||
}
|
||||
|
||||
public List<Transformer> getTransformers()
|
||||
{
|
||||
return transformers;
|
||||
}
|
||||
|
||||
public Set<String> getRemoveTransformers()
|
||||
{
|
||||
return removeTransformers;
|
||||
}
|
||||
|
||||
public Set<AddSupported> getAddSupported()
|
||||
{
|
||||
return addSupported;
|
||||
}
|
||||
|
||||
public Set<RemoveSupported> getRemoveSupported()
|
||||
{
|
||||
return removeSupported;
|
||||
}
|
||||
|
||||
public Set<OverrideSupported> getOverrideSupported()
|
||||
{
|
||||
return overrideSupported;
|
||||
}
|
||||
|
||||
public Set<SupportedDefaults> getSupportedDefaults()
|
||||
{
|
||||
return supportedDefaults;
|
||||
}
|
||||
|
||||
public void setTransformers(List<Transformer> transformers)
|
||||
{
|
||||
this.transformers = transformers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
TransformConfig that = (TransformConfig) o;
|
||||
return transformOptions.equals(that.transformOptions) &&
|
||||
transformers.equals(that.transformers) &&
|
||||
removeTransformers.equals(that.removeTransformers) &&
|
||||
addSupported.equals(that.addSupported) &&
|
||||
removeSupported.equals(that.removeSupported) &&
|
||||
overrideSupported.equals(that.overrideSupported) &&
|
||||
supportedDefaults.equals(that.supportedDefaults);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return Objects.hash(transformOptions, transformers, removeTransformers, addSupported, removeSupported,
|
||||
overrideSupported, supportedDefaults);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "TransformConfig{" +
|
||||
"transformOptions=" + transformOptions +
|
||||
", transformers=" + transformers +
|
||||
'}';
|
||||
}
|
||||
|
||||
public static Builder builder()
|
||||
{
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
public static class Builder
|
||||
{
|
||||
private final TransformConfig transformConfig = new TransformConfig();
|
||||
|
||||
private Builder() {}
|
||||
|
||||
public TransformConfig build()
|
||||
{
|
||||
return transformConfig;
|
||||
}
|
||||
|
||||
public Builder withTransformOptions(final Map<String, Set<TransformOption>> transformOptions)
|
||||
{
|
||||
transformConfig.transformOptions = transformOptions;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withTransformers(final List<Transformer> transformers)
|
||||
{
|
||||
transformConfig.transformers = transformers;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withRemoveTransformers(final Set<String> removeTransformers)
|
||||
{
|
||||
transformConfig.removeTransformers = removeTransformers;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withAddSupported(final Set<AddSupported> addSupported)
|
||||
{
|
||||
transformConfig.addSupported = addSupported;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withRemoveSupported(final Set<RemoveSupported> removeSupported)
|
||||
{
|
||||
transformConfig.removeSupported = removeSupported;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withOverrideSupported(final Set<OverrideSupported> overrideSupported)
|
||||
{
|
||||
transformConfig.overrideSupported = overrideSupported;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withSupportedDefaults(final Set<SupportedDefaults> supportedDefaults)
|
||||
{
|
||||
transformConfig.supportedDefaults = supportedDefaults;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Transform Model
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2019 Alfresco Software Limited
|
||||
* %%
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 General Lesser Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Lesser Public
|
||||
* License along with this program. If not, see
|
||||
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.transform.client.model.config;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonSubTypes;
|
||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
|
||||
/**
|
||||
* Represents an individual transformer option or group of options that are required or optional (default).
|
||||
*/
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME,
|
||||
include = JsonTypeInfo.As.WRAPPER_OBJECT)
|
||||
@JsonSubTypes({@JsonSubTypes.Type(value = TransformOptionValue.class, name = "value"),
|
||||
@JsonSubTypes.Type(value = TransformOptionGroup.class, name = "group")})
|
||||
public interface TransformOption
|
||||
{
|
||||
boolean isRequired();
|
||||
|
||||
void setRequired(boolean required);
|
||||
}
|
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Transform Model
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2019 Alfresco Software Limited
|
||||
* %%
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 General Lesser Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Lesser Public
|
||||
* License along with this program. If not, see
|
||||
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.transform.client.model.config;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Represents a group of one or more options. If the group is optional, child options that are marked as required are
|
||||
* only required if any child in the group is supplied by the client. If the group is required, child options are
|
||||
* optional or required based on their own setting alone.
|
||||
*
|
||||
* In a pipeline transformation, a group of options
|
||||
*/
|
||||
public class TransformOptionGroup extends AbstractTransformOption
|
||||
{
|
||||
private Set<TransformOption> transformOptions = new HashSet<>();
|
||||
|
||||
public TransformOptionGroup()
|
||||
{
|
||||
}
|
||||
|
||||
public TransformOptionGroup(boolean required, Set<TransformOption> transformOptions)
|
||||
{
|
||||
super(required);
|
||||
this.transformOptions = transformOptions;
|
||||
}
|
||||
|
||||
public Set<TransformOption> getTransformOptions()
|
||||
{
|
||||
return transformOptions;
|
||||
}
|
||||
|
||||
public void setTransformOptions(Set<TransformOption> transformOptions)
|
||||
{
|
||||
this.transformOptions = transformOptions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
if (!super.equals(o)) return false;
|
||||
TransformOptionGroup that = (TransformOptionGroup) o;
|
||||
return Objects.equals(transformOptions, that.transformOptions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return Objects.hash(super.hashCode(), transformOptions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "TransformOptionGroup{" +
|
||||
"transformOptions=" + transformOptions +
|
||||
'}';
|
||||
}
|
||||
}
|
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Transform Model
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2019 Alfresco Software Limited
|
||||
* %%
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 General Lesser Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Lesser Public
|
||||
* License along with this program. If not, see
|
||||
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.transform.client.model.config;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Represents a single transformation option.
|
||||
*/
|
||||
public class TransformOptionValue extends AbstractTransformOption
|
||||
{
|
||||
private String name;
|
||||
|
||||
public TransformOptionValue()
|
||||
{
|
||||
}
|
||||
|
||||
public TransformOptionValue(boolean required, String name)
|
||||
{
|
||||
super(required);
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name)
|
||||
{
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
if (!super.equals(o)) return false;
|
||||
TransformOptionValue that = (TransformOptionValue) o;
|
||||
return Objects.equals(name, that.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return Objects.hash(super.hashCode(), name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "TransformOptionValue{" +
|
||||
"name='" + name + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Transform Model
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2019 Alfresco Software Limited
|
||||
* %%
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 General Lesser Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Lesser Public
|
||||
* License along with this program. If not, see
|
||||
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.transform.client.model.config;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Represents a single transform step in a transform pipeline. The last step in the pipeline does not specify the
|
||||
* target type as that is based on the supported types and what has been requested.
|
||||
*/
|
||||
public class TransformStep
|
||||
{
|
||||
private String transformerName;
|
||||
private String targetMediaType;
|
||||
|
||||
public TransformStep()
|
||||
{
|
||||
}
|
||||
|
||||
public TransformStep(String transformerName, String targetMediaType)
|
||||
{
|
||||
this.transformerName = transformerName;
|
||||
this.targetMediaType = targetMediaType;
|
||||
}
|
||||
|
||||
public String getTransformerName()
|
||||
{
|
||||
return transformerName;
|
||||
}
|
||||
|
||||
public void setTransformerName(String transformerName)
|
||||
{
|
||||
this.transformerName = transformerName;
|
||||
}
|
||||
|
||||
public String getTargetMediaType()
|
||||
{
|
||||
return targetMediaType;
|
||||
}
|
||||
|
||||
public void setTargetMediaType(String targetMediaType)
|
||||
{
|
||||
this.targetMediaType = targetMediaType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
TransformStep that = (TransformStep) o;
|
||||
return Objects.equals(transformerName, that.transformerName) &&
|
||||
Objects.equals(targetMediaType, that.targetMediaType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return Objects.hash(transformerName, targetMediaType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "TransformStep{" +
|
||||
"transformerName='" + transformerName + '\'' +
|
||||
", targetMediaType='" + targetMediaType + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
@@ -0,0 +1,244 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Transform Model
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2022 Alfresco Software Limited
|
||||
* %%
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 General Lesser Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Lesser Public
|
||||
* License along with this program. If not, see
|
||||
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.transform.client.model.config;
|
||||
|
||||
import org.alfresco.transform.client.registry.TransformServiceRegistry;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Represents a set of transformations supported by the Transform Service or Local Transform Service Registry that
|
||||
* share the same transform options. Each may be an actual transformer, a pipeline of multiple transformers or a list
|
||||
* of failover transforms. It is possible that more than one transformer may able to perform a transformation from one
|
||||
* mimetype to another. The actual selection of transformer is up to the Transform Service or Local Transform Service
|
||||
* Registry to decide. Clients may use
|
||||
* {@link TransformServiceRegistry#isSupported(String, long, String, java.util.Map, String)} to decide
|
||||
* if they should send a request to the service. As a result clients have a simple generic view of transformations which
|
||||
* allows new transformations to be added without the need to change client data structures other than to define new
|
||||
* name value pairs. For this to work the Transform Service defines unique names for each option.
|
||||
* <ul>
|
||||
* <li>transformerName - is optional but if supplied should be unique. The client should infer nothing from the name
|
||||
* as it is simply a label, but the Local Transform Service Registry will use the name in pipelines.</lI>
|
||||
* <li>transformOptions - a grouping of individual transformer transformOptions. The group may be optional and may
|
||||
* contain nested transformOptions.</li>
|
||||
* </ul>
|
||||
* For local transforms, this structure is extended when defining a pipeline transform and failover transform.
|
||||
* <ul>
|
||||
* <li>transformerPipeline - an array of pairs of transformer name and target extension for each transformer in the
|
||||
* pipeline. The last one should not have an extension as that is defined by the request and should be in the
|
||||
* supported list.</li>
|
||||
* <li>transformerFailover - an array of failover definitions used in case of a fail transformation to pass a document
|
||||
* to a sequence of transforms until one succeeds.</li>
|
||||
* <li>coreVersion - indicates the version of the T-Engine's base. See {@link CoreVersionDecorator} for more detail.</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class Transformer
|
||||
{
|
||||
private String transformerName;
|
||||
private String coreVersion;
|
||||
private Set<String> transformOptions = new HashSet<>();
|
||||
private Set<SupportedSourceAndTarget> supportedSourceAndTargetList = new HashSet<>();
|
||||
private List<TransformStep> transformerPipeline = new ArrayList<>();
|
||||
private List<String> transformerFailover = new ArrayList<>();
|
||||
|
||||
public Transformer()
|
||||
{
|
||||
}
|
||||
|
||||
public Transformer(String transformerName, Set<String> transformOptions,
|
||||
Set<SupportedSourceAndTarget> supportedSourceAndTargetList)
|
||||
{
|
||||
this.transformerName = transformerName;
|
||||
this.transformOptions = transformOptions;
|
||||
this.supportedSourceAndTargetList = supportedSourceAndTargetList;
|
||||
}
|
||||
|
||||
public Transformer(String transformerName, Set<String> transformOptions,
|
||||
Set<SupportedSourceAndTarget> supportedSourceAndTargetList,
|
||||
List<TransformStep> transformerPipeline)
|
||||
{
|
||||
this(transformerName, transformOptions, supportedSourceAndTargetList);
|
||||
this.transformerPipeline = transformerPipeline;
|
||||
}
|
||||
|
||||
public Transformer(String transformerName, Set<String> transformOptions,
|
||||
Set<SupportedSourceAndTarget> supportedSourceAndTargetList,
|
||||
List<TransformStep> transformerPipeline, List<String> transformerFailover)
|
||||
{
|
||||
this(transformerName, transformOptions, supportedSourceAndTargetList, transformerPipeline);
|
||||
this.transformerFailover = transformerFailover;
|
||||
}
|
||||
|
||||
public String getTransformerName()
|
||||
{
|
||||
return transformerName;
|
||||
}
|
||||
|
||||
public void setTransformerName(String transformerName)
|
||||
{
|
||||
this.transformerName = transformerName;
|
||||
}
|
||||
|
||||
public String getCoreVersion()
|
||||
{
|
||||
return coreVersion;
|
||||
}
|
||||
|
||||
public void setCoreVersion(String coreVersion)
|
||||
{
|
||||
this.coreVersion = coreVersion;
|
||||
}
|
||||
|
||||
public List<TransformStep> getTransformerPipeline()
|
||||
{
|
||||
return transformerPipeline;
|
||||
}
|
||||
|
||||
public void setTransformerPipeline(List<TransformStep> transformerPipeline)
|
||||
{
|
||||
this.transformerPipeline = transformerPipeline;
|
||||
}
|
||||
|
||||
public List<String> getTransformerFailover()
|
||||
{
|
||||
return transformerFailover;
|
||||
}
|
||||
|
||||
public void setTransformerFailover(List<String> transformerFailover)
|
||||
{
|
||||
this.transformerFailover = transformerFailover;
|
||||
}
|
||||
|
||||
public Set<String> getTransformOptions()
|
||||
{
|
||||
return transformOptions;
|
||||
}
|
||||
|
||||
public void setTransformOptions(Set<String> transformOptions)
|
||||
{
|
||||
this.transformOptions = transformOptions;
|
||||
}
|
||||
|
||||
public Set<SupportedSourceAndTarget> getSupportedSourceAndTargetList()
|
||||
{
|
||||
return supportedSourceAndTargetList;
|
||||
}
|
||||
|
||||
public void setSupportedSourceAndTargetList(
|
||||
Set<SupportedSourceAndTarget> supportedSourceAndTargetList)
|
||||
{
|
||||
this.supportedSourceAndTargetList = supportedSourceAndTargetList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Transformer that = (Transformer) o;
|
||||
return Objects.equals(transformerName, that.transformerName) &&
|
||||
Objects.equals(coreVersion, that.coreVersion) &&
|
||||
Objects.equals(transformerPipeline, that.transformerPipeline) &&
|
||||
Objects.equals(transformerFailover, that.transformerFailover) &&
|
||||
Objects.equals(transformOptions, that.transformOptions) &&
|
||||
Objects.equals(supportedSourceAndTargetList,
|
||||
that.supportedSourceAndTargetList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return Objects.hash(transformerName, coreVersion, transformerPipeline, transformerFailover, transformOptions,
|
||||
supportedSourceAndTargetList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "Transformer{" +
|
||||
"transformerName='" + transformerName + '\'' +
|
||||
", coreVersion=" + coreVersion +
|
||||
", transformerPipeline=" + transformerPipeline +
|
||||
", transformerFailover=" + transformerFailover +
|
||||
", transformOptions=" + transformOptions +
|
||||
", supportedSourceAndTargetList=" + supportedSourceAndTargetList +
|
||||
'}';
|
||||
}
|
||||
|
||||
public static Builder builder()
|
||||
{
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
public static class Builder
|
||||
{
|
||||
private final Transformer transformer = new Transformer();
|
||||
|
||||
private Builder() {}
|
||||
|
||||
public Transformer build()
|
||||
{
|
||||
return transformer;
|
||||
}
|
||||
|
||||
public Builder withTransformerName(final String transformerName)
|
||||
{
|
||||
transformer.transformerName = transformerName;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withCoreVersion(final String coreVersion)
|
||||
{
|
||||
transformer.coreVersion = coreVersion;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withTransformerPipeline(final List<TransformStep> transformerPipeline)
|
||||
{
|
||||
transformer.transformerPipeline = transformerPipeline;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withTransformerFailover(final List<String> transformerFailover)
|
||||
{
|
||||
transformer.transformerFailover = transformerFailover;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withTransformOptions(final Set<String> transformOptions)
|
||||
{
|
||||
transformer.transformOptions = transformOptions;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withSupportedSourceAndTargetList(
|
||||
final Set<SupportedSourceAndTarget> supportedSourceAndTargetList)
|
||||
{
|
||||
transformer.supportedSourceAndTargetList = supportedSourceAndTargetList;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Transform Model
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2021 Alfresco Software Limited
|
||||
* %%
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 General Lesser Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Lesser Public
|
||||
* License along with this program. If not, see
|
||||
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.transform.client.model.config;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.StringJoiner;
|
||||
|
||||
/**
|
||||
* Base object with {@code transformerName}, {@code sourceMediaType}and {@code targetMediaType}.
|
||||
* Used to identify supported transforms.
|
||||
*/
|
||||
public abstract class TransformerAndTypes extends Types
|
||||
{
|
||||
String transformerName;
|
||||
|
||||
protected TransformerAndTypes() {}
|
||||
|
||||
public String getTransformerName()
|
||||
{
|
||||
return transformerName;
|
||||
}
|
||||
|
||||
public void setTransformerName(String transformerName)
|
||||
{
|
||||
this.transformerName = transformerName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
if (!super.equals(o)) return false;
|
||||
TransformerAndTypes that = (TransformerAndTypes) o;
|
||||
return Objects.equals(transformerName, that.transformerName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return Objects.hash(super.hashCode(), transformerName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
StringJoiner sj = new StringJoiner(", ");
|
||||
String superToString = super.toString();
|
||||
if (transformerName != null) sj.add("\"transformerName\": \""+transformerName+'"');
|
||||
if (superToString != null) sj.add(superToString);
|
||||
return sj.toString();
|
||||
}
|
||||
|
||||
public static class Builder<B extends TransformerAndTypes.Builder, T extends TransformerAndTypes>
|
||||
extends Types.Builder<B, T>
|
||||
{
|
||||
private final T t;
|
||||
|
||||
protected Builder(T t)
|
||||
{
|
||||
super(t);
|
||||
this.t = t;
|
||||
}
|
||||
|
||||
public B withTransformerName(final String transformerName)
|
||||
{
|
||||
t.transformerName = transformerName;
|
||||
return (B)this;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Transform Model
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2021 Alfresco Software Limited
|
||||
* %%
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 General Lesser Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Lesser Public
|
||||
* License along with this program. If not, see
|
||||
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.transform.client.model.config;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.StringJoiner;
|
||||
|
||||
/**
|
||||
* Base object with {@code transformerName}, {@code sourceMediaType}, {@code targetMediaType},
|
||||
* {@code maxSourceSizeBytes} and {@code priority}.
|
||||
*/
|
||||
public abstract class TransformerTypesSizeAndPriority extends TransformerAndTypes
|
||||
{
|
||||
Long maxSourceSizeBytes = null;
|
||||
Integer priority = null;
|
||||
|
||||
protected TransformerTypesSizeAndPriority() {}
|
||||
|
||||
public Long getMaxSourceSizeBytes()
|
||||
{
|
||||
return maxSourceSizeBytes;
|
||||
}
|
||||
|
||||
public void setMaxSourceSizeBytes(Long maxSourceSizeBytes)
|
||||
{
|
||||
this.maxSourceSizeBytes = maxSourceSizeBytes;
|
||||
}
|
||||
|
||||
public Integer getPriority()
|
||||
{
|
||||
return priority;
|
||||
}
|
||||
|
||||
public void setPriority(Integer priority)
|
||||
{
|
||||
this.priority = priority;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
if (!super.equals(o)) return false;
|
||||
TransformerTypesSizeAndPriority that = (TransformerTypesSizeAndPriority)o;
|
||||
return getMaxSourceSizeBytes().equals(that.getMaxSourceSizeBytes()) &&
|
||||
getPriority() == that.getPriority();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return Objects.hash(super.hashCode(), transformerName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
StringJoiner sj = new StringJoiner(", ");
|
||||
String superToString = super.toString();
|
||||
if (superToString != null) sj.add(superToString);
|
||||
if (maxSourceSizeBytes != null) sj.add("\"maxSourceSizeBytes\": \""+maxSourceSizeBytes+'"');
|
||||
if (priority != null) sj.add("\"priority\": \""+priority+'"');
|
||||
return "{"+sj.toString()+"}";
|
||||
}
|
||||
|
||||
public static class Builder<B extends TransformerTypesSizeAndPriority.Builder, T extends TransformerTypesSizeAndPriority>
|
||||
extends TransformerAndTypes.Builder<B, T>
|
||||
{
|
||||
private final T t;
|
||||
|
||||
protected Builder(T t)
|
||||
{
|
||||
super(t);
|
||||
this.t = t;
|
||||
}
|
||||
|
||||
public B withMaxSourceSizeBytes(final long maxSourceSizeBytes)
|
||||
{
|
||||
t.setMaxSourceSizeBytes(maxSourceSizeBytes);
|
||||
return (B)this;
|
||||
}
|
||||
|
||||
public B withPriority(final int priority)
|
||||
{
|
||||
t.setPriority(priority);
|
||||
return (B)this;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Transform Model
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2021 Alfresco Software Limited
|
||||
* %%
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 General Lesser Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Lesser Public
|
||||
* License along with this program. If not, see
|
||||
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.transform.client.model.config;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.StringJoiner;
|
||||
|
||||
/**
|
||||
* Base object with {@code sourceMediaType} and {@code targetMediaType}.
|
||||
* Used to identify supported transforms.
|
||||
*/
|
||||
public class Types
|
||||
{
|
||||
String sourceMediaType;
|
||||
String targetMediaType;
|
||||
|
||||
protected Types() {}
|
||||
|
||||
public String getSourceMediaType()
|
||||
{
|
||||
return sourceMediaType;
|
||||
}
|
||||
|
||||
public void setSourceMediaType(String sourceMediaType)
|
||||
{
|
||||
this.sourceMediaType = sourceMediaType;
|
||||
}
|
||||
|
||||
public String getTargetMediaType()
|
||||
{
|
||||
return targetMediaType;
|
||||
}
|
||||
|
||||
public void setTargetMediaType(String targetMediaType)
|
||||
{
|
||||
this.targetMediaType = targetMediaType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Types that = (Types) o;
|
||||
return Objects.equals(sourceMediaType, that.sourceMediaType) &&
|
||||
Objects.equals(targetMediaType, that.targetMediaType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return Objects.hash(sourceMediaType, targetMediaType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
StringJoiner sj = new StringJoiner(", ");
|
||||
if (sourceMediaType != null) sj.add("\"sourceMediaType\": \""+sourceMediaType+'"');
|
||||
if (targetMediaType != null) sj.add("\"targetMediaType\": \""+targetMediaType+'"');
|
||||
return sj.toString();
|
||||
}
|
||||
|
||||
public static abstract class Builder<B extends Types.Builder, T extends Types>
|
||||
{
|
||||
final T t;
|
||||
|
||||
protected Builder(T t)
|
||||
{
|
||||
this.t = t;
|
||||
}
|
||||
|
||||
public T build()
|
||||
{
|
||||
return (T)t;
|
||||
}
|
||||
|
||||
public B withSourceMediaType(final String sourceMediaType)
|
||||
{
|
||||
t.sourceMediaType = sourceMediaType;
|
||||
return (B)this;
|
||||
}
|
||||
|
||||
public B withTargetMediaType(final String targetMediaType)
|
||||
{
|
||||
t.targetMediaType = targetMediaType;
|
||||
return (B)this;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Transform Model
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2022 Alfresco Software Limited
|
||||
* %%
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 General Lesser Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Lesser Public
|
||||
* License along with this program. If not, see
|
||||
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.transform.client.registry;
|
||||
|
||||
import static org.alfresco.transform.client.registry.TransformRegistryHelper.retrieveTransformListBySize;
|
||||
import static org.alfresco.transform.client.registry.TransformRegistryHelper.lookupTransformOptions;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.transform.client.model.config.CoreFunction;
|
||||
import org.alfresco.transform.client.model.config.TransformOption;
|
||||
import org.alfresco.transform.client.model.config.Transformer;
|
||||
|
||||
/**
|
||||
* Used to work out if a transformation is supported. Sub classes should implement {@link #getData()} to return an
|
||||
* instance of the {@link TransformCache} class. This allows sub classes to periodically replace the registry's data with newer
|
||||
* values. They may also extend the Data class to include extra fields and methods.
|
||||
*/
|
||||
public abstract class AbstractTransformRegistry implements TransformServiceRegistry
|
||||
{
|
||||
/**
|
||||
* Logs an error message if there is an error in the configuration.
|
||||
*
|
||||
* @param msg to be logged.
|
||||
*/
|
||||
protected abstract void logError(String msg);
|
||||
|
||||
/**
|
||||
* Logs a warning message if there is a problem in the configuration.
|
||||
*
|
||||
* @param msg to be logged.
|
||||
*/
|
||||
protected void logWarn(String msg)
|
||||
{
|
||||
logError(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the data held by the registry. Sub classes may extend the base Data and replace it at run time.
|
||||
*
|
||||
* @return the Data object that contains the registry's data.
|
||||
*/
|
||||
public abstract TransformCache getData();
|
||||
|
||||
/**
|
||||
* Registers a single transformer. This is an internal method called by
|
||||
* {@link CombinedTransformConfig#registerCombinedTransformers(AbstractTransformRegistry)}.
|
||||
*
|
||||
* @param transformer to be registered
|
||||
* @param transformOptions all the transform options
|
||||
* @param baseUrl where the config was be read from. Only needed when it is remote. Is null when local.
|
||||
* Does not need to be a URL. May just be a name.
|
||||
* @param readFrom debug message for log messages, indicating what type of config was read.
|
||||
*/
|
||||
protected void register(final Transformer transformer,
|
||||
final Map<String, Set<TransformOption>> transformOptions, final String baseUrl,
|
||||
final String readFrom)
|
||||
{
|
||||
getData().incrementTransformerCount();
|
||||
transformer
|
||||
.getSupportedSourceAndTargetList()
|
||||
.forEach(e -> getData().appendTransform(e.getSourceMediaType(), e.getTargetMediaType(),
|
||||
new SupportedTransform(
|
||||
transformer.getTransformerName(),
|
||||
lookupTransformOptions(transformer.getTransformOptions(), transformOptions,
|
||||
readFrom, this::logError),
|
||||
e.getMaxSourceSizeBytes(),
|
||||
e.getPriority()),
|
||||
transformer.getTransformerName(),
|
||||
transformer.getCoreVersion()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Works out the name of the transformer (might not map to an actual transformer) that will be used to transform
|
||||
* content of a given source mimetype and size into a target mimetype given a list of actual transform option names
|
||||
* and values (Strings) plus the data contained in the Transform objects registered with this class.
|
||||
*
|
||||
* @param sourceMimetype the mimetype of the source content
|
||||
* @param sourceSizeInBytes the size in bytes of the source content. Ignored if negative.
|
||||
* @param targetMimetype the mimetype of the target
|
||||
* @param actualOptions the actual name value pairs available that could be passed to the Transform Service.
|
||||
* @param renditionName (optional) name for the set of options and target mimetype. If supplied is used to cache
|
||||
* results to avoid having to work out if a given transformation is supported a second time.
|
||||
* The sourceMimetype and sourceSizeInBytes may still change. In the case of ACS this is the
|
||||
* rendition name.
|
||||
*/
|
||||
@Override
|
||||
public String findTransformerName(final String sourceMimetype, final long sourceSizeInBytes,
|
||||
final String targetMimetype, final Map<String, String> actualOptions,
|
||||
final String renditionName)
|
||||
{
|
||||
return retrieveTransformListBySize(getData(), sourceMimetype, targetMimetype, actualOptions,
|
||||
renditionName)
|
||||
.stream()
|
||||
.filter(t -> t.getMaxSourceSizeBytes() == -1 ||
|
||||
t.getMaxSourceSizeBytes() >= sourceSizeInBytes)
|
||||
.findFirst()
|
||||
.map(SupportedTransform::getName)
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long findMaxSize(final String sourceMimetype, final String targetMimetype,
|
||||
final Map<String, String> actualOptions, final String renditionName)
|
||||
{
|
||||
final List<SupportedTransform> supportedTransforms = retrieveTransformListBySize(getData(),
|
||||
sourceMimetype, targetMimetype, actualOptions, renditionName);
|
||||
return supportedTransforms.isEmpty() ? 0 :
|
||||
supportedTransforms.get(supportedTransforms.size() - 1).getMaxSourceSizeBytes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSupported(CoreFunction function, String transformerName)
|
||||
{
|
||||
return function.isSupported(getData().getCoreVersion(transformerName));
|
||||
}
|
||||
|
||||
// When testing, we need to be able to set the baseUrl when reading from a file.
|
||||
public String getBaseUrlIfTesting(String name, String baseUrl)
|
||||
{
|
||||
return baseUrl;
|
||||
}
|
||||
}
|
@@ -0,0 +1,830 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Transform Model
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2022 Alfresco Software Limited
|
||||
* %%
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 General Lesser Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Lesser Public
|
||||
* License along with this program. If not, see
|
||||
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.transform.client.registry;
|
||||
|
||||
import org.alfresco.transform.client.model.config.AddSupported;
|
||||
import org.alfresco.transform.client.model.config.SupportedDefaults;
|
||||
import org.alfresco.transform.client.model.config.OverrideSupported;
|
||||
import org.alfresco.transform.client.model.config.RemoveSupported;
|
||||
import org.alfresco.transform.client.model.config.SupportedSourceAndTarget;
|
||||
import org.alfresco.transform.client.model.config.TransformConfig;
|
||||
import org.alfresco.transform.client.model.config.TransformOption;
|
||||
import org.alfresco.transform.client.model.config.TransformStep;
|
||||
import org.alfresco.transform.client.model.config.Transformer;
|
||||
import org.alfresco.transform.client.model.config.TransformerAndTypes;
|
||||
import org.alfresco.transform.client.model.config.Types;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.StringJoiner;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static java.util.stream.Collectors.toSet;
|
||||
import static org.alfresco.transform.client.model.config.CoreVersionDecorator.setCoreVersionOnMultiStepTransformers;
|
||||
|
||||
/**
|
||||
* This class combines one or more T-Engine config and local files and registers them as if they were all in one file.
|
||||
* Transform options are shared between all sources.<p><br>
|
||||
*
|
||||
* The caller should make calls to {@link #addTransformConfig(TransformConfig, String, String, AbstractTransformRegistry)}
|
||||
* followed by calls to {@link #combineTransformerConfig(AbstractTransformRegistry)} and then
|
||||
* {@link #registerCombinedTransformers(AbstractTransformRegistry)}.<p><br>
|
||||
*
|
||||
* The helper method {@link #combineAndRegister(TransformConfig, String, String, AbstractTransformRegistry)} may be used
|
||||
* when there is only one config.
|
||||
*
|
||||
* @author adavis
|
||||
*/
|
||||
public class CombinedTransformConfig
|
||||
{
|
||||
private static final String MIMETYPE_METADATA_EXTRACT = "alfresco-metadata-extract";
|
||||
private static final String MIMETYPE_METADATA_EMBED = "alfresco-metadata-embed";
|
||||
|
||||
private static final String INTERMEDIATE_STEPS_SHOULD_HAVE_A_TARGET_MIMETYPE = "intermediate steps should have a target mimetype";
|
||||
private static final String THE_FINAL_STEP_SHOULD_NOT_HAVE_A_TARGET_MIMETYPE = "the final step should not have a target mimetype";
|
||||
|
||||
private final Map<String, Set<TransformOption>> combinedTransformOptions = new HashMap<>();
|
||||
private List<Origin<Transformer>> combinedTransformers = new ArrayList<>();
|
||||
private final Defaults defaults = new Defaults();
|
||||
|
||||
public static void combineAndRegister(TransformConfig transformConfig, String readFrom, String baseUrl,
|
||||
AbstractTransformRegistry registry)
|
||||
{
|
||||
CombinedTransformConfig combinedTransformConfig = new CombinedTransformConfig();
|
||||
combinedTransformConfig.addTransformConfig(transformConfig, readFrom, baseUrl, registry);
|
||||
combinedTransformConfig.combineTransformerConfig(registry);
|
||||
combinedTransformConfig.registerCombinedTransformers(registry);
|
||||
}
|
||||
|
||||
public void clear()
|
||||
{
|
||||
combinedTransformOptions.clear();
|
||||
combinedTransformers.clear();
|
||||
defaults.clear();
|
||||
}
|
||||
|
||||
public void addTransformConfig(List<Origin<TransformConfig>> transformConfigList, AbstractTransformRegistry registry)
|
||||
{
|
||||
transformConfigList.forEach(tc -> addTransformConfig(tc.get(), tc.getReadFrom(), tc.getBaseUrl(), registry));
|
||||
}
|
||||
|
||||
public void addTransformConfig(TransformConfig transformConfig, String readFrom, String baseUrl,
|
||||
AbstractTransformRegistry registry)
|
||||
{
|
||||
removeTransformers(transformConfig.getRemoveTransformers(), readFrom, registry);
|
||||
supportedDefaults(transformConfig.getSupportedDefaults(), readFrom, registry);
|
||||
|
||||
removeSupported(transformConfig.getRemoveSupported(), readFrom, registry);
|
||||
addSupported(transformConfig.getAddSupported(), readFrom, registry);
|
||||
overrideSupported(transformConfig.getOverrideSupported(), readFrom, registry);
|
||||
|
||||
// Add transform options and transformers from the new transformConfig
|
||||
transformConfig.getTransformOptions().forEach(combinedTransformOptions::put);
|
||||
transformConfig.getTransformers().forEach(t -> combinedTransformers.add(new Origin<>(t, baseUrl, readFrom)));
|
||||
}
|
||||
|
||||
private void removeTransformers(Set<String> removeTransformersSet, String readFrom, AbstractTransformRegistry registry)
|
||||
{
|
||||
if (!removeTransformersSet.isEmpty())
|
||||
{
|
||||
Set<String> leftOver = new HashSet<>(removeTransformersSet);
|
||||
combinedTransformers.removeIf(combinedTransformer ->
|
||||
{
|
||||
String transformerName = combinedTransformer.get().getTransformerName();
|
||||
if (removeTransformersSet.contains(transformerName))
|
||||
{
|
||||
leftOver.remove(transformerName);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
Set<String> quotedLeftOver = leftOver.stream().map(transformerName -> "\""+transformerName+'"').collect(toSet());
|
||||
logWarn(quotedLeftOver, readFrom, registry, "removeTransformers");
|
||||
}
|
||||
}
|
||||
|
||||
private void supportedDefaults(Set<SupportedDefaults> supportedDefaults, String readFrom, AbstractTransformRegistry registry)
|
||||
{
|
||||
if (!supportedDefaults.isEmpty())
|
||||
{
|
||||
Set<SupportedDefaults> leftOver = new HashSet<>(supportedDefaults);
|
||||
supportedDefaults.stream()
|
||||
.filter(supportedDefault -> supportedDefault.getMaxSourceSizeBytes() != null ||
|
||||
supportedDefault.getPriority() != null)
|
||||
.forEach(supportedDefault ->
|
||||
{
|
||||
defaults.add(supportedDefault);
|
||||
leftOver.remove(supportedDefault);
|
||||
});
|
||||
|
||||
logWarn(leftOver, readFrom, registry, "supportedDefaults");
|
||||
}
|
||||
}
|
||||
|
||||
private <T extends TransformerAndTypes> void processSupported(
|
||||
Set<T> tSet, String readFrom, AbstractTransformRegistry registry, String elementName,
|
||||
ProcessSingleT<T> process)
|
||||
{
|
||||
if (!tSet.isEmpty())
|
||||
{
|
||||
Set<T> leftOver = new HashSet<>(tSet);
|
||||
tSet.stream()
|
||||
.filter(t -> t.getTransformerName() != null &&
|
||||
t.getSourceMediaType() != null &&
|
||||
t.getTargetMediaType() != null)
|
||||
.forEach(t -> process.process(leftOver, t));
|
||||
|
||||
logWarn(leftOver, readFrom, registry, elementName);
|
||||
}
|
||||
}
|
||||
|
||||
private <T> void logWarn(Set<T> leftOver, String readFrom, AbstractTransformRegistry registry, String elementName)
|
||||
{
|
||||
if (!leftOver.isEmpty())
|
||||
{
|
||||
StringJoiner sj = new StringJoiner(", ",
|
||||
"Unable to process \"" + elementName + "\": [", "]. Read from " + readFrom);
|
||||
leftOver.forEach(removeSupported -> sj.add(removeSupported.toString()));
|
||||
registry.logWarn(sj.toString());
|
||||
}
|
||||
}
|
||||
|
||||
private interface ProcessSingleT<T>
|
||||
{
|
||||
void process(Set<T> leftOver, T removeSupported);
|
||||
}
|
||||
|
||||
private void removeSupported(Set<RemoveSupported> removeSupportedSet, String readFrom, AbstractTransformRegistry registry)
|
||||
{
|
||||
processSupported(removeSupportedSet, readFrom, registry, "removeSupported",
|
||||
(leftOver, removeSupported) ->
|
||||
combinedTransformers.stream()
|
||||
.map(Origin::get)
|
||||
.forEach(transformer ->
|
||||
{
|
||||
if (transformer.getTransformerName().equals(removeSupported.getTransformerName()) &&
|
||||
transformer.getSupportedSourceAndTargetList().removeIf(supported ->
|
||||
supported.getSourceMediaType().equals(removeSupported.getSourceMediaType()) &&
|
||||
supported.getTargetMediaType().equals(removeSupported.getTargetMediaType())))
|
||||
{
|
||||
leftOver.remove(removeSupported);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
private void addSupported(Set<AddSupported> addSupportedSet, String readFrom, AbstractTransformRegistry registry)
|
||||
{
|
||||
processSupported(addSupportedSet, readFrom, registry, "addSupported",
|
||||
(leftOver, addSupported) ->
|
||||
combinedTransformers.stream()
|
||||
.map(Origin::get)
|
||||
.filter(transformer -> transformer.getTransformerName().equals(addSupported.getTransformerName()))
|
||||
.forEach(transformerWithName ->
|
||||
{
|
||||
Set<SupportedSourceAndTarget> supportedSourceAndTargetList =
|
||||
transformerWithName.getSupportedSourceAndTargetList();
|
||||
SupportedSourceAndTarget existingSupported = getExistingSupported(
|
||||
supportedSourceAndTargetList,
|
||||
addSupported.getSourceMediaType(), addSupported.getTargetMediaType());
|
||||
if (existingSupported == null)
|
||||
{
|
||||
SupportedSourceAndTarget newSupportedSourceAndTarget = SupportedSourceAndTarget.builder()
|
||||
.withSourceMediaType(addSupported.getSourceMediaType())
|
||||
.withTargetMediaType(addSupported.getTargetMediaType())
|
||||
.withMaxSourceSizeBytes(addSupported.getMaxSourceSizeBytes())
|
||||
.withPriority(addSupported.getPriority())
|
||||
.build();
|
||||
supportedSourceAndTargetList.add(newSupportedSourceAndTarget);
|
||||
leftOver.remove(addSupported);
|
||||
}}));
|
||||
}
|
||||
|
||||
private void overrideSupported(Set<OverrideSupported> overrideSupportedSet, String readFrom, AbstractTransformRegistry registry)
|
||||
{
|
||||
processSupported(overrideSupportedSet, readFrom, registry, "overrideSupported",
|
||||
(leftOver, overrideSupported) ->
|
||||
combinedTransformers.stream().
|
||||
map(Origin::get).
|
||||
filter(transformer -> transformer.getTransformerName().equals(overrideSupported.getTransformerName())).
|
||||
forEach(transformerWithName ->
|
||||
{
|
||||
Set<SupportedSourceAndTarget> supportedSourceAndTargetList =
|
||||
transformerWithName.getSupportedSourceAndTargetList();
|
||||
SupportedSourceAndTarget existingSupported = getExistingSupported(
|
||||
supportedSourceAndTargetList,
|
||||
overrideSupported.getSourceMediaType(), overrideSupported.getTargetMediaType());
|
||||
if (existingSupported != null)
|
||||
{
|
||||
supportedSourceAndTargetList.remove(existingSupported);
|
||||
existingSupported.setMaxSourceSizeBytes(overrideSupported.getMaxSourceSizeBytes());
|
||||
existingSupported.setPriority(overrideSupported.getPriority());
|
||||
supportedSourceAndTargetList.add(existingSupported);
|
||||
leftOver.remove(overrideSupported);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
private SupportedSourceAndTarget getExistingSupported(Set<SupportedSourceAndTarget> supportedSourceAndTargetList,
|
||||
String sourceMediaType, String targetMediaType)
|
||||
{
|
||||
return supportedSourceAndTargetList.stream().filter(supported ->
|
||||
supported.getSourceMediaType().equals(sourceMediaType) &&
|
||||
supported.getTargetMediaType().equals(targetMediaType))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
public void combineTransformerConfig(AbstractTransformRegistry registry)
|
||||
{
|
||||
removeInvalidTransformers(registry);
|
||||
sortTransformers(registry);
|
||||
applyDefaults();
|
||||
addWildcardSupportedSourceAndTarget(registry);
|
||||
setCoreVersionOnCombinedMultiStepTransformers();
|
||||
}
|
||||
|
||||
public TransformConfig buildTransformConfig()
|
||||
{
|
||||
List<Transformer> transformers = new ArrayList<>();
|
||||
combinedTransformers.forEach(ct->transformers.add(ct.get()));
|
||||
Set<SupportedDefaults> supportedDefaults = defaults.getSupportedDefaults();
|
||||
return TransformConfig
|
||||
.builder()
|
||||
.withTransformers(transformers)
|
||||
.withTransformOptions(combinedTransformOptions)
|
||||
.withSupportedDefaults(supportedDefaults)
|
||||
.build();
|
||||
}
|
||||
|
||||
public void registerCombinedTransformers(AbstractTransformRegistry registry)
|
||||
{
|
||||
combinedTransformers.forEach(ct ->
|
||||
registry.register(ct.get(), combinedTransformOptions, ct.getBaseUrl(), ct.getReadFrom()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Discards transformers that are invalid (e.g. transformers that have both pipeline and failover sections). Calls
|
||||
* {@link #removeInvalidTransformer(int, List, AbstractTransformRegistry, Origin, Transformer, String, String,
|
||||
* boolean, boolean)} for each transform, so that individual invalid transforms or overridden
|
||||
* transforms may be discarded.
|
||||
*
|
||||
* @param registry that will hold the transforms.
|
||||
*/
|
||||
private void removeInvalidTransformers(AbstractTransformRegistry registry)
|
||||
{
|
||||
for (int i=0; i<combinedTransformers.size(); i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
Origin<Transformer> transformAndItsOrigin = combinedTransformers.get(i);
|
||||
Transformer transformer = transformAndItsOrigin.get();
|
||||
String readFrom = transformAndItsOrigin.getReadFrom();
|
||||
String name = transformer.getTransformerName();
|
||||
List<TransformStep> pipeline = transformer.getTransformerPipeline();
|
||||
List<String> failover = transformer.getTransformerFailover();
|
||||
boolean isPipeline = pipeline != null && !pipeline.isEmpty();
|
||||
boolean isFailover = failover != null && !failover.isEmpty();
|
||||
|
||||
if (isPipeline && isFailover)
|
||||
{
|
||||
throw new IllegalArgumentException("Transformer " + transformerName(name) +
|
||||
" cannot have pipeline and failover sections. Read from " + readFrom);
|
||||
}
|
||||
|
||||
// Remove transforms as they may override each other or be invalid
|
||||
int indexToRemove = removeInvalidTransformer(i, combinedTransformers, registry, transformAndItsOrigin,
|
||||
transformer, name, readFrom, isPipeline, isFailover);
|
||||
|
||||
// Remove an overridden transform
|
||||
if (indexToRemove >= 0)
|
||||
{
|
||||
combinedTransformers.remove(indexToRemove);
|
||||
// The current index i should be decremented so we don't skip one.
|
||||
// Condition not really needed as IllegalArgumentException is thrown if the latest entry is removed.
|
||||
if (i >= indexToRemove)
|
||||
{
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IllegalStateException e)
|
||||
{
|
||||
String msg = e.getMessage();
|
||||
registry.logWarn(msg);
|
||||
combinedTransformers.remove(i--);
|
||||
}
|
||||
catch (IllegalArgumentException e)
|
||||
{
|
||||
String msg = e.getMessage();
|
||||
registry.logError(msg);
|
||||
combinedTransformers.remove(i--);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Discards a transformer that is
|
||||
* 1) invalid:
|
||||
* a) has no name
|
||||
* b) the pass through transformer name is specified in a T-Engine
|
||||
* c) specifies transform options that don't exist,
|
||||
* d) has the same name as another T-Engine transform (i.e. there should be no duplicate names from t-engines),
|
||||
* e) the pass through transformer name is specified in a pipeline file
|
||||
* f) a single step transform defined outside a t-engine without it being an override,
|
||||
* g) a pipeline or failover transform is being overridden by a single step transform. Invalid because we
|
||||
* don't know if a t-engine will be able to do it.
|
||||
* 2) an earlier transform with the same name (it is being overridden). If the overridden transform is from a
|
||||
* T-Engine and the overriding transform is not a pipeline or a failover, we also copy the {@code baseUrl}
|
||||
* from the overridden transform so that the original T-Engine will still be called.
|
||||
*
|
||||
* @param i the current transform's index into combinedTransformers.
|
||||
* @param combinedTransformers the full list of transformers in the order they were read.
|
||||
* @param registry that wil hold the transforms.
|
||||
* @param transformAndItsOrigin the current combinedTransformers element.
|
||||
* @param transformer the current transformer.
|
||||
* @param name the current transformer's name.
|
||||
* @param readFrom where the current transformer was read from.
|
||||
* @param isPipeline if the current transform is a pipeline.
|
||||
* @param isFailover if the current transform is a failover.
|
||||
*
|
||||
* @return the index of a transform to be removed. {@code -1} is returned if there should not be a remove.
|
||||
* @throws IllegalArgumentException if the current transform has a problem and should be removed.
|
||||
* @throws IllegalStateException if the current transform is dependent on config from another transform which
|
||||
* is currently unavailable.
|
||||
*/
|
||||
private int removeInvalidTransformer(int i, List<Origin<Transformer>> combinedTransformers,
|
||||
AbstractTransformRegistry registry,
|
||||
Origin<Transformer> transformAndItsOrigin, Transformer transformer,
|
||||
String name, String readFrom, boolean isPipeline, boolean isFailover)
|
||||
{
|
||||
int indexToRemove = -1;
|
||||
|
||||
if (name == null || "".equals(name.trim()))
|
||||
{
|
||||
throw new IllegalArgumentException("Transformer names may not be null. Read from " + readFrom);
|
||||
}
|
||||
|
||||
// Get the baseUrl - test code might change it
|
||||
String baseUrl = transformAndItsOrigin.getBaseUrl();
|
||||
String testBaseUrl = registry.getBaseUrlIfTesting(name, baseUrl);
|
||||
if (!nullSafeEquals(baseUrl, testBaseUrl))
|
||||
{
|
||||
baseUrl = testBaseUrl;
|
||||
transformAndItsOrigin = new Origin<>(transformer, baseUrl, readFrom);
|
||||
combinedTransformers.set(i, transformAndItsOrigin);
|
||||
}
|
||||
boolean isTEngineTransform = baseUrl != null;
|
||||
|
||||
boolean isPassThroughTransform = isPassThroughTransformName(name);
|
||||
if (isPassThroughTransform && isTEngineTransform)
|
||||
{
|
||||
throw new IllegalArgumentException("T-Engines should not use " + transformerName(name) +
|
||||
" as a transform name. Read from " + readFrom);
|
||||
}
|
||||
|
||||
for (String transformOptionsLabel : transformer.getTransformOptions())
|
||||
{
|
||||
if (!combinedTransformOptions.containsKey(transformOptionsLabel))
|
||||
{
|
||||
throw new IllegalStateException("Transformer " + transformerName(name) +
|
||||
" references \"" + transformOptionsLabel +
|
||||
"\" which do not exist. Read from " + readFrom);
|
||||
}
|
||||
}
|
||||
|
||||
boolean isOneStepTransform = !isPipeline && !isFailover && !isPassThroughTransform;
|
||||
|
||||
// Check to see if the name has been used before.
|
||||
int j = lastIndexOf(name, combinedTransformers, i);
|
||||
if (j >= 0)
|
||||
{
|
||||
if (isTEngineTransform)
|
||||
{
|
||||
// We currently don't allow different t-engines to override each others single step transforms,
|
||||
// but we could if the order is defined in which they are read. Would need to check the baseUrl
|
||||
// is different.
|
||||
throw new IllegalArgumentException("Transformer " + transformerName(name) +
|
||||
" must be a unique name. Read from " + readFrom);
|
||||
}
|
||||
|
||||
if (isPassThroughTransform)
|
||||
{
|
||||
throw new IllegalArgumentException("Pipeline files should not use " + transformerName(name) +
|
||||
" as a transform name. Read from " + readFrom);
|
||||
}
|
||||
|
||||
if (isOneStepTransform)
|
||||
{
|
||||
Origin<Transformer> overriddenTransformAndItsOrigin = combinedTransformers.get(j);
|
||||
Transformer overriddenTransformer = overriddenTransformAndItsOrigin.get();
|
||||
List<TransformStep> overriddenPipeline = overriddenTransformer.getTransformerPipeline();
|
||||
List<String> overriddenFailover = overriddenTransformer.getTransformerFailover();
|
||||
boolean isOverriddenPipeline = overriddenPipeline != null && !overriddenPipeline.isEmpty();
|
||||
boolean isOverriddenFailover = overriddenFailover != null && !overriddenFailover.isEmpty();
|
||||
if (isOverriddenPipeline || isOverriddenFailover)
|
||||
{
|
||||
throw new IllegalArgumentException("Single step transformers (such as " + transformerName(name) +
|
||||
") may not override a pipeline or failover transform as there is no T-Engine to perform" +
|
||||
" work. Read from " + readFrom);
|
||||
}
|
||||
|
||||
// We need to set the baseUrl of the original transform in the one overriding,
|
||||
// so we can talk to its T-Engine
|
||||
String overriddenBaseUrl = overriddenTransformAndItsOrigin.getBaseUrl();
|
||||
Transformer overriddenTransformTransform = transformAndItsOrigin.get();
|
||||
Origin<Transformer> overridingTransform =
|
||||
new Origin<>(overriddenTransformTransform, overriddenBaseUrl, readFrom);
|
||||
combinedTransformers.set(i, overridingTransform);
|
||||
}
|
||||
indexToRemove = j;
|
||||
}
|
||||
else if (isOneStepTransform && baseUrl == null)
|
||||
{
|
||||
throw new IllegalArgumentException("Single step transformers (such as " + transformerName(name) +
|
||||
") must be defined in a T-Engine rather than in a pipeline file, unless they are overriding " +
|
||||
"an existing single step definition. Read from " + readFrom);
|
||||
}
|
||||
|
||||
return indexToRemove;
|
||||
}
|
||||
|
||||
protected boolean isPassThroughTransformName(String name)
|
||||
{
|
||||
return false; // There is no pass through transformer in ATS but there is in the Repo.
|
||||
}
|
||||
|
||||
private static int lastIndexOf(String name, List<Origin<Transformer>> combinedTransformers, int toIndex)
|
||||
{
|
||||
// Lists are short (< 100) entries and this is not a frequent or time critical step, so walking the list
|
||||
// should be okay.
|
||||
for (int j = toIndex-1; j >=0; j--)
|
||||
{
|
||||
Origin<Transformer> transformAndItsOrigin = combinedTransformers.get(j);
|
||||
Transformer transformer = transformAndItsOrigin.get();
|
||||
String transformerName = transformer.getTransformerName();
|
||||
if (name.equals(transformerName))
|
||||
{
|
||||
return j;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
protected static String transformerName(String name)
|
||||
{
|
||||
return name == null ? " without a name" : "\"" + name + "\"";
|
||||
}
|
||||
|
||||
// Copied from EqualsHelper
|
||||
private static boolean nullSafeEquals(Object left, Object right)
|
||||
{
|
||||
return (left == right) || (left != null && left.equals(right));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort transformers so there are no forward references, if that is possible.
|
||||
* Logs warning message for those that have missing step transformers and removes them.
|
||||
* @param registry used to log messages
|
||||
*/
|
||||
private void sortTransformers(AbstractTransformRegistry registry)
|
||||
{
|
||||
List<Origin<Transformer>> transformers = new ArrayList<>(combinedTransformers.size());
|
||||
List<Origin<Transformer>> todo = new ArrayList<>(combinedTransformers.size());
|
||||
Set<String> transformerNames = new HashSet<>();
|
||||
boolean added;
|
||||
do
|
||||
{
|
||||
added = false;
|
||||
for (Origin<Transformer> transformAndItsOrigin : combinedTransformers)
|
||||
{
|
||||
Transformer transformer = transformAndItsOrigin.get();
|
||||
String name = transformer.getTransformerName();
|
||||
Set<String> referencedTransformerNames = getReferencedTransformerNames(transformer);
|
||||
|
||||
boolean addEntry = true;
|
||||
for (String referencedTransformerName : referencedTransformerNames)
|
||||
{
|
||||
if (!transformerNames.contains(referencedTransformerName))
|
||||
{
|
||||
todo.add(transformAndItsOrigin);
|
||||
addEntry = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (addEntry)
|
||||
{
|
||||
transformers.add(transformAndItsOrigin);
|
||||
added = true;
|
||||
if (name != null)
|
||||
{
|
||||
transformerNames.add(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
combinedTransformers.clear();
|
||||
combinedTransformers.addAll(todo);
|
||||
todo.clear();
|
||||
}
|
||||
while (added && !combinedTransformers.isEmpty());
|
||||
|
||||
transformers.addAll(todo);
|
||||
|
||||
for (Origin<Transformer> transformAndItsOrigin : combinedTransformers)
|
||||
{
|
||||
Transformer transformer = transformAndItsOrigin.get();
|
||||
String name = transformer.getTransformerName();
|
||||
registry.logWarn("Transformer " + transformerName(name) +
|
||||
" ignored as step transforms " + getUnknownReferencedTransformerNames(transformer, transformerNames) +
|
||||
" do not exist. Read from " + transformAndItsOrigin.getReadFrom());
|
||||
}
|
||||
|
||||
this.combinedTransformers = transformers;
|
||||
}
|
||||
|
||||
private Set<String> getReferencedTransformerNames(Transformer transformer)
|
||||
{
|
||||
Set<String> referencedTransformerNames = new HashSet<>();
|
||||
List<TransformStep> pipeline = transformer.getTransformerPipeline();
|
||||
if (pipeline != null)
|
||||
{
|
||||
for (TransformStep step : pipeline)
|
||||
{
|
||||
String stepName = step.getTransformerName();
|
||||
referencedTransformerNames.add(stepName);
|
||||
}
|
||||
}
|
||||
List<String> failover = transformer.getTransformerFailover();
|
||||
if (failover != null)
|
||||
{
|
||||
referencedTransformerNames.addAll(failover);
|
||||
}
|
||||
return referencedTransformerNames;
|
||||
}
|
||||
|
||||
private String getUnknownReferencedTransformerNames(Transformer transformer, Set<String> transformerNames)
|
||||
{
|
||||
StringJoiner sj = new StringJoiner(", ", "(", ")");
|
||||
Set<String> referencedTransformerNames = getReferencedTransformerNames(transformer);
|
||||
for (String referencedTransformerName : referencedTransformerNames)
|
||||
{
|
||||
if (!transformerNames.contains(referencedTransformerName))
|
||||
{
|
||||
sj.add(transformerName(referencedTransformerName));
|
||||
}
|
||||
}
|
||||
return sj.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies priority and size defaults. Must be called before {@link #addWildcardSupportedSourceAndTarget(AbstractTransformRegistry)}
|
||||
* as it uses the priority value.
|
||||
*/
|
||||
private void applyDefaults()
|
||||
{
|
||||
combinedTransformers.stream()
|
||||
.map(Origin::get)
|
||||
.forEach(transformer ->
|
||||
{
|
||||
transformer.setSupportedSourceAndTargetList(
|
||||
transformer.getSupportedSourceAndTargetList().stream().map(supportedSourceAndTarget ->
|
||||
{
|
||||
Integer priority = supportedSourceAndTarget.getPriority();
|
||||
Long maxSourceSizeBytes = supportedSourceAndTarget.getMaxSourceSizeBytes();
|
||||
if (defaults.valuesUnset(priority, maxSourceSizeBytes))
|
||||
{
|
||||
String transformerName = transformer.getTransformerName();
|
||||
String sourceMediaType = supportedSourceAndTarget.getSourceMediaType();
|
||||
supportedSourceAndTarget.setPriority(defaults.getPriority(transformerName, sourceMediaType, priority));
|
||||
supportedSourceAndTarget.setMaxSourceSizeBytes(defaults.getMaxSourceSizeBytes(transformerName, sourceMediaType, maxSourceSizeBytes));
|
||||
}
|
||||
return supportedSourceAndTarget;
|
||||
}).collect(toSet()));
|
||||
});
|
||||
|
||||
defaults.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* When no supported source and target mimetypes have been defined in a failover or pipeline transformer
|
||||
* this method adds all possible values that make sense.
|
||||
* <lu>
|
||||
* <li>Failover - all the supported values from the step transformers</li>
|
||||
* <li>Pipeline - builds up supported source and target values. The list of source types and max sizes will come
|
||||
* from the initial step transformer that have a target mimetype that matches the first
|
||||
* intermediate mimetype. We then step through all intermediate transformers checking the next
|
||||
* intermediate type is supported. When we get to the last step transformer, it provides all the
|
||||
* target mimetypes based on the previous intermediate mimetype. Any combinations supported by
|
||||
* the first transformer are excluded.</li>
|
||||
* </lu>
|
||||
* @param registry used to log messages
|
||||
*/
|
||||
private void addWildcardSupportedSourceAndTarget(AbstractTransformRegistry registry)
|
||||
{
|
||||
Map<String, Transformer> transformers = new HashMap<>();
|
||||
combinedTransformers.forEach(ct -> transformers.put(ct.get().getTransformerName(), ct.get()));
|
||||
|
||||
combinedTransformers.forEach(transformAndItsOrigin ->
|
||||
{
|
||||
Transformer transformer = transformAndItsOrigin.get();
|
||||
|
||||
// If there are no SupportedSourceAndTarget, then work out all the wildcard combinations.
|
||||
if (transformer.getSupportedSourceAndTargetList().isEmpty())
|
||||
{
|
||||
List<TransformStep> pipeline = transformer.getTransformerPipeline();
|
||||
List<String> failover = transformer.getTransformerFailover();
|
||||
boolean isPipeline = pipeline != null && !pipeline.isEmpty();
|
||||
boolean isFailover = failover != null && !failover.isEmpty();
|
||||
String errorReason = null;
|
||||
if (isFailover)
|
||||
{
|
||||
Set<SupportedSourceAndTarget> supportedSourceAndTargets = failover.stream().flatMap(
|
||||
name -> transformers.get(name).getSupportedSourceAndTargetList().stream()).
|
||||
collect(toSet());
|
||||
|
||||
// The failover transform might not be picked if the priority is the same as the step transforms
|
||||
// so reduce it here by 1. In future we might want to specify the priority in the json, but for now
|
||||
// it should be okay.
|
||||
supportedSourceAndTargets.forEach(s->s.setPriority(s.getPriority()-1));
|
||||
transformer.setSupportedSourceAndTargetList(supportedSourceAndTargets);
|
||||
errorReason = "the step transforms don't support any"; // only used if there are none
|
||||
}
|
||||
else if (isPipeline)
|
||||
{
|
||||
String sourceMediaType = null;
|
||||
Set<SupportedSourceAndTarget> sourceMediaTypesAndMaxSizes = null;
|
||||
Set<String> firstTransformOptions = null;
|
||||
String firstTransformStepName = null;
|
||||
int numberOfSteps = pipeline.size();
|
||||
for (int stepIndex=0; stepIndex<numberOfSteps; stepIndex++)
|
||||
{
|
||||
TransformStep step = pipeline.get(stepIndex);
|
||||
String name = step.getTransformerName();
|
||||
Transformer stepTransformer = transformers.get(name);
|
||||
if (stepTransformer == null) // should not happen as previous checks avoid this
|
||||
{
|
||||
errorReason = "one of the step transformers is missing";
|
||||
break;
|
||||
}
|
||||
|
||||
String stepTrg = step.getTargetMediaType();
|
||||
if (stepIndex == 0)
|
||||
{
|
||||
sourceMediaTypesAndMaxSizes = stepTransformer.getSupportedSourceAndTargetList().stream().
|
||||
filter(s -> stepTrg.equals(s.getTargetMediaType())).
|
||||
collect(toSet());
|
||||
sourceMediaType = stepTrg;
|
||||
firstTransformOptions = stepTransformer.getTransformOptions();
|
||||
firstTransformStepName = name;
|
||||
if (sourceMediaTypesAndMaxSizes.isEmpty())
|
||||
{
|
||||
errorReason = "the first step transformer " + transformerName(name) +
|
||||
" does not support to \"" + stepTrg + "\"";
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
final String src = sourceMediaType;
|
||||
if (stepIndex+1 == numberOfSteps) // if final step
|
||||
{
|
||||
if (stepTrg != null)
|
||||
{
|
||||
errorReason = THE_FINAL_STEP_SHOULD_NOT_HAVE_A_TARGET_MIMETYPE;
|
||||
break;
|
||||
}
|
||||
|
||||
// Create a cartesian product of sourceMediaType,MaxSourceSize and TargetMediaType where
|
||||
// the source matches the last intermediate.
|
||||
Set<SupportedSourceAndTarget> supportedSourceAndTargets = sourceMediaTypesAndMaxSizes.stream().
|
||||
flatMap(s -> stepTransformer.getSupportedSourceAndTargetList().stream().
|
||||
filter(st ->
|
||||
{
|
||||
String targetMimetype = st.getTargetMediaType();
|
||||
return st.getSourceMediaType().equals(src) &&
|
||||
!(MIMETYPE_METADATA_EXTRACT.equals(targetMimetype) ||
|
||||
MIMETYPE_METADATA_EMBED.equals(targetMimetype));
|
||||
}).
|
||||
map(Types::getTargetMediaType).
|
||||
map(trg -> SupportedSourceAndTarget.builder().
|
||||
withSourceMediaType(s.getSourceMediaType()).
|
||||
withMaxSourceSizeBytes(s.getMaxSourceSizeBytes()).
|
||||
withPriority(s.getPriority()).
|
||||
withTargetMediaType(trg).build())).
|
||||
collect(toSet());
|
||||
|
||||
if (supportedSourceAndTargets.isEmpty())
|
||||
{
|
||||
errorReason = "the final step transformer " + transformerName(name) +
|
||||
" does not support from \"" + src + "\"";
|
||||
}
|
||||
else
|
||||
{
|
||||
// Exclude duplicates with the first transformer, if it has the same options.
|
||||
// There is no point doing more work.
|
||||
Set<String> transformOptions = transformer.getTransformOptions();
|
||||
if (sameOptions(transformOptions, firstTransformOptions))
|
||||
{
|
||||
supportedSourceAndTargets.removeAll(sourceMediaTypesAndMaxSizes);
|
||||
}
|
||||
if (supportedSourceAndTargets.isEmpty())
|
||||
{
|
||||
errorReason = "the first transformer " + transformerName(firstTransformStepName) +
|
||||
" in the pipeline already supported all source and target mimetypes" +
|
||||
" that would have been added as wildcards";
|
||||
}
|
||||
}
|
||||
|
||||
transformer.setSupportedSourceAndTargetList(supportedSourceAndTargets);
|
||||
}
|
||||
else // if intermediate step
|
||||
{
|
||||
if (stepTrg == null)
|
||||
{
|
||||
errorReason = INTERMEDIATE_STEPS_SHOULD_HAVE_A_TARGET_MIMETYPE;
|
||||
break;
|
||||
}
|
||||
|
||||
// Check source to target is supported (it normally is)
|
||||
if (stepTransformer.getSupportedSourceAndTargetList().stream().
|
||||
noneMatch(st -> st.getSourceMediaType().equals(src) &&
|
||||
st.getTargetMediaType().equals(stepTrg)))
|
||||
{
|
||||
errorReason = "the step transformer " +
|
||||
transformerName(stepTransformer.getTransformerName()) + " does not support \"" +
|
||||
src + "\" to \"" + stepTrg + "\"";
|
||||
break;
|
||||
}
|
||||
|
||||
sourceMediaType = stepTrg;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (transformer.getSupportedSourceAndTargetList().isEmpty() && (isFailover || isPipeline))
|
||||
{
|
||||
registry.logError("No supported source and target mimetypes could be added to the" +
|
||||
" transformer " + transformerName(transformer.getTransformerName()) + " as " + errorReason +
|
||||
". Read from " + transformAndItsOrigin.getReadFrom());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private boolean sameOptions(Set<String> transformOptionNames1, Set<String> transformOptionNames2)
|
||||
{
|
||||
// They have the same names
|
||||
if (transformOptionNames1.equals(transformOptionNames2))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check the actual options.
|
||||
Set<TransformOption> transformOptions1 = getTransformOptions(transformOptionNames1);
|
||||
Set<TransformOption> transformOptions2 = getTransformOptions(transformOptionNames2);
|
||||
return transformOptions1.equals(transformOptions2);
|
||||
}
|
||||
|
||||
private Set<TransformOption> getTransformOptions(Set<String> transformOptionNames)
|
||||
{
|
||||
Set<TransformOption> transformOptions = new HashSet<>();
|
||||
transformOptionNames.forEach(name->transformOptions.addAll(combinedTransformOptions.get(name)));
|
||||
return transformOptions;
|
||||
}
|
||||
|
||||
private void setCoreVersionOnCombinedMultiStepTransformers()
|
||||
{
|
||||
setCoreVersionOnMultiStepTransformers(combinedTransformOptions, combinedTransformers.stream()
|
||||
.map(Origin::get)
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
protected int transformerCount()
|
||||
{
|
||||
return combinedTransformers.size();
|
||||
}
|
||||
}
|
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Transform Model
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2022 Alfresco Software Limited
|
||||
* %%
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 General Lesser Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Lesser Public
|
||||
* License along with this program. If not, see
|
||||
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.transform.client.registry;
|
||||
|
||||
import org.alfresco.transform.client.model.config.SupportedDefaults;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static java.util.stream.Collectors.toSet;
|
||||
|
||||
/**
|
||||
* Maintains a list of defaults of {@code maxSourceSizeBytes} and {@code priority} keyed on
|
||||
* {@code transformerName} and {@code sourceMediaType} so that it can provide a lookup when we
|
||||
* join everything together in {@link CombinedTransformConfig#combineTransformerConfig(AbstractTransformRegistry)}.
|
||||
*
|
||||
* @see SupportedDefaults
|
||||
*/
|
||||
class Defaults
|
||||
{
|
||||
private static final Integer DEFAULT_PRIORITY = 50;
|
||||
private static final Long DEFAULT_MAX_SOURCE_SIZE_BYTES = -1L;
|
||||
|
||||
private static final TransformerAndSourceType SYSTEM_WIDE_KEY = new TransformerAndSourceType(null, null);
|
||||
|
||||
private final Map<TransformerAndSourceType, Integer> priorityDefaults = new HashMap<>();
|
||||
private final Map<TransformerAndSourceType, Long> maxSourceSizeBytesDefaults = new HashMap<>();
|
||||
|
||||
public void add(SupportedDefaults supportedDefault)
|
||||
{
|
||||
TransformerAndSourceType key =
|
||||
new TransformerAndSourceType(supportedDefault.getTransformerName(), supportedDefault.getSourceMediaType());
|
||||
Long maxSourceSizeBytes = supportedDefault.getMaxSourceSizeBytes();
|
||||
if (maxSourceSizeBytes != null)
|
||||
{
|
||||
maxSourceSizeBytesDefaults.put(key, maxSourceSizeBytes);
|
||||
}
|
||||
Integer priority = supportedDefault.getPriority();
|
||||
if (priority != null)
|
||||
{
|
||||
priorityDefaults.put(key, priority);
|
||||
}
|
||||
}
|
||||
|
||||
Defaults()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
public boolean valuesUnset(Integer supportedSourceAndTargetPriority, Long supportedSourceAndTargetMaxSourceSizeBytes)
|
||||
{
|
||||
return supportedSourceAndTargetPriority == null || supportedSourceAndTargetMaxSourceSizeBytes == null;
|
||||
}
|
||||
|
||||
public int getPriority(String transformerName, String sourceMediaType, Integer supportedSourceAndTargetPriority)
|
||||
{
|
||||
return getDefault(transformerName, sourceMediaType, supportedSourceAndTargetPriority, priorityDefaults);
|
||||
}
|
||||
|
||||
public long getMaxSourceSizeBytes(String transformerName, String sourceMediaType, Long supportedSourceAndTargetMaxSourceSizeBytes)
|
||||
{
|
||||
return getDefault(transformerName, sourceMediaType, supportedSourceAndTargetMaxSourceSizeBytes, maxSourceSizeBytesDefaults);
|
||||
}
|
||||
|
||||
private <T> T getDefault(String transformerName, String sourceMediaType, T supportedSourceAndTargetValue,
|
||||
Map<TransformerAndSourceType, T> map)
|
||||
{
|
||||
if (supportedSourceAndTargetValue != null)
|
||||
{
|
||||
return supportedSourceAndTargetValue;
|
||||
}
|
||||
|
||||
// 0: transformer and source media type default
|
||||
// 1: transformer default
|
||||
// 2: source media type default
|
||||
// 3: system wide default
|
||||
TransformerAndSourceType key = new TransformerAndSourceType(transformerName, sourceMediaType);
|
||||
for (int i=0; ; i++)
|
||||
{
|
||||
T value = map.get(key);
|
||||
if (value != null)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
switch (i)
|
||||
{
|
||||
case 0:
|
||||
case 2: key.setSourceMediaType(null); break;
|
||||
case 1: key.setSourceMediaType(sourceMediaType); key.setTransformerName(null); break;
|
||||
default: throw new IllegalStateException("Should have found an entry with a null, null lookup");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Set<SupportedDefaults> getSupportedDefaults()
|
||||
{
|
||||
return Stream.concat(maxSourceSizeBytesDefaults.keySet().stream(), priorityDefaults.keySet().stream())
|
||||
.filter(key ->
|
||||
{
|
||||
// Discard the entry added by clear()
|
||||
return !SYSTEM_WIDE_KEY.equals(key) ||
|
||||
!DEFAULT_MAX_SOURCE_SIZE_BYTES.equals(maxSourceSizeBytesDefaults.get(key)) ||
|
||||
!DEFAULT_PRIORITY.equals(priorityDefaults.get(key));
|
||||
})
|
||||
.map(key ->
|
||||
{
|
||||
Long maxSourceSizeBytes = maxSourceSizeBytesDefaults.get(key);
|
||||
Integer priority = priorityDefaults.get(key);
|
||||
return SupportedDefaults.builder()
|
||||
.withTransformerName(key.getTransformerName())
|
||||
.withSourceMediaType(key.getSourceMediaType())
|
||||
.withPriority(priority)
|
||||
.withMaxSourceSizeBytes(maxSourceSizeBytes)
|
||||
.build();
|
||||
}).collect(toSet());
|
||||
}
|
||||
|
||||
public void clear()
|
||||
{
|
||||
priorityDefaults.clear();
|
||||
maxSourceSizeBytesDefaults.clear();
|
||||
|
||||
priorityDefaults.put(SYSTEM_WIDE_KEY, DEFAULT_PRIORITY);
|
||||
maxSourceSizeBytesDefaults.put(SYSTEM_WIDE_KEY, DEFAULT_MAX_SOURCE_SIZE_BYTES);
|
||||
}
|
||||
}
|
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Transform Model
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2021 Alfresco Software Limited
|
||||
* %%
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 General Lesser Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Lesser Public
|
||||
* License along with this program. If not, see
|
||||
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.transform.client.registry;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Wraps an object so that we know where it was read from. The equals() and hashcode() are that of the wrapped object
|
||||
* so it is still possible do set operations.
|
||||
*/
|
||||
public class Origin<T>
|
||||
{
|
||||
final T t;
|
||||
final String baseUrl;
|
||||
final String readFrom;
|
||||
|
||||
public Origin(T t, String baseUrl, String readFrom)
|
||||
{
|
||||
this.t = t;
|
||||
this.baseUrl = baseUrl;
|
||||
this.readFrom = readFrom;
|
||||
}
|
||||
|
||||
public T get()
|
||||
{
|
||||
return t;
|
||||
}
|
||||
public String getBaseUrl()
|
||||
{
|
||||
return baseUrl;
|
||||
}
|
||||
|
||||
public String getReadFrom()
|
||||
{
|
||||
return readFrom;
|
||||
}
|
||||
|
||||
public static <T> Set<T> setOf(Collection<Origin<T>> originCollection)
|
||||
{
|
||||
Set<T> tSet = new HashSet<>(originCollection.size());
|
||||
originCollection.forEach(element -> tSet.add(element.get()));
|
||||
return tSet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Origin<?> origin = (Origin<?>)o;
|
||||
return t.equals(origin.t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return Objects.hash(t);
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Transform Model
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2019 Alfresco Software Limited
|
||||
* %%
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 General Lesser Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Lesser Public
|
||||
* License along with this program. If not, see
|
||||
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.transform.client.registry;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.transform.client.model.config.TransformOption;
|
||||
import org.alfresco.transform.client.model.config.TransformOptionGroup;
|
||||
|
||||
public class SupportedTransform
|
||||
{
|
||||
private final TransformOptionGroup transformOptions;
|
||||
private final long maxSourceSizeBytes;
|
||||
private final String name;
|
||||
private final int priority;
|
||||
|
||||
SupportedTransform(String name, Set<TransformOption> transformOptions,
|
||||
long maxSourceSizeBytes, int priority)
|
||||
{
|
||||
// Logically the top level TransformOptionGroup is required, so that child options are optional or required
|
||||
// based on their own setting.
|
||||
this.transformOptions = new TransformOptionGroup(true, transformOptions);
|
||||
this.maxSourceSizeBytes = maxSourceSizeBytes;
|
||||
this.name = name;
|
||||
this.priority = priority;
|
||||
}
|
||||
|
||||
public TransformOptionGroup getTransformOptions()
|
||||
{
|
||||
return transformOptions;
|
||||
}
|
||||
|
||||
public long getMaxSourceSizeBytes()
|
||||
{
|
||||
return maxSourceSizeBytes;
|
||||
}
|
||||
|
||||
public String getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
public int getPriority()
|
||||
{
|
||||
return priority;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
SupportedTransform that = (SupportedTransform) o;
|
||||
return maxSourceSizeBytes == that.maxSourceSizeBytes &&
|
||||
priority == that.priority &&
|
||||
Objects.equals(transformOptions, that.transformOptions) &&
|
||||
Objects.equals(name, that.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return Objects.hash(transformOptions, maxSourceSizeBytes, name, priority);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return name + ':' + maxSourceSizeBytes + ':' + priority;
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Transform Model
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2022 Alfresco Software Limited
|
||||
* %%
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 General Lesser Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Lesser Public
|
||||
* License along with this program. If not, see
|
||||
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.transform.client.registry;
|
||||
|
||||
import static java.util.Collections.emptyMap;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class TransformCache
|
||||
{
|
||||
// Looks up supported transform routes given source to target media types.
|
||||
private final Map<String, Map<String, List<SupportedTransform>>> transforms =
|
||||
new ConcurrentHashMap<>();
|
||||
|
||||
// Looks up coreVersion given the transformer name
|
||||
private final Map<String, String> coreVersions = new ConcurrentHashMap<>();
|
||||
|
||||
// Caches results in the ACS repository implementations which repeatedly make the same request.
|
||||
// Looks up a sorted list of transform routes, for a rendition (if the name is supplied) and the source
|
||||
// media type. Unlike a lookup on the transforms map above, processing of the transform options and priorities
|
||||
// will have already been done if cached.
|
||||
private final Map<String, Map<String, List<SupportedTransform>>> cachedSupportedTransformList =
|
||||
new ConcurrentHashMap<>();
|
||||
|
||||
protected int transformerCount = 0;
|
||||
protected int transformCount = 0;
|
||||
|
||||
public void incrementTransformerCount()
|
||||
{
|
||||
transformerCount++;
|
||||
}
|
||||
|
||||
public void appendTransform(final String sourceMimetype,
|
||||
final String targetMimetype, final SupportedTransform transform,
|
||||
String transformerName, String coreVersion)
|
||||
{
|
||||
transforms
|
||||
.computeIfAbsent(sourceMimetype, k -> new ConcurrentHashMap<>())
|
||||
.computeIfAbsent(targetMimetype, k -> new ArrayList<>())
|
||||
.add(transform);
|
||||
coreVersions.put(transformerName, coreVersion == null ? "" : coreVersion);
|
||||
transformCount++;
|
||||
}
|
||||
|
||||
public Map<String, List<SupportedTransform>> retrieveTransforms(final String sourceMimetype)
|
||||
{
|
||||
return transforms.getOrDefault(sourceMimetype, emptyMap());
|
||||
}
|
||||
|
||||
public Map<String, Map<String, List<SupportedTransform>>> getTransforms()
|
||||
{
|
||||
return transforms;
|
||||
}
|
||||
|
||||
public void cache(final String transformerName, final String sourceMimetype,
|
||||
final List<SupportedTransform> transformListBySize)
|
||||
{
|
||||
cachedSupportedTransformList
|
||||
.get(transformerName)
|
||||
.put(sourceMimetype, transformListBySize);
|
||||
}
|
||||
|
||||
public List<SupportedTransform> retrieveCached(final String transformerName,
|
||||
final String sourceMimetype)
|
||||
{
|
||||
return cachedSupportedTransformList
|
||||
.computeIfAbsent(transformerName, k -> new ConcurrentHashMap<>())
|
||||
.get(sourceMimetype);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return transformerCount == 0 && transformCount == 0
|
||||
? ""
|
||||
: "(transformers: " + transformerCount + " transforms: " + transformCount + ")";
|
||||
}
|
||||
|
||||
public String getCoreVersion(String transformerName)
|
||||
{
|
||||
String coreVersion = coreVersions.get(transformerName);
|
||||
return coreVersion.isBlank() ? null : coreVersion;
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,370 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Transform Model
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2019 Alfresco Software Limited
|
||||
* %%
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 General Lesser Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Lesser Public
|
||||
* License along with this program. If not, see
|
||||
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.transform.client.registry;
|
||||
|
||||
import static java.util.Collections.emptyList;
|
||||
import static java.util.Collections.emptyMap;
|
||||
import static java.util.Collections.emptySet;
|
||||
import static java.util.Map.Entry;
|
||||
import static java.util.stream.Collectors.toMap;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.alfresco.transform.client.model.config.TransformOption;
|
||||
import org.alfresco.transform.client.model.config.TransformOptionGroup;
|
||||
import org.alfresco.transform.client.model.config.TransformOptionValue;
|
||||
import org.alfresco.transform.exceptions.TransformException;
|
||||
|
||||
class TransformRegistryHelper
|
||||
{
|
||||
private static final String TIMEOUT = "timeout";
|
||||
|
||||
static Set<TransformOption> lookupTransformOptions(final Set<String> transformOptionNames,
|
||||
final Map<String, Set<TransformOption>> transformOptions, final String readFrom,
|
||||
final Consumer<String> logError)
|
||||
{
|
||||
if (transformOptionNames == null)
|
||||
{
|
||||
return emptySet();
|
||||
}
|
||||
|
||||
final Set<TransformOption> options = new HashSet<>();
|
||||
for (String name : transformOptionNames)
|
||||
{
|
||||
final Set<TransformOption> oneSetOfTransformOptions = transformOptions.get(name);
|
||||
if (oneSetOfTransformOptions == null)
|
||||
{
|
||||
logError.accept("transformOptions in " + readFrom + " with the name " + name +
|
||||
" does not exist. Ignored");
|
||||
continue;
|
||||
}
|
||||
options.add(new TransformOptionGroup(false, oneSetOfTransformOptions));
|
||||
}
|
||||
|
||||
return options.size() == 1 ?
|
||||
((TransformOptionGroup) options.iterator().next()).getTransformOptions() :
|
||||
options;
|
||||
}
|
||||
|
||||
// Returns transformers in increasing supported size order, where lower priority transformers for the same size have
|
||||
// been discarded.
|
||||
static List<SupportedTransform> retrieveTransformListBySize(final TransformCache data,
|
||||
final String sourceMimetype, final String targetMimetype,
|
||||
Map<String, String> actualOptions, String transformerName)
|
||||
{
|
||||
if (actualOptions == null)
|
||||
{
|
||||
actualOptions = emptyMap();
|
||||
}
|
||||
if (transformerName != null && transformerName.trim().isEmpty())
|
||||
{
|
||||
transformerName = null;
|
||||
}
|
||||
|
||||
final List<SupportedTransform> cachedTransformList =
|
||||
transformerName == null ? null :
|
||||
data.retrieveCached(transformerName, sourceMimetype);
|
||||
if (cachedTransformList != null)
|
||||
{
|
||||
return cachedTransformList;
|
||||
}
|
||||
|
||||
final List<SupportedTransform> builtTransformList = buildTransformList(data,
|
||||
sourceMimetype,
|
||||
targetMimetype,
|
||||
filterTimeout(actualOptions));
|
||||
|
||||
if (transformerName != null)
|
||||
{
|
||||
data.cache(transformerName, sourceMimetype, builtTransformList);
|
||||
}
|
||||
|
||||
return builtTransformList;
|
||||
}
|
||||
|
||||
private static List<SupportedTransform> buildTransformList(
|
||||
final TransformCache data, final String sourceMimetype, final String targetMimetype,
|
||||
final Map<String, String> actualOptions)
|
||||
{
|
||||
|
||||
if(sourceMimetype == null)
|
||||
{
|
||||
throw new TransformException(400, "Null value provided for sourceMimetype, please provide a value");
|
||||
}
|
||||
|
||||
if(targetMimetype == null)
|
||||
{
|
||||
throw new TransformException(400, "Null value provided for tragetMimetype, please provide a value");
|
||||
}
|
||||
|
||||
final Map<String, List<SupportedTransform>> targetMap = data.retrieveTransforms(
|
||||
sourceMimetype);
|
||||
|
||||
final List<SupportedTransform> supportedTransformList = targetMap.getOrDefault(
|
||||
targetMimetype, emptyList());
|
||||
|
||||
final List<SupportedTransform> transformListBySize = new ArrayList<>();
|
||||
|
||||
for (SupportedTransform supportedTransform : supportedTransformList)
|
||||
{
|
||||
final Map<String, Boolean> possibleTransformOptions = gatherPossibleTransformOptions(
|
||||
supportedTransform.getTransformOptions(), actualOptions);
|
||||
|
||||
if (optionsMatch(possibleTransformOptions, actualOptions))
|
||||
{
|
||||
addToSupportedTransformList(transformListBySize, supportedTransform);
|
||||
}
|
||||
}
|
||||
return transformListBySize;
|
||||
}
|
||||
|
||||
// Add newTransform to the transformListBySize in increasing size order and discards
|
||||
// lower priority (numerically higher) transforms with a smaller or equal size.
|
||||
private static void addToSupportedTransformList(
|
||||
final List<SupportedTransform> transformListBySize,
|
||||
final SupportedTransform newTransform)
|
||||
{
|
||||
if (transformListBySize.isEmpty())
|
||||
{
|
||||
transformListBySize.add(newTransform);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < transformListBySize.size(); i++)
|
||||
{
|
||||
final SupportedTransform existingTransform = transformListBySize.get(i);
|
||||
final int compareMaxSize = compareMaxSize(newTransform.getMaxSourceSizeBytes(),
|
||||
existingTransform.getMaxSourceSizeBytes());
|
||||
final int comparePriority = existingTransform.getPriority() - newTransform.getPriority();
|
||||
|
||||
if (compareMaxSize == 0)
|
||||
{
|
||||
if (comparePriority == 0)
|
||||
{
|
||||
// If same priority and size limit, replace with the newer transform.
|
||||
// It is possibly a replacement in an extension.
|
||||
transformListBySize.set(i, newTransform);
|
||||
break;
|
||||
}
|
||||
else if (comparePriority > 0)
|
||||
{
|
||||
// Replace as newer one is higher priority and try to discard some existing ones.
|
||||
transformListBySize.set(i, newTransform);
|
||||
discardFromSupportedTransformList(transformListBySize, i);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Ignore as lower priority
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (compareMaxSize < 0)
|
||||
{
|
||||
if (comparePriority > 0)
|
||||
{
|
||||
// If higher priority insert and try to discard some existing ones.
|
||||
transformListBySize.add(i, newTransform);
|
||||
discardFromSupportedTransformList(transformListBySize, i);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Ignore the newer one as its priority is lower or the same as one that has a higher size limit
|
||||
break;
|
||||
}
|
||||
}
|
||||
else // if (compareMaxSize > 0)
|
||||
{
|
||||
if (comparePriority < 0)
|
||||
{
|
||||
if (i+1 < transformListBySize.size())
|
||||
{
|
||||
// Look at the next element as size is higher but the priority is lower.
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Append to the list as the size is higher but the priority is lower.
|
||||
transformListBySize.add(newTransform);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Else same or better priority and higher size limit, so replace with the newer transform and try
|
||||
// to discard some existing ones.
|
||||
transformListBySize.set(i, newTransform);
|
||||
discardFromSupportedTransformList(transformListBySize, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Starting at i+1, try to remove transforms that will not be used.
|
||||
private static void discardFromSupportedTransformList(List<SupportedTransform> transformListBySize, int i)
|
||||
{
|
||||
SupportedTransform newTransform = transformListBySize.get(i++);
|
||||
while (i < transformListBySize.size())
|
||||
{
|
||||
final SupportedTransform existingTransform = transformListBySize.get(i);
|
||||
final int compareMaxSize = compareMaxSize(newTransform.getMaxSourceSizeBytes(),
|
||||
existingTransform.getMaxSourceSizeBytes());
|
||||
final int comparePriority = existingTransform.getPriority() - newTransform.getPriority();
|
||||
|
||||
// Discard those with
|
||||
// 1) the same priority but support a smaller size
|
||||
// 2) those with a lower priority and a smaller size
|
||||
if ((comparePriority == 0 && compareMaxSize >= 0) ||
|
||||
(comparePriority > 0 && compareMaxSize >= 0))
|
||||
{
|
||||
transformListBySize.remove(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Map<String, Boolean> gatherPossibleTransformOptions(
|
||||
final TransformOptionGroup transformOptionGroup, final Map<String, String> actualOptions)
|
||||
{
|
||||
final Map<String, Boolean> possibleTransformOptions = new HashMap<>();
|
||||
addToPossibleTransformOptions(possibleTransformOptions, transformOptionGroup, true,
|
||||
actualOptions);
|
||||
return possibleTransformOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flatten out the transform options by adding them to the supplied possibleTransformOptions.</p>
|
||||
*
|
||||
* If possible discards options in the supplied transformOptionGroup if the group is optional and the actualOptions
|
||||
* don't provide any of the options in the group. Or to put it another way:<p/>
|
||||
*
|
||||
* It adds individual transform options from the transformOptionGroup to possibleTransformOptions if the group is
|
||||
* required or if the actualOptions include individual options from the group. As a result it is possible that none
|
||||
* of the group are added if it is optional. It is also possible to add individual transform options that are
|
||||
* themselves required but not in the actualOptions. In this the optionsMatch method will return false.
|
||||
*
|
||||
* @return true if any options were added. Used by nested call parents to determine if an option was added from a
|
||||
* nested sub group.
|
||||
*/
|
||||
static boolean addToPossibleTransformOptions(
|
||||
final Map<String, Boolean> possibleTransformOptions,
|
||||
final TransformOptionGroup transformOptionGroup, final Boolean parentGroupRequired,
|
||||
final Map<String, String> actualOptions)
|
||||
{
|
||||
boolean added = false;
|
||||
boolean required = false;
|
||||
|
||||
final Set<TransformOption> optionList = transformOptionGroup.getTransformOptions();
|
||||
if (optionList != null && !optionList.isEmpty())
|
||||
{
|
||||
// We need to avoid adding options from a group that is required but its parents are not.
|
||||
boolean transformOptionGroupRequired = transformOptionGroup.isRequired() && parentGroupRequired;
|
||||
|
||||
// Check if the group contains options in actualOptions. This will add any options from sub groups.
|
||||
for (final TransformOption transformOption : optionList)
|
||||
{
|
||||
if (transformOption instanceof TransformOptionGroup)
|
||||
{
|
||||
added = addToPossibleTransformOptions(possibleTransformOptions,
|
||||
(TransformOptionGroup) transformOption, transformOptionGroupRequired,
|
||||
actualOptions);
|
||||
required |= added;
|
||||
}
|
||||
else
|
||||
{
|
||||
final String name = ((TransformOptionValue) transformOption).getName();
|
||||
if (actualOptions.containsKey(name))
|
||||
{
|
||||
required = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (required || transformOptionGroupRequired)
|
||||
{
|
||||
for (TransformOption transformOption : optionList)
|
||||
{
|
||||
if (transformOption instanceof TransformOptionValue)
|
||||
{
|
||||
added = true;
|
||||
final TransformOptionValue option = (TransformOptionValue) transformOption;
|
||||
possibleTransformOptions.put(option.getName(), option.isRequired());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return added;
|
||||
}
|
||||
|
||||
// compare where -1 is unlimited.
|
||||
private static int compareMaxSize(final long a, final long b)
|
||||
{
|
||||
return a == -1 ? b == -1 ? 0 : 1 : b == -1 ? -1 : Long.compare(a, b);
|
||||
}
|
||||
|
||||
static boolean optionsMatch(final Map<String, Boolean> transformOptions,
|
||||
final Map<String, String> actualOptions)
|
||||
{
|
||||
// Check all required transformOptions are supplied
|
||||
final boolean supported = transformOptions
|
||||
.entrySet()
|
||||
.stream()
|
||||
.filter(Entry::getValue)// filter by the required status
|
||||
.map(Entry::getKey)// map to the option name
|
||||
.allMatch(actualOptions::containsKey);
|
||||
|
||||
if (!supported)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check there are no extra unused actualOptions
|
||||
return actualOptions
|
||||
.keySet()
|
||||
.stream()
|
||||
.allMatch(transformOptions::containsKey);
|
||||
}
|
||||
|
||||
private static Map<String, String> filterTimeout(final Map<String, String> options)
|
||||
{
|
||||
// Remove the "timeout" property from the actualOptions as it is not used to select a transformer.
|
||||
if (!options.containsKey(TIMEOUT))
|
||||
{
|
||||
return options;
|
||||
}
|
||||
return options
|
||||
.entrySet()
|
||||
.stream()
|
||||
.filter(e -> !TIMEOUT.equals(e.getKey()))
|
||||
.collect(toMap(Entry::getKey, Entry::getValue));
|
||||
}
|
||||
}
|
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Transform Model
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2022 Alfresco Software Limited
|
||||
* %%
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 General Lesser Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Lesser Public
|
||||
* License along with this program. If not, see
|
||||
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.transform.client.registry;
|
||||
|
||||
import org.alfresco.transform.client.model.config.CoreFunction;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Used by clients work out if a transformation is supported by a Transform Service.
|
||||
*/
|
||||
public interface TransformServiceRegistry
|
||||
{
|
||||
/**
|
||||
* Works out if the Transform Server should be able to transform content of a given source mimetype and size into a
|
||||
* target mimetype given a list of actual transform option names and values (Strings) plus the data contained in the
|
||||
* Transformer objects registered with this class.
|
||||
*
|
||||
* @param sourceMimetype the mimetype of the source content
|
||||
* @param sourceSizeInBytes the size in bytes of the source content. Ignored if negative.
|
||||
* @param targetMimetype the mimetype of the target
|
||||
* @param actualOptions the actual name value pairs available that could be passed to the Transform Service.
|
||||
* @param transformName (optional) name for the set of options and target mimetype. If supplied is used to cache
|
||||
* results to avoid having to work out if a given transformation is supported a second time.
|
||||
* The sourceMimetype and sourceSizeInBytes may still change. In the case of ACS this is the
|
||||
* rendition name.
|
||||
* @return {@code}true{@code} if it is supported.
|
||||
*/
|
||||
default boolean isSupported(final String sourceMimetype, final long sourceSizeInBytes,
|
||||
final String targetMimetype, final Map<String, String> actualOptions,
|
||||
final String transformName)
|
||||
{
|
||||
long maxSize = findMaxSize(sourceMimetype, targetMimetype, actualOptions, transformName);
|
||||
return maxSize != 0 && (maxSize == -1L || maxSize >= sourceSizeInBytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximun size (in bytes) of the source content that can be transformed.
|
||||
*
|
||||
* @param sourceMimetype the mimetype of the source content
|
||||
* @param targetMimetype the mimetype of the target
|
||||
* @param actualOptions the actual name value pairs available that could be passed to the Transform Service.
|
||||
* @param transformName (optional) name for the set of options and target mimetype. If supplied is used to cache
|
||||
* results to avoid having to work out if a given transformation is supported a second time.
|
||||
* The sourceMimetype and sourceSizeInBytes may still change. In the case of ACS this is the
|
||||
* rendition name.
|
||||
* @return the maximum size (in bytes) of the source content that can be transformed. If {@code -1} there is no
|
||||
* limit, but if {@code 0} the transform is not supported.
|
||||
*/
|
||||
long findMaxSize(String sourceMimetype, String targetMimetype, Map<String, String> actualOptions,
|
||||
String transformName);
|
||||
|
||||
/**
|
||||
* Works out the name of the transformer (might not map to an actual transformer) that will be used to transform
|
||||
* content of a given source mimetype and size into a target mimetype given a list of actual transform option names
|
||||
* and values (Strings) plus the data contained in the Transformer objects registered with this class.
|
||||
*
|
||||
* @param sourceMimetype the mimetype of the source content
|
||||
* @param sourceSizeInBytes the size in bytes of the source content. Ignored if negative.
|
||||
* @param targetMimetype the mimetype of the target
|
||||
* @param actualOptions the actual name value pairs available that could be passed to the Transform Service.
|
||||
* @param renditionName (optional) name for the set of options and target mimetype. If supplied is used to cache
|
||||
* results to avoid having to work out if a given transformation is supported a second time.
|
||||
* The sourceMimetype and sourceSizeInBytes may still change. In the case of ACS this is the
|
||||
* rendition name.
|
||||
* @return the name of the transformer or {@code}null{@code} if not set or there is no supported transformer.
|
||||
*/
|
||||
String findTransformerName(String sourceMimetype, long sourceSizeInBytes, String targetMimetype,
|
||||
Map<String, String> actualOptions, String renditionName);
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the {@code function} is supported by the named transformer. Not all transformers are
|
||||
* able to support all functionality, as newer features may have been introduced into the core t-engine code since
|
||||
* it was released. Normally used in conjunction with {@link #findTransformerName(String, long, String, Map, String)}
|
||||
* rather than {@link #isSupported(String, long, String, Map, String)}.
|
||||
* @param function to be checked.
|
||||
* @param transformerName name of the transformer.
|
||||
* @return {@code true} is supported, {@code false} otherwise.
|
||||
*/
|
||||
default boolean isSupported(CoreFunction function, String transformerName)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Transform Model
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2021 Alfresco Software Limited
|
||||
* %%
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 General Lesser Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Lesser Public
|
||||
* License along with this program. If not, see
|
||||
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.transform.client.registry;
|
||||
|
||||
import org.alfresco.transform.client.model.config.OverrideSupported;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Key based using {@code transformerName} and {@code sourceMediaType} used as a key to lookup default values held in
|
||||
* {@link OverrideSupported} objects.
|
||||
*/
|
||||
class TransformerAndSourceType
|
||||
{
|
||||
private String transformerName;
|
||||
private String sourceMediaType;
|
||||
|
||||
public TransformerAndSourceType(String transformerName, String sourceMediaType)
|
||||
{
|
||||
this.transformerName = transformerName;
|
||||
this.sourceMediaType = sourceMediaType;
|
||||
}
|
||||
|
||||
public void setTransformerName(String transformerName)
|
||||
{
|
||||
this.transformerName = transformerName;
|
||||
}
|
||||
|
||||
public void setSourceMediaType(String sourceMediaType)
|
||||
{
|
||||
this.sourceMediaType = sourceMediaType;
|
||||
}
|
||||
|
||||
public String getTransformerName()
|
||||
{
|
||||
return transformerName;
|
||||
}
|
||||
|
||||
public String getSourceMediaType()
|
||||
{
|
||||
return sourceMediaType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
if (this == o)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
TransformerAndSourceType that = (TransformerAndSourceType)o;
|
||||
return Objects.equals(transformerName, that.transformerName) &&
|
||||
Objects.equals(sourceMediaType, that.sourceMediaType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return Objects.hash(transformerName, sourceMediaType);
|
||||
}
|
||||
}
|
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Transform Model
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2022 Alfresco Software Limited
|
||||
* %%
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 General Lesser Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Lesser Public
|
||||
* License along with this program. If not, see
|
||||
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.transform.client.util;
|
||||
|
||||
import org.alfresco.transform.client.model.config.CoreVersionDecorator;
|
||||
|
||||
/**
|
||||
* Request parameters and transform options used in the core transformers.
|
||||
*/
|
||||
public interface RequestParamMap
|
||||
{
|
||||
// Transform options used in the core transformers.
|
||||
String SOURCE_ENCODING = "sourceEncoding";
|
||||
String TARGET_ENCODING = "targetEncoding";
|
||||
String PAGE_REQUEST_PARAM = "page";
|
||||
String WIDTH_REQUEST_PARAM = "width";
|
||||
String HEIGHT_REQUEST_PARAM = "height";
|
||||
String ALLOW_PDF_ENLARGEMENT = "allowPdfEnlargement";
|
||||
String MAINTAIN_PDF_ASPECT_RATIO = "maintainPdfAspectRatio";
|
||||
String START_PAGE = "startPage";
|
||||
String END_PAGE = "endPage";
|
||||
String ALPHA_REMOVE = "alphaRemove";
|
||||
String AUTO_ORIENT = "autoOrient";
|
||||
String CROP_GRAVITY = "cropGravity";
|
||||
String CROP_WIDTH = "cropWidth";
|
||||
String CROP_HEIGHT = "cropHeight";
|
||||
String CROP_PERCENTAGE = "cropPercentage";
|
||||
String CROP_X_OFFSET = "cropXOffset";
|
||||
String CROP_Y_OFFSET = "cropYOffset";
|
||||
String THUMBNAIL = "thumbnail";
|
||||
String RESIZE_WIDTH = "resizeWidth";
|
||||
String RESIZE_HEIGHT = "resizeHeight";
|
||||
String RESIZE_PERCENTAGE = "resizePercentage";
|
||||
String ALLOW_ENLARGEMENT = "allowEnlargement";
|
||||
String MAINTAIN_ASPECT_RATIO = "maintainAspectRatio";
|
||||
String COMMAND_OPTIONS = "commandOptions";
|
||||
String TIMEOUT = "timeout";
|
||||
String INCLUDE_CONTENTS = "includeContents";
|
||||
String NOT_EXTRACT_BOOKMARKS_TEXT = "notExtractBookmarksText";
|
||||
String PAGE_LIMIT = "pageLimit";
|
||||
|
||||
// Parameters interpreted by the AbstractTransformerController
|
||||
String DIRECT_ACCESS_URL = "directAccessUrl";
|
||||
|
||||
// An optional parameter (defaults to 1) to be included in the request to the t-engine {@code /transform/config}
|
||||
// endpoint to specify what version (of the schema) to return. Provides the flexibility to introduce changes
|
||||
// without getting deserialization issues when we have components at different versions.
|
||||
String CONFIG_VERSION = "configVersion";
|
||||
String CONFIG_VERSION_DEFAULT = "1";
|
||||
int CONFIG_VERSION_LATEST = CoreVersionDecorator.CONFIG_VERSION_INCLUDES_CORE_VERSION;
|
||||
|
||||
// Endpoints
|
||||
String ENDPOINT_TRANSFORM = "/transform";
|
||||
String ENDPOINT_TRANSFORM_CONFIG = "/transform/config";
|
||||
String ENDPOINT_TRANSFORM_CONFIG_LATEST = ENDPOINT_TRANSFORM_CONFIG + "?" + CONFIG_VERSION + "=" + CONFIG_VERSION_LATEST;
|
||||
String ENDPOINT_TRANSFORM_LOG = "/log";
|
||||
String ENDPOINT_TRANSFORM_TEST = "/";
|
||||
}
|
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Transform Model
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
* %%
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 General Lesser Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Lesser Public
|
||||
* License along with this program. If not, see
|
||||
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.transform.exceptions;
|
||||
|
||||
public class TransformException extends RuntimeException
|
||||
{
|
||||
private final int statusCode;
|
||||
|
||||
public TransformException(int statusCode, String message)
|
||||
{
|
||||
super(message);
|
||||
this.statusCode = statusCode;
|
||||
}
|
||||
|
||||
public TransformException(int statusCode, String message, Throwable cause)
|
||||
{
|
||||
super(message, cause);
|
||||
this.statusCode = statusCode;
|
||||
}
|
||||
|
||||
public int getStatusCode()
|
||||
{
|
||||
return statusCode;
|
||||
}
|
||||
}
|
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Transform Model
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2022 Alfresco Software Limited
|
||||
* %%
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 General Lesser Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Lesser Public
|
||||
* License along with this program. If not, see
|
||||
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.transform.router;
|
||||
|
||||
import static org.alfresco.transform.client.model.Mimetype.MIMETYPE_DITA;
|
||||
import static org.alfresco.transform.client.model.Mimetype.MIMETYPE_EXCEL;
|
||||
import static org.alfresco.transform.client.model.Mimetype.MIMETYPE_IMAGE_SVG;
|
||||
import static org.alfresco.transform.client.model.Mimetype.MIMETYPE_OPENDOCUMENT_GRAPHICS;
|
||||
import static org.alfresco.transform.client.model.Mimetype.MIMETYPE_OPENDOCUMENT_PRESENTATION;
|
||||
import static org.alfresco.transform.client.model.Mimetype.MIMETYPE_OPENDOCUMENT_PRESENTATION_TEMPLATE;
|
||||
import static org.alfresco.transform.client.model.Mimetype.MIMETYPE_OPENDOCUMENT_SPREADSHEET;
|
||||
import static org.alfresco.transform.client.model.Mimetype.MIMETYPE_OPENDOCUMENT_SPREADSHEET_TEMPLATE;
|
||||
import static org.alfresco.transform.client.model.Mimetype.MIMETYPE_OPENDOCUMENT_TEXT;
|
||||
import static org.alfresco.transform.client.model.Mimetype.MIMETYPE_OPENDOCUMENT_TEXT_TEMPLATE;
|
||||
import static org.alfresco.transform.client.model.Mimetype.MIMETYPE_OPENOFFICE1_CALC;
|
||||
import static org.alfresco.transform.client.model.Mimetype.MIMETYPE_OPENOFFICE1_IMPRESS;
|
||||
import static org.alfresco.transform.client.model.Mimetype.MIMETYPE_OPENOFFICE1_WRITER;
|
||||
import static org.alfresco.transform.client.model.Mimetype.MIMETYPE_OPENXML_PRESENTATION;
|
||||
import static org.alfresco.transform.client.model.Mimetype.MIMETYPE_OPENXML_PRESENTATION_ADDIN;
|
||||
import static org.alfresco.transform.client.model.Mimetype.MIMETYPE_OPENXML_PRESENTATION_MACRO;
|
||||
import static org.alfresco.transform.client.model.Mimetype.MIMETYPE_OPENXML_PRESENTATION_SLIDE;
|
||||
import static org.alfresco.transform.client.model.Mimetype.MIMETYPE_OPENXML_PRESENTATION_SLIDESHOW;
|
||||
import static org.alfresco.transform.client.model.Mimetype.MIMETYPE_OPENXML_PRESENTATION_SLIDE_MACRO;
|
||||
import static org.alfresco.transform.client.model.Mimetype.MIMETYPE_OPENXML_PRESENTATION_TEMPLATE;
|
||||
import static org.alfresco.transform.client.model.Mimetype.MIMETYPE_OPENXML_PRESENTATION_TEMPLATE_MACRO;
|
||||
import static org.alfresco.transform.client.model.Mimetype.MIMETYPE_OPENXML_SPREADSHEET;
|
||||
import static org.alfresco.transform.client.model.Mimetype.MIMETYPE_OPENXML_SPREADSHEET_BINARY_MACRO;
|
||||
import static org.alfresco.transform.client.model.Mimetype.MIMETYPE_OPENXML_SPREADSHEET_MACRO;
|
||||
import static org.alfresco.transform.client.model.Mimetype.MIMETYPE_OPENXML_SPREADSHEET_TEMPLATE;
|
||||
import static org.alfresco.transform.client.model.Mimetype.MIMETYPE_OPENXML_SPREADSHEET_TEMPLATE_MACRO;
|
||||
import static org.alfresco.transform.client.model.Mimetype.MIMETYPE_OPENXML_WORDPROCESSING;
|
||||
import static org.alfresco.transform.client.model.Mimetype.MIMETYPE_OPENXML_WORDPROCESSING_MACRO;
|
||||
import static org.alfresco.transform.client.model.Mimetype.MIMETYPE_OPENXML_WORD_TEMPLATE;
|
||||
import static org.alfresco.transform.client.model.Mimetype.MIMETYPE_OPENXML_WORD_TEMPLATE_MACRO;
|
||||
import static org.alfresco.transform.client.model.Mimetype.MIMETYPE_OUTLOOK_MSG;
|
||||
import static org.alfresco.transform.client.model.Mimetype.MIMETYPE_PPT;
|
||||
import static org.alfresco.transform.client.model.Mimetype.MIMETYPE_VISIO;
|
||||
import static org.alfresco.transform.client.model.Mimetype.MIMETYPE_VISIO_2013;
|
||||
import static org.alfresco.transform.client.model.Mimetype.MIMETYPE_WORD;
|
||||
import static org.alfresco.transform.client.model.Mimetype.MIMETYPE_WORDPERFECT;
|
||||
import static org.alfresco.transform.client.model.Mimetype.MIMETYPE_TEXT_PLAIN;
|
||||
import static org.alfresco.transform.router.TransformerDebug.MIMETYPE_METADATA_EMBED;
|
||||
import static org.alfresco.transform.router.TransformerDebug.MIMETYPE_METADATA_EXTRACT;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Provides mapping between mimtypes and file extensions, static and not configurable.
|
||||
* The correct extension is required for a small subset of transforms in pipelines which go through the
|
||||
* libreoffice transformer
|
||||
*/
|
||||
public class ExtensionService
|
||||
{
|
||||
private final static String MIMETYPE_TAB_SEPARATED_VALUES="text/tab-separated-values";
|
||||
private final static String MIMETYPE_CALC_TEMPLATE="application/vnd.sun.xml.calc.template";
|
||||
private final static String MIMETYPE_IMPRESS_TEMPLATE="application/vnd.sun.xml.impress.template";
|
||||
private final static String MIMETYPE_WRITER_TEMPLATE="application/vnd.sun.xml.writer.template";
|
||||
|
||||
private static final Map<String,String> mimetpeExtensions = Map.ofEntries(
|
||||
Map.entry(MIMETYPE_WORD, "doc"),
|
||||
Map.entry(MIMETYPE_OPENXML_WORDPROCESSING_MACRO, "docm"),
|
||||
Map.entry(MIMETYPE_OPENXML_WORDPROCESSING, "docx"),
|
||||
Map.entry(MIMETYPE_OPENXML_WORD_TEMPLATE_MACRO, "dotm"),
|
||||
Map.entry(MIMETYPE_OPENXML_WORD_TEMPLATE, "dotx"),
|
||||
Map.entry(MIMETYPE_OPENDOCUMENT_GRAPHICS, "odg"),
|
||||
Map.entry(MIMETYPE_OPENDOCUMENT_PRESENTATION, "odp"),
|
||||
Map.entry(MIMETYPE_OPENDOCUMENT_PRESENTATION_TEMPLATE, "otp"),
|
||||
Map.entry(MIMETYPE_OPENDOCUMENT_SPREADSHEET, "ods"),
|
||||
Map.entry(MIMETYPE_OPENDOCUMENT_SPREADSHEET_TEMPLATE, "ots"),
|
||||
Map.entry(MIMETYPE_OPENDOCUMENT_TEXT, "odt"),
|
||||
Map.entry(MIMETYPE_OPENDOCUMENT_TEXT_TEMPLATE, "ott"),
|
||||
Map.entry(MIMETYPE_OPENXML_PRESENTATION_TEMPLATE_MACRO, "potm"),
|
||||
Map.entry(MIMETYPE_OPENXML_PRESENTATION_TEMPLATE, "potx"),
|
||||
Map.entry(MIMETYPE_OPENXML_PRESENTATION_ADDIN, "ppam"),
|
||||
Map.entry(MIMETYPE_PPT, "ppt"),
|
||||
Map.entry(MIMETYPE_OPENXML_PRESENTATION_MACRO, "pptm"),
|
||||
Map.entry(MIMETYPE_OPENXML_PRESENTATION, "pptx"),
|
||||
Map.entry(MIMETYPE_OPENXML_PRESENTATION_SLIDE_MACRO, "sldm"),
|
||||
Map.entry(MIMETYPE_OPENXML_PRESENTATION_SLIDE, "sldx"),
|
||||
Map.entry(MIMETYPE_CALC_TEMPLATE, "stc"),
|
||||
Map.entry(MIMETYPE_IMPRESS_TEMPLATE, "sti"),
|
||||
Map.entry(MIMETYPE_WRITER_TEMPLATE, "stw"),
|
||||
Map.entry(MIMETYPE_TAB_SEPARATED_VALUES, "tsv"),
|
||||
Map.entry(MIMETYPE_OPENOFFICE1_CALC, "sxc"),
|
||||
Map.entry(MIMETYPE_OPENOFFICE1_IMPRESS, "sxi"),
|
||||
Map.entry(MIMETYPE_OPENOFFICE1_WRITER, "sxw"),
|
||||
Map.entry(MIMETYPE_VISIO, "vsd"),
|
||||
Map.entry(MIMETYPE_VISIO_2013, "vsdx"),
|
||||
Map.entry(MIMETYPE_WORDPERFECT, "wp"),
|
||||
Map.entry(MIMETYPE_EXCEL, "xls"),
|
||||
Map.entry(MIMETYPE_OPENXML_SPREADSHEET_BINARY_MACRO, "xlsb"),
|
||||
Map.entry(MIMETYPE_OPENXML_SPREADSHEET_MACRO, "xlsm"),
|
||||
Map.entry(MIMETYPE_OPENXML_SPREADSHEET, "xlsx"),
|
||||
Map.entry(MIMETYPE_OPENXML_SPREADSHEET_TEMPLATE_MACRO, "xltm"),
|
||||
Map.entry(MIMETYPE_OPENXML_PRESENTATION_SLIDESHOW, "ppsx"),
|
||||
Map.entry(MIMETYPE_OUTLOOK_MSG, "msg"),
|
||||
Map.entry(MIMETYPE_DITA, "dita"),
|
||||
Map.entry(MIMETYPE_OPENXML_SPREADSHEET_TEMPLATE, "xltx"),
|
||||
Map.entry(MIMETYPE_IMAGE_SVG, "svg"),
|
||||
Map.entry(MIMETYPE_TEXT_PLAIN, "txt")
|
||||
);
|
||||
|
||||
public static String getExtensionForTargetMimetype(String targetMimetype, String sourceMimetype)
|
||||
{
|
||||
if (targetMimetype == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return getExtensionForMimetype(MIMETYPE_METADATA_EMBED.equals(targetMimetype) ? sourceMimetype : targetMimetype);
|
||||
}
|
||||
|
||||
public static String getExtensionForMimetype(String mimetype)
|
||||
{
|
||||
if (mimetype == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (mimetpeExtensions.containsKey(mimetype))
|
||||
{
|
||||
return mimetpeExtensions.get(mimetype);
|
||||
}
|
||||
if (MIMETYPE_METADATA_EXTRACT.equals(mimetype))
|
||||
{
|
||||
return "json";
|
||||
}
|
||||
// else fall back to the original implementation
|
||||
return splitMimetype(mimetype);
|
||||
}
|
||||
|
||||
// Moved from Dispatcher. This fails to work in many cases, but we need to be backward compatible.
|
||||
private static String splitMimetype(final String mimetype)
|
||||
{
|
||||
final String[] parts = mimetype.split("[.\\-_|/]");
|
||||
return parts[parts.length - 1];
|
||||
}
|
||||
}
|
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Transform Model
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2022 Alfresco Software Limited
|
||||
* %%
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 General Lesser Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Lesser Public
|
||||
* License along with this program. If not, see
|
||||
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.transform.router;
|
||||
|
||||
import java.util.StringJoiner;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* The client data supplied and echoed back to content repository (the client). May be modified to include
|
||||
* TransformerDebug.
|
||||
*/
|
||||
class RepositoryClientData
|
||||
{
|
||||
private static final String CLIENT_DATA_SEPARATOR = "\u23D0";
|
||||
public static final String DEBUG_SEPARATOR = "\u23D1";
|
||||
|
||||
private static final String REPO_ID = "Repo";
|
||||
private static final String DEBUG = "debug:";
|
||||
|
||||
private final String[] split;
|
||||
|
||||
public RepositoryClientData(String clientData)
|
||||
{
|
||||
split = clientData == null ? null : clientData.split(CLIENT_DATA_SEPARATOR);
|
||||
}
|
||||
|
||||
private boolean isRepositoryClientData()
|
||||
{
|
||||
return split != null && split.length == 10 && split[0].startsWith(REPO_ID);
|
||||
}
|
||||
|
||||
public String getAcsVersion()
|
||||
{
|
||||
return isRepositoryClientData() ? split[0].substring(REPO_ID.length()) : "";
|
||||
}
|
||||
|
||||
public int getRequestId()
|
||||
{
|
||||
try
|
||||
{
|
||||
return isRepositoryClientData() ? Integer.parseInt(split[6]) : -1;
|
||||
}
|
||||
catch (NumberFormatException e)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public String getRenditionName()
|
||||
{
|
||||
return isRepositoryClientData() ? split[2] : "";
|
||||
}
|
||||
|
||||
public void appendDebug(String message)
|
||||
{
|
||||
if (isDebugRequested())
|
||||
{
|
||||
split[9] += DEBUG_SEPARATOR+ message;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isDebugRequested()
|
||||
{
|
||||
return isRepositoryClientData() && split[9].startsWith(DEBUG);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
if (split == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
StringJoiner sj = new StringJoiner(CLIENT_DATA_SEPARATOR);
|
||||
Stream.of(split).forEach(element -> sj.add(element));
|
||||
return sj.toString();
|
||||
}
|
||||
}
|
@@ -0,0 +1,546 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Transform Model
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2022 Alfresco Software Limited
|
||||
* %%
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 General Lesser Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Lesser Public
|
||||
* License along with this program. If not, see
|
||||
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.transform.router;
|
||||
|
||||
import org.alfresco.transform.client.model.InternalContext;
|
||||
import org.alfresco.transform.client.model.TransformReply;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.StringJoiner;
|
||||
|
||||
/**
|
||||
* Represents the current state of a top level transform request in terms of its current nested call stack, which is
|
||||
* the current transform step being performed and what other transform steps are still to be executed in the current
|
||||
* level. This information is encoded in the {@link org.alfresco.transform.client.model.MultiStep} structure of the
|
||||
* internal context passed between T-Router and T-Engines. Ideally we would have changed the structure,
|
||||
* but for backward compatibility we are using the existing structure, which allows T-Engines that were developed
|
||||
* previously to be used unchanged.<p><br/>
|
||||
*
|
||||
* Originally the T-Router only allowed pipeline and single step transforms, so it was possible to represent them as a
|
||||
* flat list. However the original design was of a nested structure. Pipelines are just one example, with failover
|
||||
* transforms being the other. To bring the T-Router up to the same level of functionality as the Repository, it too
|
||||
* needs to support nested transforms. <p><br/>
|
||||
*
|
||||
* <li>@{code transformsToBeDone[0]} holds the original Transformer Request Options as a list of key values pairs.
|
||||
* Needed so that we don't lose values as we walk down the individual transform steps</li>
|
||||
* <li>@{code transformsToBeDone[1]} holds the original source reference so that we don't delete the original source
|
||||
* until the whole transform is known to be successful, so that a queue entry may be retried on failure.</li>
|
||||
* <li>@{code transformsToBeDone[2]} holds information about the top level transform</li>
|
||||
* <li>@{code transformsToBeDone[size()-1]} holds information about the most nested transform being processed</li>
|
||||
* <li>Each level contains a list of step transforms. Just one for a singe step transform or a list for pipeline and
|
||||
* failover transforms</li>
|
||||
* <li>When a step is processed it will result in the creation of another level if it is a pipeline or failover
|
||||
* transform</li>
|
||||
* <li>As steps are completed, they are removed</li>
|
||||
* <li>When there are no steps left in a level the level is removed</li>
|
||||
*
|
||||
* Each level is represented by a String with a pipeline or failover flag @{code 'P'|'F'} followed by a step counter
|
||||
* and start time used in debug, a retry count and a sequence of transform steps. Each step is made up of three parts:
|
||||
* @{code<transformerName>|<sourceMimetype>|<targetMimetype> . All fields are separated by a @code{'\u23D0'} character.
|
||||
* The last step in the sequence is the current transform being performed. The top level transform is a pipeline of
|
||||
* one step. Although the source and target mimetypes are always the same for failover transforms, they use the same
|
||||
* structure.
|
||||
*/
|
||||
public class TransformStack
|
||||
{
|
||||
public static final String PIPELINE_FLAG = "P";
|
||||
public static final String FAILOVER_FLAG = "F";
|
||||
|
||||
static final String SEPARATOR = "\u23D0";
|
||||
private static final String SEPARATOR_REGEX = "\u23D0";
|
||||
|
||||
static final int OPTIONS_LEVEL = 0;
|
||||
static final int SOURCE_REFERENCE_LEVEL = 1;
|
||||
static final int TOP_STACK_LEVEL = 2;
|
||||
|
||||
private static final int FLAG_INDEX = 0;
|
||||
private static final int REFERENCE_INDEX = 1;
|
||||
private static final int START_INDEX = 2;
|
||||
private static final int RETRY_INDEX = 3;
|
||||
|
||||
private static final int FIELDS_IN_HEADER = 4; // flag | counter | retry
|
||||
private static final int FIELDS_PER_STEP = 3; // name | source | target
|
||||
|
||||
public static LevelBuilder levelBuilder(String flag)
|
||||
{
|
||||
return new LevelBuilder(flag);
|
||||
}
|
||||
|
||||
public static class LevelBuilder
|
||||
{
|
||||
private final ArrayList<String> reverseOrderStepElements = new ArrayList<>();
|
||||
private final String flag;
|
||||
|
||||
private LevelBuilder(String flag)
|
||||
{
|
||||
this.flag = flag;
|
||||
}
|
||||
|
||||
public LevelBuilder withStep(String transformerName, String sourceMediaType, String targetMediaType)
|
||||
{
|
||||
reverseOrderStepElements.add(targetMediaType);
|
||||
reverseOrderStepElements.add(sourceMediaType);
|
||||
reverseOrderStepElements.add(transformerName);
|
||||
return this;
|
||||
}
|
||||
|
||||
public String build()
|
||||
{
|
||||
StringJoiner stringJoiner = new StringJoiner(SEPARATOR);
|
||||
stringJoiner.add(flag);
|
||||
stringJoiner.add("1");
|
||||
stringJoiner.add("0");
|
||||
stringJoiner.add("0");
|
||||
for (int i=reverseOrderStepElements.size()-1; i>=0; i--)
|
||||
{
|
||||
stringJoiner.add(reverseOrderStepElements.get(i));
|
||||
}
|
||||
return stringJoiner.toString();
|
||||
}
|
||||
}
|
||||
|
||||
public static class Step
|
||||
{
|
||||
private final String[] step;
|
||||
|
||||
private Step(String stepWithSeparatedFields)
|
||||
{
|
||||
this.step = stepWithSeparatedFields.split(SEPARATOR_REGEX);
|
||||
}
|
||||
|
||||
public String getTransformerName()
|
||||
{
|
||||
return step[0];
|
||||
}
|
||||
|
||||
public String getSourceMediaType()
|
||||
{
|
||||
return step[1];
|
||||
}
|
||||
|
||||
public String getTargetMediaType()
|
||||
{
|
||||
return step[2];
|
||||
}
|
||||
}
|
||||
|
||||
public static void setInitialTransformRequestOptions(InternalContext internalContext,
|
||||
Map<String, String> transformRequestOptions)
|
||||
{
|
||||
init(internalContext);
|
||||
StringJoiner sj = new StringJoiner(SEPARATOR);
|
||||
transformRequestOptions.forEach((key,value)-> sj.add(key).add(value));
|
||||
levels(internalContext).set(OPTIONS_LEVEL, sj.toString());
|
||||
}
|
||||
|
||||
public static void setInitialSourceReference(InternalContext internalContext, String sourceReference)
|
||||
{
|
||||
init(internalContext);
|
||||
levels(internalContext).set(SOURCE_REFERENCE_LEVEL, sourceReference);
|
||||
}
|
||||
|
||||
public static Map<String, String> getInitialTransformRequestOptions(InternalContext internalContext)
|
||||
{
|
||||
Map<String, String> transformRequestOptions = new HashMap<>();
|
||||
|
||||
// To avoid the case where split() discards the last value, when it is a zero length string, we add and remove
|
||||
// a space. None of the keys or value may be null.
|
||||
String[] split = (level(internalContext, OPTIONS_LEVEL)+' ').split(SEPARATOR_REGEX);
|
||||
String lastValue = split[split.length - 1];
|
||||
split[split.length-1] = lastValue.substring(0, lastValue.length()-1);
|
||||
|
||||
for (int i = split.length-2; i >= 0; i-=2)
|
||||
{
|
||||
transformRequestOptions.put(split[i], split[i+1]);
|
||||
}
|
||||
return transformRequestOptions;
|
||||
}
|
||||
|
||||
public static String getInitialSourceReference(InternalContext internalContext)
|
||||
{
|
||||
return level(internalContext, SOURCE_REFERENCE_LEVEL);
|
||||
}
|
||||
|
||||
private static List<String> levels(InternalContext internalContext)
|
||||
{
|
||||
return internalContext.getMultiStep().getTransformsToBeDone();
|
||||
}
|
||||
|
||||
private static String level(InternalContext internalContext, int i)
|
||||
{
|
||||
return levels(internalContext).get(i);
|
||||
}
|
||||
|
||||
private static void init(InternalContext internalContext)
|
||||
{
|
||||
while(levels(internalContext).size() < TOP_STACK_LEVEL)
|
||||
{
|
||||
levels(internalContext).add(null);
|
||||
}
|
||||
}
|
||||
|
||||
private static String currentLevel(InternalContext internalContext)
|
||||
{
|
||||
return parentLevel(internalContext, 0);
|
||||
}
|
||||
|
||||
private static String parentLevel(InternalContext internalContext, int parentLevels)
|
||||
{
|
||||
List<String> levels = levels(internalContext);
|
||||
int i = levels.size() - 1 - parentLevels;
|
||||
return i >= TOP_STACK_LEVEL ? levels.get(i) : null;
|
||||
}
|
||||
|
||||
public static boolean isFinished(InternalContext internalContext)
|
||||
{
|
||||
|
||||
int levelsLeft = levels(internalContext).size() - TOP_STACK_LEVEL;
|
||||
return levelsLeft <= 0 || // there has been an error, so we have lost the stack
|
||||
levelsLeft == 1 && // on top level wrapper level
|
||||
isTransformLevelFinished(internalContext); // the one step has been processed (removed)
|
||||
|
||||
}
|
||||
|
||||
public static void addTransformLevel(InternalContext internalContext, LevelBuilder levelBuilder)
|
||||
{
|
||||
levels(internalContext).add(levelBuilder.build());
|
||||
}
|
||||
|
||||
public static void setReference(InternalContext internalContext, int requestCountOrClientRequestId)
|
||||
{
|
||||
setHeaderField(internalContext, REFERENCE_INDEX, requestCountOrClientRequestId);
|
||||
}
|
||||
|
||||
public static void incrementReference(InternalContext internalContext)
|
||||
{
|
||||
setHeaderField(internalContext, REFERENCE_INDEX, getReferenceCounter(internalContext)+1);
|
||||
}
|
||||
|
||||
public static void resetAttemptedRetries(InternalContext internalContext)
|
||||
{
|
||||
setHeaderField(internalContext, RETRY_INDEX, 0);
|
||||
}
|
||||
|
||||
public static void setStartTime(InternalContext internalContext)
|
||||
{
|
||||
setHeaderField(internalContext, START_INDEX, System.currentTimeMillis());
|
||||
}
|
||||
|
||||
public static void incrementAttemptedRetries(InternalContext internalContext)
|
||||
{
|
||||
setHeaderField(internalContext, RETRY_INDEX,getAttemptedRetries(internalContext)+1);
|
||||
}
|
||||
|
||||
private static void setHeaderField(InternalContext internalContext, int index, long value)
|
||||
{
|
||||
List<String> levels = levels(internalContext);
|
||||
int size = levels.size();
|
||||
String level = levels.get(size-1);
|
||||
int j = indexOfField(level, index);
|
||||
int k = level.indexOf(SEPARATOR, j+1);
|
||||
levels.set(size-1, level.substring(0, j) + value + level.substring(k));
|
||||
}
|
||||
|
||||
public static String getReference(InternalContext internalContext)
|
||||
{
|
||||
StringJoiner ref = new StringJoiner(".");
|
||||
List<String> levels = levels(internalContext);
|
||||
for (int i=TOP_STACK_LEVEL; i<levels.size(); i++)
|
||||
{
|
||||
ref.add(getHeaderField(levels.get(i), REFERENCE_INDEX).toString());
|
||||
}
|
||||
return ref.toString();
|
||||
}
|
||||
|
||||
public static void setReferenceInADummyTopLevelIfUnset(InternalContext internalContext, int reference)
|
||||
{
|
||||
if (reference != -1 && getReference(internalContext).isBlank() ) // When top transform level not set
|
||||
{
|
||||
init(internalContext);
|
||||
addTransformLevel(internalContext, levelBuilder(PIPELINE_FLAG));
|
||||
setReference(internalContext, reference);
|
||||
}
|
||||
}
|
||||
|
||||
public static long getElapsedTime(InternalContext internalContext)
|
||||
{
|
||||
return System.currentTimeMillis() - getHeaderField(internalContext, START_INDEX).longValue();
|
||||
}
|
||||
|
||||
private static int getReferenceCounter(InternalContext internalContext)
|
||||
{
|
||||
return getHeaderField(internalContext, REFERENCE_INDEX).intValue();
|
||||
}
|
||||
|
||||
public static int getAttemptedRetries(InternalContext internalContext)
|
||||
{
|
||||
return getHeaderField(internalContext, RETRY_INDEX).intValue();
|
||||
}
|
||||
|
||||
private static Long getHeaderField(InternalContext internalContext, int index)
|
||||
{
|
||||
return getHeaderField(currentLevel(internalContext), index);
|
||||
}
|
||||
|
||||
private static Long getHeaderField(String level, int index)
|
||||
{
|
||||
return Long.valueOf(level.split(SEPARATOR_REGEX)[index]);
|
||||
}
|
||||
|
||||
public static void removeTransformLevel(InternalContext internalContext)
|
||||
{
|
||||
List<String> levels = levels(internalContext);
|
||||
levels.remove(levels.size()-1);
|
||||
}
|
||||
|
||||
public static void removeRemainingTransformLevels(TransformReply reply, TransformerDebug transformerDebug)
|
||||
{
|
||||
List<String> levels = levels(reply.getInternalContext());
|
||||
if (levels != null)
|
||||
{
|
||||
while (!TransformStack.isFinished(reply.getInternalContext()))
|
||||
{
|
||||
removeFailedStep(reply, transformerDebug);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isParentAFailover(InternalContext internalContext)
|
||||
{
|
||||
String level = currentLevel(internalContext);
|
||||
return level != null && level.startsWith(FAILOVER_FLAG);
|
||||
}
|
||||
|
||||
public static String getParentName(InternalContext internalContext)
|
||||
{
|
||||
String level = parentLevel(internalContext, 1);
|
||||
return level == null ? null : new Step(level.substring(indexOfNextStep(level))).getTransformerName();
|
||||
}
|
||||
|
||||
public static Step currentStep(InternalContext internalContext)
|
||||
{
|
||||
String level = currentLevel(internalContext);
|
||||
return new Step(level.substring(indexOfNextStep(level)));
|
||||
}
|
||||
|
||||
public static boolean isLastStepInTransformLevel(InternalContext internalContext)
|
||||
{
|
||||
return getStepCount(internalContext) == 1;
|
||||
}
|
||||
|
||||
private static boolean isTransformLevelFinished(InternalContext internalContext)
|
||||
{
|
||||
return getStepCount(internalContext) == 0;
|
||||
}
|
||||
|
||||
private static int getStepCount(InternalContext internalContext)
|
||||
{
|
||||
return (StringUtils.countMatches(currentLevel(internalContext), SEPARATOR)+1-FIELDS_IN_HEADER)/FIELDS_PER_STEP;
|
||||
}
|
||||
|
||||
public static void removeSuccessfulStep(TransformReply reply, TransformerDebug transformerDebug)
|
||||
{
|
||||
removeFinishedSteps(reply, true, transformerDebug);
|
||||
}
|
||||
|
||||
public static void removeFailedStep(TransformReply reply, TransformerDebug transformerDebug)
|
||||
{
|
||||
removeFinishedSteps(reply, false, transformerDebug);
|
||||
}
|
||||
|
||||
private static void removeFinishedSteps(TransformReply reply, boolean successful,
|
||||
TransformerDebug transformerDebug)
|
||||
{
|
||||
TransformStack.removeStep(reply, successful, transformerDebug);
|
||||
|
||||
InternalContext internalContext = reply.getInternalContext();
|
||||
while (!TransformStack.isFinished(internalContext) &&
|
||||
TransformStack.isTransformLevelFinished(internalContext))
|
||||
{
|
||||
TransformStack.removeTransformLevel(internalContext);
|
||||
// We want to exit if removing steps for a failure and we have a parent that is a failover transform
|
||||
if (successful || !TransformStack.isParentAFailover(internalContext))
|
||||
{
|
||||
TransformStack.removeStep(reply, successful, transformerDebug);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void removeStep(TransformReply reply, boolean successful, TransformerDebug transformerDebug)
|
||||
{
|
||||
InternalContext internalContext = reply.getInternalContext();
|
||||
boolean parentAFailover = isParentAFailover(internalContext);
|
||||
boolean successfulFailoverStep = successful && parentAFailover;
|
||||
boolean unsuccessfulPipelineStep = !successful && !parentAFailover;
|
||||
|
||||
transformerDebug.popTransform(reply);
|
||||
|
||||
// For a successful failover step, or an unsuccessful pipeline step remove all sibling steps, otherwise just
|
||||
// remove one step as it was a successful pipeline step or an unsuccessful failover step
|
||||
List<String> levels = levels(internalContext);
|
||||
int size = levels.size();
|
||||
String level = levels.get(size-1);
|
||||
levels.set(size-1, level.substring(0,
|
||||
(successfulFailoverStep || unsuccessfulPipelineStep ? indexOfLastStep(level) : indexOfNextStep(level)) - 1));
|
||||
|
||||
if (!isTransformLevelFinished(internalContext))
|
||||
{
|
||||
TransformStack.incrementReference(internalContext);
|
||||
}
|
||||
}
|
||||
|
||||
private static int indexOfNextStep(String level)
|
||||
{
|
||||
int j = level.length()-1;
|
||||
for (int i = FIELDS_PER_STEP; i >= 1 && j > 0; i--)
|
||||
{
|
||||
j = level.lastIndexOf(SEPARATOR, j-1);
|
||||
}
|
||||
return j+1;
|
||||
}
|
||||
|
||||
private static int indexOfLastStep(String level)
|
||||
{
|
||||
return indexOfField(level, FIELDS_IN_HEADER);
|
||||
}
|
||||
|
||||
private static int indexOfField(String level, int n)
|
||||
{
|
||||
int j = 0;
|
||||
for (int i = n; i >= 1; i--)
|
||||
{
|
||||
j = level.indexOf(SEPARATOR, j+1);
|
||||
}
|
||||
return j+1;
|
||||
}
|
||||
|
||||
public static String checkStructure(InternalContext internalContext, String type)
|
||||
{
|
||||
// A null value will have been replaced with an empty array, so no need to check for that.
|
||||
String errorMessage = levels(internalContext).size() < (TOP_STACK_LEVEL + 1)
|
||||
? type+" InternalContext did not have the Stack set"
|
||||
: !validTransformOptions(internalContext)
|
||||
? type+" InternalContext did not have the TransformOptions set correctly"
|
||||
: levels(internalContext).size() == 1
|
||||
? type+" InternalContext levels were not set"
|
||||
: !validLevels(levels(internalContext))
|
||||
? type+" InternalContext did not have levels set correctly"
|
||||
: null;
|
||||
return errorMessage;
|
||||
}
|
||||
|
||||
private static boolean validTransformOptions(InternalContext internalContext)
|
||||
{
|
||||
String keysAndValues = level(internalContext, OPTIONS_LEVEL);
|
||||
if (keysAndValues == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if ("".equals(keysAndValues))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
String[] split = keysAndValues.split(SEPARATOR_REGEX);
|
||||
if (split.length%2 != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
for (int i = split.length-2; i >= 0; i-=2)
|
||||
{
|
||||
if (split[i].isEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean validLevels(List<String> levels)
|
||||
{
|
||||
for (int i=levels.size()-1; i >=TOP_STACK_LEVEL; i--)
|
||||
{
|
||||
String level = levels.get(i);
|
||||
if (!validLevel(level))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean validLevel(String level)
|
||||
{
|
||||
if (level == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
String[] split = level.split(SEPARATOR_REGEX);
|
||||
if (split.length < FIELDS_IN_HEADER+FIELDS_PER_STEP || // must be at least 1 step
|
||||
(split.length-FIELDS_IN_HEADER)%FIELDS_PER_STEP != 0 ||
|
||||
(!PIPELINE_FLAG.equals(split[FLAG_INDEX]) &&
|
||||
!FAILOVER_FLAG.equals(split[FLAG_INDEX])) ||
|
||||
!aPositiveInt(split[REFERENCE_INDEX]) ||
|
||||
!aPositiveLong(split[START_INDEX]) ||
|
||||
!aPositiveInt(split[RETRY_INDEX]))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i=split.length-1; i>=FIELDS_IN_HEADER; i--)
|
||||
{
|
||||
if (split[i].isBlank())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean aPositiveInt(String string)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Integer.valueOf(string).toString().equals(string) && Integer.valueOf(string) >= 0;
|
||||
}
|
||||
catch (NumberFormatException e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean aPositiveLong(String string)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Long.valueOf(string).toString().equals(string) && Long.valueOf(string) >= 0;
|
||||
}
|
||||
catch (NumberFormatException e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,345 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Transform Model
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2022 Alfresco Software Limited
|
||||
* %%
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 General Lesser Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Lesser Public
|
||||
* License along with this program. If not, see
|
||||
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.transform.router;
|
||||
|
||||
import org.alfresco.transform.client.model.InternalContext;
|
||||
import org.alfresco.transform.client.model.TransformReply;
|
||||
import org.alfresco.transform.client.model.TransformRequest;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Map;
|
||||
|
||||
public class TransformerDebug
|
||||
{
|
||||
public static final Logger logger = LoggerFactory.getLogger(TransformerDebug.class);
|
||||
|
||||
private static final int REFERENCE_SIZE = 15;
|
||||
|
||||
private static final String TRANSFORM_NAMESPACE = "transform:";
|
||||
|
||||
public static final String MIMETYPE_METADATA_EXTRACT = "alfresco-metadata-extract";
|
||||
|
||||
public static final String MIMETYPE_METADATA_EMBED = "alfresco-metadata-embed";
|
||||
|
||||
private static final String TIMEOUT = "timeout";
|
||||
|
||||
// For truncating long option values
|
||||
private static int MAX_OPTION_VALUE = 60;
|
||||
private static int MAX_OPTION_END_CHARS = 5;
|
||||
private static String MAX_OPTION_DOTS = "...";
|
||||
|
||||
private boolean isTEngine = false;
|
||||
|
||||
public void pushTransform(TransformRequest request)
|
||||
{
|
||||
RepositoryClientData repositoryClientData = new RepositoryClientData(request.getClientData());
|
||||
if (isEnabled(repositoryClientData))
|
||||
{
|
||||
TransformStack.Step step = TransformStack.currentStep(request.getInternalContext());
|
||||
String reference = TransformStack.getReference(request.getInternalContext());
|
||||
boolean isTopLevel = isTopLevel(reference);
|
||||
|
||||
String message = getPaddedReference(reference) +
|
||||
getMimetypeExt(step.getSourceMediaType()) +
|
||||
getTargetMimetypeExt(step.getTargetMediaType(), step.getSourceMediaType()) + ' ' +
|
||||
(isTopLevel || isTEngine()
|
||||
? fileSize(request.getSourceSize()) + ' ' +
|
||||
getRenditionName(new RepositoryClientData(request.getClientData()).getRenditionName())
|
||||
: "") +
|
||||
step.getTransformerName();
|
||||
if (isDebugToBeReturned(repositoryClientData))
|
||||
{
|
||||
repositoryClientData.appendDebug(message);
|
||||
request.setClientData(repositoryClientData.toString());
|
||||
}
|
||||
logger.debug(message);
|
||||
}
|
||||
}
|
||||
|
||||
public void pushTransform(String reference, String sourceMimetype, String targetMimetype, File sourceFile, String transformerName)
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
final long sourceSizeInBytes = sourceFile.length();
|
||||
String message = getPaddedReference(reference) +
|
||||
getMimetypeExt(sourceMimetype) +
|
||||
getTargetMimetypeExt(targetMimetype, sourceMimetype) + ' ' +
|
||||
fileSize(sourceSizeInBytes) + ' ' +
|
||||
transformerName;
|
||||
logger.debug(message);
|
||||
}
|
||||
}
|
||||
|
||||
public void popTransform(TransformReply reply)
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
InternalContext internalContext = reply.getInternalContext();
|
||||
String reference = TransformStack.getReference(internalContext);
|
||||
long elapsedTime = TransformStack.getElapsedTime(internalContext);
|
||||
|
||||
String message = getPaddedReference(reference) + "Finished in " + ms(elapsedTime);
|
||||
if (isTopLevel(reference) || isTEngine())
|
||||
{
|
||||
logger.debug(message);
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.trace(message);
|
||||
}
|
||||
// We don't append the Finished message to ClientData as that would be too much
|
||||
}
|
||||
}
|
||||
|
||||
public void popTransform(String reference, long elapsedTime)
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
String message = getPaddedReference(reference) + "Finished in " + ms(elapsedTime);
|
||||
logger.debug(message);
|
||||
}
|
||||
}
|
||||
|
||||
public void logOptions(TransformRequest request)
|
||||
{
|
||||
RepositoryClientData repositoryClientData = new RepositoryClientData(request.getClientData());
|
||||
if (isEnabled(repositoryClientData))
|
||||
{
|
||||
Map<String, String> options = request.getTransformRequestOptions();
|
||||
if (options != null && !options.isEmpty())
|
||||
{
|
||||
String reference = TransformStack.getReference(request.getInternalContext());
|
||||
for (Map.Entry<String, String> option : options.entrySet())
|
||||
{
|
||||
String key = option.getKey();
|
||||
if (!TIMEOUT.equals(key))
|
||||
{
|
||||
String value = option.getValue();
|
||||
String message = getOptionAndValue(reference, key, value);
|
||||
logger.debug(message);
|
||||
if (isDebugToBeReturned(repositoryClientData))
|
||||
{
|
||||
repositoryClientData.appendDebug(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
request.setClientData(repositoryClientData.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void logOptions(String reference, Map<String, String> options)
|
||||
{
|
||||
if (logger.isDebugEnabled() && options != null && !options.isEmpty())
|
||||
{
|
||||
for (Map.Entry<String, String> option : options.entrySet())
|
||||
{
|
||||
String key = option.getKey();
|
||||
if (!TIMEOUT.equals(key))
|
||||
{
|
||||
String value = option.getValue();
|
||||
String message = getOptionAndValue(reference, key, value);
|
||||
logger.debug(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String getOptionAndValue(String reference, String key, String value)
|
||||
{
|
||||
// Truncate the value if it is long or needs to be protected, like Direct Access Urls
|
||||
int len = value.length();
|
||||
if (len > MAX_OPTION_VALUE)
|
||||
{
|
||||
value = value.substring(0, MAX_OPTION_VALUE-MAX_OPTION_DOTS.length()-MAX_OPTION_END_CHARS) +
|
||||
MAX_OPTION_DOTS +value.substring(len-MAX_OPTION_END_CHARS);
|
||||
}
|
||||
return getPaddedReference(reference) +
|
||||
" " + key + "=\"" + value.replaceAll("\"", "\\\"") + "\"";
|
||||
}
|
||||
|
||||
public void logFailure(TransformReply reply)
|
||||
{
|
||||
RepositoryClientData repositoryClientData = new RepositoryClientData(reply.getClientData());
|
||||
if (isEnabled(repositoryClientData))
|
||||
{
|
||||
String reference = TransformStack.getReference(reply.getInternalContext());
|
||||
String message = getPaddedReference(reference) + reply.getErrorDetails();
|
||||
logger.debug(message);
|
||||
if (isDebugToBeReturned(repositoryClientData))
|
||||
{
|
||||
repositoryClientData.appendDebug(message);
|
||||
reply.setClientData(repositoryClientData.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void logFailure(String reference, String message)
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug(getPaddedReference(reference) + message);
|
||||
}
|
||||
}
|
||||
|
||||
// T-Engines call this method, as the T-Router will appended the same debug messages
|
||||
public TransformerDebug setIsTEngine(boolean isTEngine)
|
||||
{
|
||||
this.isTEngine = isTEngine;
|
||||
return this;
|
||||
}
|
||||
|
||||
private boolean isEnabled(RepositoryClientData repositoryClientData)
|
||||
{
|
||||
return logger.isDebugEnabled() || isDebugToBeReturned(repositoryClientData);
|
||||
}
|
||||
|
||||
private boolean isDebugToBeReturned(RepositoryClientData repositoryClientData)
|
||||
{
|
||||
return !isTEngine() && repositoryClientData.isDebugRequested();
|
||||
}
|
||||
|
||||
private boolean isTEngine()
|
||||
{
|
||||
return isTEngine;
|
||||
}
|
||||
|
||||
private boolean isTopLevel(String reference)
|
||||
{
|
||||
return !reference.contains(".");
|
||||
}
|
||||
|
||||
private String getPaddedReference(String reference)
|
||||
{
|
||||
return reference + spaces(REFERENCE_SIZE + 3 - reference.length()); // 3 for "a) " ordered list
|
||||
}
|
||||
|
||||
private String getMimetypeExt(String mimetype)
|
||||
{
|
||||
return padExt(ExtensionService.getExtensionForMimetype(mimetype), mimetype);
|
||||
}
|
||||
|
||||
public String getTargetMimetypeExt(String targetMimetype, String sourceMimetype)
|
||||
{
|
||||
return padExt(ExtensionService.getExtensionForTargetMimetype(targetMimetype, sourceMimetype), targetMimetype);
|
||||
}
|
||||
|
||||
private String padExt(String mimetypeExt, String mimetype)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder("");
|
||||
if (mimetypeExt == null)
|
||||
{
|
||||
sb.append(mimetype);
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append(mimetypeExt);
|
||||
sb.append(spaces(4 - mimetypeExt.length())); // Pad to normal max ext (4)
|
||||
}
|
||||
sb.append(' ');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private String getRenditionName(String renditionName)
|
||||
{
|
||||
return !renditionName.isEmpty()
|
||||
? "-- "+ replaceWithMetadataRenditionNameIfEmbedOrExtract(renditionName)+" -- "
|
||||
: "";
|
||||
}
|
||||
|
||||
private static String replaceWithMetadataRenditionNameIfEmbedOrExtract(String renditionName)
|
||||
{
|
||||
String transformName = getTransformName(renditionName);
|
||||
return transformName.startsWith(MIMETYPE_METADATA_EXTRACT)
|
||||
? "metadataExtract"
|
||||
: transformName.startsWith(MIMETYPE_METADATA_EMBED)
|
||||
? "metadataEmbed"
|
||||
: renditionName;
|
||||
}
|
||||
|
||||
private static String getTransformName(String renditionName)
|
||||
{
|
||||
return !renditionName.startsWith(TRANSFORM_NAMESPACE)
|
||||
? ""
|
||||
: renditionName.substring(TRANSFORM_NAMESPACE.length());
|
||||
}
|
||||
|
||||
private String spaces(int i)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder("");
|
||||
while (--i >= 0)
|
||||
{
|
||||
sb.append(' ');
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private String ms(long time)
|
||||
{
|
||||
return String.format("%,d ms", time);
|
||||
}
|
||||
|
||||
private String fileSize(long size)
|
||||
{
|
||||
if (size < 0)
|
||||
{
|
||||
return "unlimited";
|
||||
}
|
||||
if (size == 1)
|
||||
{
|
||||
return "1 byte";
|
||||
}
|
||||
final String[] units = new String[] { "bytes", "KB", "MB", "GB", "TB" };
|
||||
long divider = 1;
|
||||
for(int i = 0; i < units.length-1; i++)
|
||||
{
|
||||
long nextDivider = divider * 1024;
|
||||
if (size < nextDivider)
|
||||
{
|
||||
return fileSizeFormat(size, divider, units[i]);
|
||||
}
|
||||
divider = nextDivider;
|
||||
}
|
||||
return fileSizeFormat(size, divider, units[units.length-1]);
|
||||
}
|
||||
|
||||
private String fileSizeFormat(long size, long divider, String unit)
|
||||
{
|
||||
size = size * 10 / divider;
|
||||
int decimalPoint = (int) size % 10;
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(size/10);
|
||||
if (decimalPoint != 0)
|
||||
{
|
||||
sb.append(".");
|
||||
sb.append(decimalPoint);
|
||||
}
|
||||
sb.append(' ');
|
||||
sb.append(unit);
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
@@ -0,0 +1,198 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Transform Model
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2022 Alfresco Software Limited
|
||||
* %%
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 General Lesser Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Lesser Public
|
||||
* License along with this program. If not, see
|
||||
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.transform.client.model;
|
||||
|
||||
import static org.alfresco.transform.client.model.Mimetype.MIMETYPE_IMAGE_PNG;
|
||||
import static org.alfresco.transform.client.model.Mimetype.MIMETYPE_PDF;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.validation.DirectFieldBindingResult;
|
||||
import org.springframework.validation.Errors;
|
||||
|
||||
/**
|
||||
* TransformRequestValidatorTest
|
||||
* <p/>
|
||||
* Unit test that checks the Transform request validation.
|
||||
*/
|
||||
public class TransformRequestValidatorTest
|
||||
{
|
||||
private TransformRequestValidator validator = new TransformRequestValidator();
|
||||
|
||||
@Test
|
||||
public void testSupports()
|
||||
{
|
||||
assertTrue(validator.supports(TransformRequest.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullRequest()
|
||||
{
|
||||
Errors errors = new DirectFieldBindingResult(null, "request");
|
||||
validator.validate(null, errors);
|
||||
|
||||
assertEquals(1, errors.getAllErrors().size());
|
||||
assertEquals("request cannot be null",
|
||||
errors.getAllErrors().iterator().next().getDefaultMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMissingId()
|
||||
{
|
||||
TransformRequest request = new TransformRequest();
|
||||
Errors errors = new DirectFieldBindingResult(request, "request");
|
||||
|
||||
validator.validate(request, errors);
|
||||
|
||||
assertFalse(errors.getAllErrors().isEmpty());
|
||||
assertEquals("requestId cannot be null or empty",
|
||||
errors.getAllErrors().iterator().next().getDefaultMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMissingSourceSize()
|
||||
{
|
||||
TransformRequest request = new TransformRequest();
|
||||
request.setRequestId(UUID.randomUUID().toString());
|
||||
request.setSourceReference(UUID.randomUUID().toString());
|
||||
Errors errors = new DirectFieldBindingResult(request, "request");
|
||||
|
||||
validator.validate(request, errors);
|
||||
|
||||
assertFalse(errors.getAllErrors().isEmpty());
|
||||
assertEquals("sourceSize cannot be null or have its value smaller than 0",
|
||||
errors.getAllErrors().iterator().next().getDefaultMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMissingSourceMediaType()
|
||||
{
|
||||
TransformRequest request = new TransformRequest();
|
||||
request.setRequestId(UUID.randomUUID().toString());
|
||||
request.setSourceReference(UUID.randomUUID().toString());
|
||||
request.setSourceSize(32L);
|
||||
Errors errors = new DirectFieldBindingResult(request, "request");
|
||||
|
||||
validator.validate(request, errors);
|
||||
|
||||
assertFalse(errors.getAllErrors().isEmpty());
|
||||
assertEquals("sourceMediaType cannot be null or empty",
|
||||
errors.getAllErrors().iterator().next().getDefaultMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMissingTargetMediaType()
|
||||
{
|
||||
TransformRequest request = new TransformRequest();
|
||||
request.setRequestId(UUID.randomUUID().toString());
|
||||
request.setSourceReference(UUID.randomUUID().toString());
|
||||
request.setSourceSize(32L);
|
||||
request.setSourceMediaType(MIMETYPE_PDF);
|
||||
Errors errors = new DirectFieldBindingResult(request, "request");
|
||||
|
||||
validator.validate(request, errors);
|
||||
|
||||
assertFalse(errors.getAllErrors().isEmpty());
|
||||
assertEquals("targetMediaType cannot be null or empty",
|
||||
errors.getAllErrors().iterator().next().getDefaultMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMissingTargetExtension()
|
||||
{
|
||||
TransformRequest request = new TransformRequest();
|
||||
request.setRequestId(UUID.randomUUID().toString());
|
||||
request.setSourceReference(UUID.randomUUID().toString());
|
||||
request.setSourceSize(32L);
|
||||
request.setSourceMediaType(MIMETYPE_PDF);
|
||||
request.setTargetMediaType(MIMETYPE_IMAGE_PNG);
|
||||
Errors errors = new DirectFieldBindingResult(request, "request");
|
||||
|
||||
validator.validate(request, errors);
|
||||
|
||||
assertFalse(errors.getAllErrors().isEmpty());
|
||||
assertEquals("targetExtension cannot be null or empty",
|
||||
errors.getAllErrors().iterator().next().getDefaultMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMissingClientData()
|
||||
{
|
||||
TransformRequest request = new TransformRequest();
|
||||
request.setRequestId(UUID.randomUUID().toString());
|
||||
request.setSourceReference(UUID.randomUUID().toString());
|
||||
request.setSourceSize(32L);
|
||||
request.setSourceMediaType(MIMETYPE_PDF);
|
||||
request.setTargetMediaType(MIMETYPE_IMAGE_PNG);
|
||||
request.setTargetExtension("png");
|
||||
Errors errors = new DirectFieldBindingResult(request, "request");
|
||||
|
||||
validator.validate(request, errors);
|
||||
|
||||
assertFalse(errors.getAllErrors().isEmpty());
|
||||
assertEquals("clientData cannot be null or empty",
|
||||
errors.getAllErrors().iterator().next().getDefaultMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMissingSchema()
|
||||
{
|
||||
TransformRequest request = new TransformRequest();
|
||||
request.setRequestId(UUID.randomUUID().toString());
|
||||
request.setSourceReference(UUID.randomUUID().toString());
|
||||
request.setSourceSize(32L);
|
||||
request.setSourceMediaType(MIMETYPE_PDF);
|
||||
request.setTargetMediaType(MIMETYPE_IMAGE_PNG);
|
||||
request.setTargetExtension("png");
|
||||
request.setClientData("ACS");
|
||||
request.setSchema(-1);
|
||||
Errors errors = new DirectFieldBindingResult(request, "request");
|
||||
|
||||
validator.validate(request, errors);
|
||||
|
||||
assertFalse(errors.getAllErrors().isEmpty());
|
||||
assertEquals("schema cannot be less than 0",
|
||||
errors.getAllErrors().iterator().next().getDefaultMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCompleteTransformRequest()
|
||||
{
|
||||
TransformRequest request = new TransformRequest();
|
||||
request.setRequestId(UUID.randomUUID().toString());
|
||||
request.setSourceReference(UUID.randomUUID().toString());
|
||||
request.setSourceSize(32L);
|
||||
request.setSourceMediaType(MIMETYPE_PDF);
|
||||
request.setTargetMediaType(MIMETYPE_IMAGE_PNG);
|
||||
request.setTargetExtension("png");
|
||||
request.setClientData("ACS");
|
||||
Errors errors = new DirectFieldBindingResult(request, "request");
|
||||
|
||||
validator.validate(request, errors);
|
||||
|
||||
assertTrue(errors.getAllErrors().isEmpty());
|
||||
}
|
||||
}
|
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Transform Model
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2022 Alfresco Software Limited
|
||||
* %%
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 General Lesser Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Lesser Public
|
||||
* License along with this program. If not, see
|
||||
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.transform.client.model.config;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class CoreFunctionTest
|
||||
{
|
||||
@Test
|
||||
void isSupported()
|
||||
{
|
||||
assertTrue(CoreFunction.HTTP.isSupported("0.1"));
|
||||
assertTrue(CoreFunction.HTTP.isSupported("2.5.6"));
|
||||
assertFalse(CoreFunction.HTTP.isSupported("100000"));
|
||||
|
||||
assertFalse(CoreFunction.ACTIVE_MQ.isSupported("0.1"));
|
||||
assertTrue(CoreFunction.ACTIVE_MQ.isSupported("2.5"));
|
||||
|
||||
assertFalse(CoreFunction.DIRECT_ACCESS_URL.isSupported(null));
|
||||
assertFalse(CoreFunction.DIRECT_ACCESS_URL.isSupported(""));
|
||||
assertFalse(CoreFunction.DIRECT_ACCESS_URL.isSupported("2.5"));
|
||||
assertFalse(CoreFunction.DIRECT_ACCESS_URL.isSupported("2.5.6"));
|
||||
assertTrue(CoreFunction.DIRECT_ACCESS_URL.isSupported("2.5.7-SNAPSHOT"));
|
||||
assertTrue(CoreFunction.DIRECT_ACCESS_URL.isSupported("2.5.7-A4-SNAPSHOT"));
|
||||
assertTrue(CoreFunction.DIRECT_ACCESS_URL.isSupported("2.5.7"));
|
||||
assertTrue(CoreFunction.DIRECT_ACCESS_URL.isSupported("2.6"));
|
||||
assertTrue(CoreFunction.DIRECT_ACCESS_URL.isSupported("999999"));
|
||||
}
|
||||
}
|
@@ -0,0 +1,216 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Transform Model
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2022 Alfresco Software Limited
|
||||
* %%
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 General Lesser Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Lesser Public
|
||||
* License along with this program. If not, see
|
||||
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.transform.client.model.config;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.alfresco.transform.client.model.config.CoreVersionDecorator.CONFIG_VERSION_INCLUDES_CORE_VERSION;
|
||||
import static org.alfresco.transform.client.model.config.CoreVersionDecorator.setCoreVersionOnMultiStepTransformers;
|
||||
import static org.alfresco.transform.client.model.config.CoreVersionDecorator.setCoreVersionOnSingleStepTransformers;
|
||||
import static org.alfresco.transform.client.model.config.CoreVersionDecorator.setOrClearCoreVersion;
|
||||
import static org.alfresco.transform.client.util.RequestParamMap.CONFIG_VERSION_DEFAULT;
|
||||
import static org.alfresco.transform.client.util.RequestParamMap.DIRECT_ACCESS_URL;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class CoreVersionDecoratorTest
|
||||
{
|
||||
private static final int CONFIG_VERSION_ORIGINAL = Integer.valueOf(CONFIG_VERSION_DEFAULT);
|
||||
|
||||
private static final String SOME_NAME = "optionName";
|
||||
|
||||
public static final Set<TransformOption> SOME_OPTIONS = Set.of(new TransformOptionValue(false, "someOption"));
|
||||
private static final Set<TransformOption> DIRECT_ACCESS_URL_OPTION = Set.of(new TransformOptionValue(false, DIRECT_ACCESS_URL));
|
||||
|
||||
private final Map<String, Set<TransformOption>> TRANSFORM_OPTIONS_WITHOUT_DIRECT_ACCESS_URL = new HashMap<>();
|
||||
private final Map<String, Set<TransformOption>> TRANSFORM_OPTIONS_WITH_DIRECT_ACCESS_URL = new HashMap<>();
|
||||
{
|
||||
TRANSFORM_OPTIONS_WITHOUT_DIRECT_ACCESS_URL.put(SOME_NAME, SOME_OPTIONS);
|
||||
TRANSFORM_OPTIONS_WITH_DIRECT_ACCESS_URL.put(SOME_NAME, SOME_OPTIONS);
|
||||
TRANSFORM_OPTIONS_WITH_DIRECT_ACCESS_URL.put(DIRECT_ACCESS_URL, DIRECT_ACCESS_URL_OPTION);
|
||||
}
|
||||
|
||||
private TransformConfig newTransformConfig(String version1, String version2, String version3, String version4, String version5,
|
||||
boolean hasDirectAccessUrls, boolean multiStepHaveDirectAccessUrls)
|
||||
{
|
||||
HashSet<String> transformOptions1 = new HashSet<>();
|
||||
HashSet<String> transformOptions2 = new HashSet<>(transformOptions1);
|
||||
transformOptions2.add(SOME_NAME);
|
||||
HashSet<String> transformOptions3 = new HashSet<>(transformOptions1);
|
||||
|
||||
HashSet<String> transformOptions4 = new HashSet<>(transformOptions1);
|
||||
transformOptions4.addAll(transformOptions2);
|
||||
HashSet<String> transformOptions5 = new HashSet<>(transformOptions1);
|
||||
transformOptions5.addAll(transformOptions2);
|
||||
transformOptions5.addAll(transformOptions3);
|
||||
|
||||
if (hasDirectAccessUrls)
|
||||
{
|
||||
transformOptions1.add(DIRECT_ACCESS_URL);
|
||||
transformOptions2.add(DIRECT_ACCESS_URL);
|
||||
transformOptions3.add(DIRECT_ACCESS_URL);
|
||||
}
|
||||
|
||||
if (multiStepHaveDirectAccessUrls)
|
||||
{
|
||||
transformOptions4.add(DIRECT_ACCESS_URL);
|
||||
transformOptions5.add(DIRECT_ACCESS_URL);
|
||||
}
|
||||
|
||||
return TransformConfig.builder()
|
||||
.withTransformOptions(hasDirectAccessUrls ? TRANSFORM_OPTIONS_WITH_DIRECT_ACCESS_URL : TRANSFORM_OPTIONS_WITHOUT_DIRECT_ACCESS_URL)
|
||||
.withTransformers(ImmutableList.of(
|
||||
Transformer.builder()
|
||||
.withTransformerName("transformer1")
|
||||
.withCoreVersion(version1)
|
||||
.withTransformOptions(transformOptions1)
|
||||
.build(),
|
||||
Transformer.builder()
|
||||
.withTransformerName("transformer2")
|
||||
.withCoreVersion(version2)
|
||||
.withTransformOptions(transformOptions2)
|
||||
.build(),
|
||||
Transformer.builder()
|
||||
.withTransformerName("transformer3")
|
||||
.withCoreVersion(version3)
|
||||
.withTransformOptions(transformOptions3)
|
||||
.build(),
|
||||
Transformer.builder()
|
||||
.withTransformerName("pipeline4")
|
||||
.withCoreVersion(version4)
|
||||
.withTransformerPipeline(List.of(
|
||||
new TransformStep("transformer1", "mimetype/c"),
|
||||
new TransformStep("transformer2", null)))
|
||||
.withTransformOptions(transformOptions4)
|
||||
.build(),
|
||||
Transformer.builder()
|
||||
.withTransformerName("failover5")
|
||||
.withCoreVersion(version5)
|
||||
.withTransformerFailover(List.of("transformer1", "transformer2", "transformer3"))
|
||||
.withTransformOptions(transformOptions5)
|
||||
.build()))
|
||||
.build();
|
||||
}
|
||||
|
||||
@Test
|
||||
void setCoreVersionOnSingleStepTransformersTest()
|
||||
{
|
||||
TransformConfig transformConfigReadFormTEngineJson = newTransformConfig(
|
||||
null, null, null, null, null,
|
||||
false, false);
|
||||
|
||||
setCoreVersionOnSingleStepTransformers(transformConfigReadFormTEngineJson, "2.3.1");
|
||||
assertEquals(newTransformConfig("2.3.1", "2.3.1", "2.3.1", null, null,
|
||||
false, false), transformConfigReadFormTEngineJson);
|
||||
|
||||
// Now with Direct Access URLs
|
||||
transformConfigReadFormTEngineJson = newTransformConfig(
|
||||
null, null, null, null, null,
|
||||
false, false);
|
||||
|
||||
setCoreVersionOnSingleStepTransformers(transformConfigReadFormTEngineJson, "2.5.7");
|
||||
assertEquals(newTransformConfig("2.5.7", "2.5.7", "2.5.7", null, null,
|
||||
true, false), transformConfigReadFormTEngineJson);
|
||||
}
|
||||
|
||||
@Test
|
||||
void setCoreVersionOnMultiStepTransformersTest()
|
||||
{
|
||||
// All source T-Engines provide a coreVersion and have had the coreVersion added
|
||||
TransformConfig decoratedSingleStepTransformConfig = newTransformConfig(
|
||||
"2.1", "2.2", "1.2.3", null, null,
|
||||
false, false);
|
||||
|
||||
setCoreVersionOnMultiStepTransformers(decoratedSingleStepTransformConfig.getTransformOptions(),
|
||||
decoratedSingleStepTransformConfig.getTransformers());
|
||||
assertEquals(newTransformConfig("2.1", "2.2", "1.2.3", "2.1", "1.2.3",
|
||||
false, false), decoratedSingleStepTransformConfig);
|
||||
|
||||
// Some source T-Engines are pre coreVersion
|
||||
decoratedSingleStepTransformConfig = newTransformConfig(
|
||||
"2.1", null, null, null, null,
|
||||
false, false);
|
||||
|
||||
setCoreVersionOnMultiStepTransformers(decoratedSingleStepTransformConfig.getTransformOptions(),
|
||||
decoratedSingleStepTransformConfig.getTransformers());
|
||||
assertEquals(newTransformConfig("2.1", null, null, null, null,
|
||||
false, false), decoratedSingleStepTransformConfig);
|
||||
|
||||
// Now with Direct Access URLs
|
||||
decoratedSingleStepTransformConfig = newTransformConfig("2.5.7", "2.5.7", "2.5.7", null, null,
|
||||
true, false);
|
||||
|
||||
setCoreVersionOnMultiStepTransformers(decoratedSingleStepTransformConfig.getTransformOptions(),
|
||||
decoratedSingleStepTransformConfig.getTransformers());
|
||||
assertEquals(newTransformConfig("2.5.7", "2.5.7", "2.5.7", "2.5.7", "2.5.7",
|
||||
true, true), decoratedSingleStepTransformConfig);
|
||||
}
|
||||
|
||||
@Test
|
||||
void setOrClearCoreVersionTest()
|
||||
{
|
||||
// All source T-Engines provide a coreVersion
|
||||
TransformConfig transformConfigWithCoreVersion = newTransformConfig(
|
||||
"2.1", "2.2", "1.2.3", "2.1", "1.2.3",
|
||||
false, false);
|
||||
|
||||
assertEquals(newTransformConfig(null, null, null, null, null,
|
||||
false, false),
|
||||
setOrClearCoreVersion(transformConfigWithCoreVersion, CONFIG_VERSION_ORIGINAL));
|
||||
assertEquals(newTransformConfig("2.1", "2.2", "1.2.3", "2.1", "1.2.3",
|
||||
false, false),
|
||||
setOrClearCoreVersion(transformConfigWithCoreVersion, CONFIG_VERSION_INCLUDES_CORE_VERSION));
|
||||
assertEquals(newTransformConfig("2.1", "2.2", "1.2.3", "2.1", "1.2.3",
|
||||
false, false),
|
||||
setOrClearCoreVersion(transformConfigWithCoreVersion, CONFIG_VERSION_INCLUDES_CORE_VERSION+100));
|
||||
|
||||
// Some source T-Engines are pre coreVersion
|
||||
TransformConfig transformConfigWithoutCoreVersion = newTransformConfig(
|
||||
null, null, null, null, null,
|
||||
false, false);
|
||||
|
||||
assertEquals(newTransformConfig(null, null, null, null, null,
|
||||
false, false),
|
||||
setOrClearCoreVersion(transformConfigWithoutCoreVersion, CONFIG_VERSION_ORIGINAL));
|
||||
assertEquals(newTransformConfig(null, null, null, null, null,
|
||||
false, false),
|
||||
setOrClearCoreVersion(transformConfigWithoutCoreVersion, CONFIG_VERSION_INCLUDES_CORE_VERSION));
|
||||
|
||||
// Now with Direct Access URLs
|
||||
transformConfigWithCoreVersion = newTransformConfig(
|
||||
"2.5.7", "2.5.7", "2.5.7", "2.5.7", "2.5.7",
|
||||
true, true);
|
||||
|
||||
assertEquals(newTransformConfig(null, null, null, null, null,
|
||||
false, false),
|
||||
setOrClearCoreVersion(transformConfigWithCoreVersion, CONFIG_VERSION_ORIGINAL));
|
||||
assertEquals(newTransformConfig("2.5.7", "2.5.7", "2.5.7", "2.5.7", "2.5.7",
|
||||
true, true),
|
||||
setOrClearCoreVersion(transformConfigWithCoreVersion, CONFIG_VERSION_INCLUDES_CORE_VERSION));
|
||||
}
|
||||
}
|
@@ -0,0 +1,896 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Transform Model
|
||||
* %%
|
||||
* Copyright (C) 2021 - 2022 Alfresco Software Limited
|
||||
* %%
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 General Lesser Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Lesser Public
|
||||
* License along with this program. If not, see
|
||||
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.transform.client.registry;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import org.alfresco.transform.client.model.config.SupportedSourceAndTarget;
|
||||
import org.alfresco.transform.client.model.config.TransformConfig;
|
||||
import org.alfresco.transform.client.model.config.TransformStep;
|
||||
import org.alfresco.transform.client.model.config.Transformer;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static java.util.Collections.emptyList;
|
||||
import static java.util.Collections.emptyMap;
|
||||
import static java.util.Collections.emptySet;
|
||||
import static junit.framework.TestCase.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
|
||||
/**
|
||||
* Test the CombinedTransformConfig, extended by both T-Router and ACS repository.
|
||||
*
|
||||
* @author adavis
|
||||
*/
|
||||
public class CombinedTransformConfigTest
|
||||
{
|
||||
private static final Transformer TRANSFORMER1_A2B_A2E = Transformer.builder().withTransformerName("1")
|
||||
.withSupportedSourceAndTargetList(Set.of(
|
||||
SupportedSourceAndTarget.builder()
|
||||
.withSourceMediaType("mimetype/a")
|
||||
.withTargetMediaType("mimetype/b")
|
||||
.build(),
|
||||
SupportedSourceAndTarget.builder()
|
||||
.withSourceMediaType("mimetype/a")
|
||||
.withTargetMediaType("mimetype/e")
|
||||
.build()))
|
||||
.build();
|
||||
|
||||
private static final Transformer TRANSFORMER1_A2B = Transformer.builder().withTransformerName("1")
|
||||
.withSupportedSourceAndTargetList(Set.of(
|
||||
SupportedSourceAndTarget.builder()
|
||||
.withSourceMediaType("mimetype/a")
|
||||
.withTargetMediaType("mimetype/b")
|
||||
.build()))
|
||||
.build();
|
||||
|
||||
private static final Transformer TRANSFORMER1_A2E = Transformer.builder().withTransformerName("1")
|
||||
.withSupportedSourceAndTargetList(Set.of(
|
||||
SupportedSourceAndTarget.builder()
|
||||
.withSourceMediaType("mimetype/a")
|
||||
.withTargetMediaType("mimetype/e")
|
||||
.build()))
|
||||
.build();
|
||||
|
||||
private static final Transformer TRANSFORMER1_A2D = Transformer.builder().withTransformerName("1")
|
||||
.withSupportedSourceAndTargetList(Set.of(
|
||||
SupportedSourceAndTarget.builder()
|
||||
.withSourceMediaType("mimetype/a")
|
||||
.withTargetMediaType("mimetype/d")
|
||||
.build()))
|
||||
.build();
|
||||
|
||||
// Not static as pipelines gets modified.
|
||||
private static final Transformer PIPELINE1_2C3 = Transformer.builder().withTransformerName("1")
|
||||
.withTransformerPipeline(List.of(
|
||||
new TransformStep("2", "mimetype/c"),
|
||||
new TransformStep("3", null)))
|
||||
.build();
|
||||
|
||||
// Not static as pipelines gets modified.
|
||||
private static final Transformer PIPELINE1_2C3_COPY = Transformer.builder().withTransformerName("1")
|
||||
.withTransformerPipeline(List.of(
|
||||
new TransformStep("2", "mimetype/c"),
|
||||
new TransformStep("3", null)))
|
||||
.build();
|
||||
|
||||
private static final Transformer TRANSFORMER2_B2C = Transformer.builder().withTransformerName("2")
|
||||
.withSupportedSourceAndTargetList(Set.of(
|
||||
SupportedSourceAndTarget.builder()
|
||||
.withSourceMediaType("mimetype/b")
|
||||
.withTargetMediaType("mimetype/c")
|
||||
.build()))
|
||||
.build();
|
||||
|
||||
private static final Transformer TRANSFORMER2_A2C = Transformer.builder().withTransformerName("2")
|
||||
.withSupportedSourceAndTargetList(Set.of(
|
||||
SupportedSourceAndTarget.builder()
|
||||
.withSourceMediaType("mimetype/a")
|
||||
.withTargetMediaType("mimetype/c")
|
||||
.build()))
|
||||
.build();
|
||||
|
||||
private static final Transformer TRANSFORMER2_B2X = Transformer.builder().withTransformerName("2")
|
||||
.withSupportedSourceAndTargetList(Set.of(
|
||||
SupportedSourceAndTarget.builder()
|
||||
.withSourceMediaType("mimetype/b")
|
||||
.withTargetMediaType("mimetype/X")
|
||||
.build()))
|
||||
.build();
|
||||
|
||||
private static final Transformer TRANSFORMER3_C2D = Transformer.builder().withTransformerName("3")
|
||||
.withSupportedSourceAndTargetList(Set.of(
|
||||
SupportedSourceAndTarget.builder()
|
||||
.withSourceMediaType("mimetype/c")
|
||||
.withTargetMediaType("mimetype/d")
|
||||
.build()))
|
||||
.build();
|
||||
|
||||
private static final Transformer TRANSFORMER3_C2D_C2E = Transformer.builder().withTransformerName("3")
|
||||
.withSupportedSourceAndTargetList(Set.of(
|
||||
SupportedSourceAndTarget.builder()
|
||||
.withSourceMediaType("mimetype/c")
|
||||
.withTargetMediaType("mimetype/d")
|
||||
.build(),
|
||||
SupportedSourceAndTarget.builder()
|
||||
.withSourceMediaType("mimetype/a")
|
||||
.withTargetMediaType("mimetype/e")
|
||||
.build()))
|
||||
.build();
|
||||
|
||||
private static final Transformer TRANSFORMER1 = Transformer.builder().withTransformerName("1").build();
|
||||
|
||||
private static final Transformer TRANSFORMER2 = Transformer.builder().withTransformerName("2").build();
|
||||
|
||||
private static final Transformer TRANSFORMER3 = Transformer.builder().withTransformerName("3").build();
|
||||
|
||||
public static final Transformer TRANSFORMER_WITH_NO_NAME = Transformer.builder().withTransformerName("").build();
|
||||
|
||||
public static final String PASS_THROUGH_NAME = "PassThrough";
|
||||
|
||||
private static final Transformer PASS_THROUGH = Transformer.builder().withTransformerName(PASS_THROUGH_NAME).build();
|
||||
|
||||
private static final Transformer PASS_THROUGH_COPY = Transformer.builder().withTransformerName(PASS_THROUGH_NAME).build();
|
||||
|
||||
// Not static as pipelines get modified.
|
||||
private final Transformer PIPELINE4_1B2C3 = Transformer.builder().withTransformerName("4")
|
||||
.withTransformerPipeline(List.of(
|
||||
new TransformStep("1", "mimetype/b"),
|
||||
new TransformStep("2", "mimetype/c"),
|
||||
new TransformStep("3", null)))
|
||||
.build();
|
||||
|
||||
// Not static as failover transforms get modified.
|
||||
private final Transformer FAILOVER1_23 = Transformer.builder().withTransformerName("1")
|
||||
.withTransformerFailover(List.of("2", "3"))
|
||||
.build();
|
||||
|
||||
// Not static as failover transforms get modified.
|
||||
private final Transformer FAILOVER4_123 = Transformer.builder().withTransformerName("4")
|
||||
.withTransformerFailover(List.of("1", "2", "3"))
|
||||
.build();
|
||||
|
||||
// Not static as the nested pipeline gets modified.
|
||||
private final TransformConfig ONE_TRANSFORM = TransformConfig
|
||||
.builder()
|
||||
.withTransformers(ImmutableList.of(PIPELINE1_2C3))
|
||||
.build();
|
||||
|
||||
private static final TransformConfig TWO_TRANSFORMS = TransformConfig
|
||||
.builder()
|
||||
.withTransformOptions(ImmutableMap.of(
|
||||
"options/1", emptySet(),
|
||||
"options/2", emptySet()))
|
||||
.withTransformers(ImmutableList.of(TRANSFORMER2_B2C, TRANSFORMER3_C2D))
|
||||
.build();
|
||||
|
||||
private static final String READ_FROM_A = "readFromA";
|
||||
private static final String READ_FROM_B = "readFromB";
|
||||
private static final String ROUTER_CONFIG_HAS_NO_BASE_URL = null;
|
||||
private static final String BASE_URL_B = "baseUrlB";
|
||||
|
||||
private final CombinedTransformConfig config = new CombinedTransformConfig()
|
||||
{
|
||||
@Override
|
||||
protected boolean isPassThroughTransformName(String name)
|
||||
{
|
||||
return PASS_THROUGH_NAME.equals(name);
|
||||
}
|
||||
};
|
||||
|
||||
private final TestTransformRegistry registry = new TestTransformRegistry();
|
||||
|
||||
private String expectedWildcardError(String errorReason)
|
||||
{
|
||||
return "No supported source and target mimetypes could be added to the transformer \"4\" as " +
|
||||
errorReason + ". Read from " + READ_FROM_B;
|
||||
}
|
||||
|
||||
// Assumes a t-engine transformer named "1" (normally TRANSFORMER1_A2B_A2E) is being overridden by an A2D transform.
|
||||
// The overriding transform should be the last element in the tRouterTransformers (or if empty the last element in
|
||||
// tEngineTransformers). The override is expected to good unless an error message is provided.
|
||||
// A check is made at the end that A2D is possible and that A2B is not possible.
|
||||
private void assertOverride(List<Transformer> tEngineTransformers,
|
||||
List<Transformer> tRouterTransformers, String expectedError)
|
||||
{
|
||||
Transformer expectedTransformer = tRouterTransformers.isEmpty()
|
||||
? tEngineTransformers.get(tEngineTransformers.size() - 1)
|
||||
: tRouterTransformers.get(tRouterTransformers.size() - 1);
|
||||
|
||||
final TransformConfig tEngineTransformConfig = TransformConfig.builder()
|
||||
.withTransformers(tEngineTransformers)
|
||||
.build();
|
||||
final TransformConfig tRouterTransformConfig = TransformConfig.builder()
|
||||
.withTransformers(tRouterTransformers)
|
||||
.build();
|
||||
|
||||
config.addTransformConfig(tEngineTransformConfig, READ_FROM_B, BASE_URL_B, registry);
|
||||
config.addTransformConfig(tRouterTransformConfig, READ_FROM_A, ROUTER_CONFIG_HAS_NO_BASE_URL, registry);
|
||||
config.combineTransformerConfig(registry);
|
||||
config.registerCombinedTransformers(registry);
|
||||
|
||||
TransformConfig transformConfig = config.buildTransformConfig();
|
||||
|
||||
if (expectedError == null)
|
||||
{
|
||||
assertEquals(0, registry.errorMessages.size());
|
||||
int numberOfTEngineTransformers = tEngineTransformers.size();
|
||||
assertEquals(numberOfTEngineTransformers, config.buildTransformConfig().getTransformers().size());
|
||||
|
||||
// Check we are using the overriding transformer from the t-router, or if none the last one in the t-engine
|
||||
assertEquals(numberOfTEngineTransformers, transformConfig.getTransformers().size());
|
||||
Transformer actualTransformer = transformConfig.getTransformers().get(numberOfTEngineTransformers - 1);
|
||||
assertEquals(expectedTransformer, actualTransformer);
|
||||
assertSame("It should even == the expected transform", expectedTransformer, actualTransformer);
|
||||
|
||||
// Check the baseUrl is that of the original t-engine that will do the work, if the overriding transform
|
||||
// is a single step transform.
|
||||
List<TransformStep> pipeline = actualTransformer.getTransformerPipeline();
|
||||
List<String> failover = actualTransformer.getTransformerFailover();
|
||||
boolean isPipeline = pipeline != null && !pipeline.isEmpty();
|
||||
boolean isFailover = failover != null && !failover.isEmpty();
|
||||
if (!isPipeline && !isFailover)
|
||||
{
|
||||
assertEquals(BASE_URL_B, registry.transformerBaseUrls.get(actualTransformer));
|
||||
}
|
||||
|
||||
// Double check by finding the overriding transformer for A2D but not the overridden transformer for A2B in
|
||||
// the registry.
|
||||
assertEquals("1", registry.findTransformerName("mimetype/a", -1,
|
||||
"mimetype/d", emptyMap(), null));
|
||||
// If the assumption about the overridden transform being A2D was wrong, the following would pass anyway
|
||||
assertNull(registry.findTransformerName("mimetype/a", -1,
|
||||
"mimetype/b", emptyMap(), null));
|
||||
}
|
||||
else
|
||||
{
|
||||
assertEquals(1, registry.errorMessages.size());
|
||||
assertEquals(expectedError, registry.errorMessages.get(0));
|
||||
}
|
||||
}
|
||||
|
||||
// No specific tests for addTransformConfig or buildTransformConfig as they are used in most
|
||||
// other test methods which will fail if they are not working.
|
||||
|
||||
@Test
|
||||
public void testClear()
|
||||
{
|
||||
config.addTransformConfig(TWO_TRANSFORMS, READ_FROM_B, BASE_URL_B, registry);
|
||||
assertEquals(2, config.buildTransformConfig().getTransformers().size());
|
||||
assertEquals(2, config.buildTransformConfig().getTransformOptions().size());
|
||||
|
||||
config.clear();
|
||||
|
||||
assertEquals(0, config.buildTransformConfig().getTransformers().size());
|
||||
assertEquals(0, config.buildTransformConfig().getTransformOptions().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCombineTransformerConfigNoOp()
|
||||
{
|
||||
config.addTransformConfig(TWO_TRANSFORMS, READ_FROM_B, BASE_URL_B, registry);
|
||||
config.addTransformConfig(ONE_TRANSFORM, READ_FROM_A, ROUTER_CONFIG_HAS_NO_BASE_URL, registry);
|
||||
assertEquals(3, config.buildTransformConfig().getTransformers().size());
|
||||
assertEquals(2, config.buildTransformConfig().getTransformOptions().size());
|
||||
|
||||
config.combineTransformerConfig(registry);
|
||||
assertEquals(3, config.buildTransformConfig().getTransformers().size());
|
||||
assertEquals(2, config.buildTransformConfig().getTransformOptions().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransformersAreRegistered()
|
||||
{
|
||||
config.addTransformConfig(TWO_TRANSFORMS, READ_FROM_B, BASE_URL_B, registry);
|
||||
config.addTransformConfig(ONE_TRANSFORM, READ_FROM_A, ROUTER_CONFIG_HAS_NO_BASE_URL, registry);
|
||||
assertEquals(3, config.buildTransformConfig().getTransformers().size());
|
||||
assertEquals(2, config.buildTransformConfig().getTransformOptions().size());
|
||||
|
||||
config.registerCombinedTransformers(registry);
|
||||
|
||||
assertEquals(3, registry.registeredCount);
|
||||
assertEquals(1, registry.readFromACount);
|
||||
assertEquals(2, registry.baseUrlBCount);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvalidBothPipelineAndFailover()
|
||||
{
|
||||
final Transformer invalidTransformer = Transformer.builder().withTransformerName("2")
|
||||
.withTransformerPipeline(List.of(
|
||||
new TransformStep("1", "mimetype/b"),
|
||||
new TransformStep("2", "mimetype/c"),
|
||||
new TransformStep("3", null)))
|
||||
.withTransformerFailover(List.of("1", "2", "3"))
|
||||
.build();
|
||||
final TransformConfig transformConfig = TransformConfig.builder()
|
||||
.withTransformers(ImmutableList.of(
|
||||
TRANSFORMER1_A2B_A2E,
|
||||
TRANSFORMER2_B2C,
|
||||
TRANSFORMER3_C2D,
|
||||
invalidTransformer))
|
||||
.build();
|
||||
|
||||
config.addTransformConfig(transformConfig, READ_FROM_B, BASE_URL_B, registry);
|
||||
config.combineTransformerConfig(registry);
|
||||
|
||||
String expected = "Transformer \"2\" cannot have pipeline and failover sections. Read from readFromB";
|
||||
assertEquals(1, registry.errorMessages.size());
|
||||
assertEquals(expected, registry.errorMessages.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvalidNoName()
|
||||
{
|
||||
final TransformConfig transformConfig = TransformConfig.builder()
|
||||
.withTransformers(ImmutableList.of(TRANSFORMER_WITH_NO_NAME))
|
||||
.build();
|
||||
|
||||
config.addTransformConfig(transformConfig, READ_FROM_B, BASE_URL_B, registry);
|
||||
config.combineTransformerConfig(registry);
|
||||
|
||||
String expected = "Transformer names may not be null. Read from readFromB";
|
||||
assertEquals(1, registry.errorMessages.size());
|
||||
assertEquals(expected, registry.errorMessages.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvalidTransformOptionsUnknown()
|
||||
{
|
||||
final Transformer transformer = Transformer.builder().withTransformerName("1")
|
||||
.withTransformOptions(ImmutableSet.of("unknown"))
|
||||
.build();
|
||||
final TransformConfig transformConfig = TransformConfig.builder()
|
||||
.withTransformers(ImmutableList.of(transformer))
|
||||
.build();
|
||||
|
||||
config.addTransformConfig(transformConfig, READ_FROM_B, BASE_URL_B, registry);
|
||||
config.combineTransformerConfig(registry);
|
||||
|
||||
String expected = "Transformer \"1\" references \"unknown\" which do not exist. Read from readFromB";
|
||||
assertEquals(1, registry.errorMessages.size());
|
||||
assertEquals(expected, registry.errorMessages.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvalidDuplicateTEngineSingleStepTransform()
|
||||
{
|
||||
final Transformer transformer = Transformer.builder().withTransformerName("1")
|
||||
.build();
|
||||
final Transformer identicalTransformer = Transformer.builder().withTransformerName("1")
|
||||
.build();
|
||||
final TransformConfig transformConfig = TransformConfig.builder()
|
||||
.withTransformers(ImmutableList.of(
|
||||
transformer,
|
||||
identicalTransformer))
|
||||
.build();
|
||||
|
||||
config.addTransformConfig(transformConfig, READ_FROM_B, BASE_URL_B, registry);
|
||||
config.combineTransformerConfig(registry);
|
||||
|
||||
String expected = "Transformer \"1\" must be a unique name. Read from readFromB";
|
||||
assertEquals(1, registry.errorMessages.size());
|
||||
assertEquals(expected, registry.errorMessages.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOverrideSingleStepWithSingleStepInTEngine()
|
||||
{
|
||||
final Transformer transformerWithSameNameButDifferentDefinition = Transformer.builder().withTransformerName("1")
|
||||
.withTransformOptions(ImmutableSet.of("options/1"))
|
||||
.build();
|
||||
final TransformConfig transformConfig = TransformConfig.builder()
|
||||
.withTransformers(ImmutableList.of(
|
||||
TRANSFORMER1,
|
||||
transformerWithSameNameButDifferentDefinition))
|
||||
.withTransformOptions(ImmutableMap.of("options/1", emptySet()))
|
||||
.build();
|
||||
|
||||
config.addTransformConfig(transformConfig, READ_FROM_B, BASE_URL_B, registry);
|
||||
config.combineTransformerConfig(registry);
|
||||
|
||||
// Expected: This is the same error as in testInvalidDuplicateTEngineSingleStepTransform
|
||||
String expected = "Transformer \"1\" must be a unique name. Read from readFromB";
|
||||
assertEquals(1, registry.errorMessages.size());
|
||||
assertEquals(expected, registry.errorMessages.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvalidSingleStepTransformInRouter()
|
||||
{
|
||||
final TransformConfig transformConfig = TransformConfig.builder()
|
||||
.withTransformers(ImmutableList.of(TRANSFORMER1))
|
||||
.build();
|
||||
|
||||
config.addTransformConfig(transformConfig, READ_FROM_A, ROUTER_CONFIG_HAS_NO_BASE_URL, registry);
|
||||
config.combineTransformerConfig(registry);
|
||||
|
||||
String expected = "Single step transformers (such as \"1\") must be defined in a T-Engine rather than in a " +
|
||||
"pipeline file, unless they are overriding an existing single step definition. Read from readFromA";
|
||||
assertEquals(1, registry.errorMessages.size());
|
||||
assertEquals(expected, registry.errorMessages.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOverrideSingleStepWithSingleStepInTRouter() // i.e. t-router redefines a t-engine single step transform
|
||||
{
|
||||
assertOverride(
|
||||
ImmutableList.of(TRANSFORMER1_A2B_A2E),
|
||||
ImmutableList.of(TRANSFORMER1_A2D),
|
||||
null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOverrideMultipleTimesSingleStepWithSingleStepInTRouter() // need to make sure the url is remembered
|
||||
{
|
||||
assertOverride(
|
||||
ImmutableList.of(TRANSFORMER1_A2B_A2E),
|
||||
ImmutableList.of(TRANSFORMER1_A2B, TRANSFORMER1_A2E, TRANSFORMER1_A2D),
|
||||
null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOverrideSingleStepWithPipelineInTRouter()
|
||||
{
|
||||
assertOverride(
|
||||
ImmutableList.of(TRANSFORMER1_A2B_A2E, TRANSFORMER2_A2C, TRANSFORMER3_C2D),
|
||||
ImmutableList.of(PIPELINE1_2C3),
|
||||
null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOverridePipelineWithPipelineInTRouter()
|
||||
{
|
||||
assertOverride(
|
||||
ImmutableList.of(PIPELINE1_2C3, TRANSFORMER2_A2C, TRANSFORMER3_C2D),
|
||||
ImmutableList.of(PIPELINE1_2C3_COPY),
|
||||
null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvalidOverridePipelineWithSingleStepInTRouter()
|
||||
{
|
||||
assertOverride(
|
||||
ImmutableList.of(PIPELINE1_2C3, TRANSFORMER2_A2C, TRANSFORMER3_C2D),
|
||||
ImmutableList.of(TRANSFORMER1_A2D),
|
||||
"Single step transformers (such as \"1\") may not override a pipeline or failover " +
|
||||
"transform as there is no T-Engine to perform work. Read from readFromA");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvalidOverrideFailoverWithSingleStepInTRouter()
|
||||
{
|
||||
assertOverride(
|
||||
ImmutableList.of(FAILOVER1_23, TRANSFORMER2_A2C, TRANSFORMER3_C2D),
|
||||
ImmutableList.of(TRANSFORMER1_A2D),
|
||||
"Single step transformers (such as \"1\") may not override a pipeline or failover " +
|
||||
"transform as there is no T-Engine to perform work. Read from readFromA");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSinglePassThroughInTRouter()
|
||||
{
|
||||
final TransformConfig transformConfig = TransformConfig.builder()
|
||||
.withTransformers(ImmutableList.of(PASS_THROUGH))
|
||||
.build();
|
||||
|
||||
config.addTransformConfig(transformConfig, READ_FROM_A, ROUTER_CONFIG_HAS_NO_BASE_URL, registry);
|
||||
config.combineTransformerConfig(registry);
|
||||
|
||||
assertEquals(0, registry.errorMessages.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultiplePassThroughInTRouter()
|
||||
{
|
||||
final TransformConfig transformConfig = TransformConfig.builder()
|
||||
.withTransformers(ImmutableList.of(PASS_THROUGH, PASS_THROUGH_COPY))
|
||||
.build();
|
||||
|
||||
config.addTransformConfig(transformConfig, READ_FROM_A, ROUTER_CONFIG_HAS_NO_BASE_URL, registry);
|
||||
config.combineTransformerConfig(registry);
|
||||
|
||||
String expected = "Pipeline files should not use \"PassThrough\" as a transform name. Read from readFromA";
|
||||
assertEquals(1, registry.errorMessages.size());
|
||||
assertEquals(expected, registry.errorMessages.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPassThroughInTEngine()
|
||||
{
|
||||
final TransformConfig transformConfig = TransformConfig.builder()
|
||||
.withTransformers(ImmutableList.of(PASS_THROUGH))
|
||||
.build();
|
||||
|
||||
config.addTransformConfig(transformConfig, READ_FROM_B, BASE_URL_B, registry);
|
||||
config.combineTransformerConfig(registry);
|
||||
|
||||
String expected = "T-Engines should not use \"PassThrough\" as a transform name. Read from readFromB";
|
||||
assertEquals(1, registry.errorMessages.size());
|
||||
assertEquals(expected, registry.errorMessages.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvalidOverrideSingleStepWithPipelineInTEngine()
|
||||
{
|
||||
assertOverride(
|
||||
ImmutableList.of(TRANSFORMER1_A2B_A2E, TRANSFORMER2_A2C, TRANSFORMER3_C2D, PIPELINE1_2C3),
|
||||
emptyList(),
|
||||
"Transformer \"1\" must be a unique name. Read from readFromB");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvalidOverridePipelineWithSingleStepInTEngine()
|
||||
{
|
||||
assertOverride(
|
||||
ImmutableList.of(TRANSFORMER2_A2C, TRANSFORMER3_C2D, PIPELINE1_2C3, TRANSFORMER1_A2B_A2E),
|
||||
emptyList(),
|
||||
"Transformer \"1\" must be a unique name. Read from readFromB");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvalidIndexToRemoveBeforeCurrent()
|
||||
{
|
||||
// indexToRemove is is before the current i value, so we are removing an overridden transform
|
||||
// Code throws an IllegalArgumentException and i is simply decremented to ignore the current value
|
||||
final TransformConfig tEngineTransformConfig = TransformConfig.builder()
|
||||
.withTransformers(ImmutableList.of(
|
||||
TRANSFORMER1_A2B_A2E,
|
||||
TRANSFORMER2_B2C,
|
||||
TRANSFORMER3_C2D))
|
||||
.build();
|
||||
final TransformConfig tRouterTransformConfig = TransformConfig.builder()
|
||||
.withTransformers(ImmutableList.of(
|
||||
TRANSFORMER1_A2D)) // this one triggers the removal of 0
|
||||
.build();
|
||||
|
||||
config.addTransformConfig(tEngineTransformConfig, READ_FROM_B, BASE_URL_B, registry);
|
||||
config.addTransformConfig(tRouterTransformConfig, READ_FROM_A, ROUTER_CONFIG_HAS_NO_BASE_URL, registry);
|
||||
config.combineTransformerConfig(registry);
|
||||
|
||||
assertEquals(3, config.buildTransformConfig().getTransformers().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvalidIndexToRemoveIsCurrent()
|
||||
{
|
||||
// Code throws an IllegalArgumentException and i is simply decremented to ignore the current value
|
||||
final TransformConfig transformConfig = TransformConfig.builder()
|
||||
.withTransformers(ImmutableList.of(
|
||||
TRANSFORMER1_A2D,
|
||||
TRANSFORMER2_B2C,
|
||||
TRANSFORMER_WITH_NO_NAME, // discarded
|
||||
TRANSFORMER3_C2D))
|
||||
.build();
|
||||
|
||||
config.addTransformConfig(transformConfig, READ_FROM_B, BASE_URL_B, registry);
|
||||
config.combineTransformerConfig(registry);
|
||||
|
||||
assertEquals(3, config.buildTransformConfig().getTransformers().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSortSoNoForwardRefs()
|
||||
{
|
||||
final TransformConfig transformConfig = TransformConfig.builder()
|
||||
.withTransformers(ImmutableList.of(
|
||||
PIPELINE1_2C3,
|
||||
TRANSFORMER2_B2C,
|
||||
TRANSFORMER3_C2D))
|
||||
.build();
|
||||
|
||||
config.addTransformConfig(transformConfig, READ_FROM_B, BASE_URL_B, registry);
|
||||
// Check order includes forward references after setup
|
||||
List<Transformer> transformers = config.buildTransformConfig().getTransformers();
|
||||
assertEquals(3, transformers.size());
|
||||
assertEquals("1", transformers.get(0).getTransformerName());
|
||||
assertEquals("2", transformers.get(1).getTransformerName());
|
||||
assertEquals("3", transformers.get(2).getTransformerName());
|
||||
|
||||
config.combineTransformerConfig(registry);
|
||||
|
||||
// Check order changed so there are no forward references after combined
|
||||
transformers = config.buildTransformConfig().getTransformers();
|
||||
assertEquals(3, transformers.size());
|
||||
assertEquals("2", transformers.get(0).getTransformerName());
|
||||
assertEquals("3", transformers.get(1).getTransformerName());
|
||||
assertEquals("1", transformers.get(2).getTransformerName());
|
||||
|
||||
assertEquals(0, registry.warnMessages.size());
|
||||
assertEquals(0, registry.errorMessages.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvalidTransformStepNullIntermediateMimetype()
|
||||
{
|
||||
final Transformer pipeline = Transformer.builder().withTransformerName("5")
|
||||
.withTransformerPipeline(List.of(
|
||||
new TransformStep("1", "mimetype/b"),
|
||||
new TransformStep("2", null), // should not be null
|
||||
new TransformStep("3", null)))
|
||||
.build();
|
||||
final TransformConfig transformConfig = TransformConfig.builder()
|
||||
.withTransformers(ImmutableList.of(
|
||||
TRANSFORMER1_A2B,
|
||||
TRANSFORMER2_B2C,
|
||||
TRANSFORMER3_C2D,
|
||||
pipeline))
|
||||
.build();
|
||||
|
||||
config.addTransformConfig(transformConfig, READ_FROM_B, BASE_URL_B, registry);
|
||||
config.combineTransformerConfig(registry);
|
||||
|
||||
String expected = "No supported source and target mimetypes could be added to the transformer \"5\" as " +
|
||||
"intermediate steps should have a target mimetype. Read from readFromB";
|
||||
assertEquals(1, registry.errorMessages.size());
|
||||
assertEquals(expected, registry.errorMessages.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvalidTransformStepNonNullFinalMimetype()
|
||||
{
|
||||
final Transformer pipeline = Transformer.builder().withTransformerName("5")
|
||||
.withTransformerPipeline(List.of(
|
||||
new TransformStep("1", "mimetype/b"),
|
||||
new TransformStep("2", "mimetype/c"),
|
||||
new TransformStep("3", "mimetype/d"))) // the last step's mimetype should be null
|
||||
.build();
|
||||
final TransformConfig transformConfig = TransformConfig.builder()
|
||||
.withTransformers(ImmutableList.of(
|
||||
TRANSFORMER1_A2B,
|
||||
TRANSFORMER2_B2C,
|
||||
TRANSFORMER3_C2D,
|
||||
pipeline))
|
||||
.build();
|
||||
|
||||
config.addTransformConfig(transformConfig, READ_FROM_B, BASE_URL_B, registry);
|
||||
config.combineTransformerConfig(registry);
|
||||
|
||||
String expected = "No supported source and target mimetypes could be added to the transformer \"5\" as " +
|
||||
"the final step should not have a target mimetype. Read from readFromB";
|
||||
assertEquals(1, registry.errorMessages.size());
|
||||
assertEquals(expected, registry.errorMessages.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIgnorePipelineWithMissingStep()
|
||||
{
|
||||
final Transformer pipeline = Transformer.builder().withTransformerName("1")
|
||||
.withTransformerPipeline(List.of(
|
||||
new TransformStep("2", "mimetype/c"),
|
||||
new TransformStep("3", "mimetype/d"),
|
||||
new TransformStep("4", null)))
|
||||
.build();
|
||||
final TransformConfig transformConfig = TransformConfig.builder()
|
||||
.withTransformers(ImmutableList.of(
|
||||
TRANSFORMER2_B2C,
|
||||
TRANSFORMER3_C2D,
|
||||
pipeline))
|
||||
.build();
|
||||
|
||||
config.addTransformConfig(transformConfig, READ_FROM_B, BASE_URL_B, registry);
|
||||
config.combineTransformerConfig(registry);
|
||||
|
||||
String expected = "Transformer \"1\" ignored as step transforms (\"4\") do not exist. Read from readFromB";
|
||||
assertEquals(1, registry.warnMessages.size());
|
||||
assertEquals(expected, registry.warnMessages.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIgnorePipelineWithMissingSteps()
|
||||
{
|
||||
final Transformer pipeline = Transformer.builder().withTransformerName("1")
|
||||
.withTransformerPipeline(List.of(
|
||||
new TransformStep("3", "mimetype/d"),
|
||||
new TransformStep("4", "mimetype/e"),
|
||||
new TransformStep("5", "mimetype/f"),
|
||||
new TransformStep("2", "mimetype/c"),
|
||||
new TransformStep("6", null)))
|
||||
.build();
|
||||
final TransformConfig transformConfig = TransformConfig.builder()
|
||||
.withTransformers(ImmutableList.of(
|
||||
TRANSFORMER2_B2C,
|
||||
TRANSFORMER3_C2D,
|
||||
pipeline))
|
||||
.build();
|
||||
|
||||
config.addTransformConfig(transformConfig, READ_FROM_B, BASE_URL_B, registry);
|
||||
config.combineTransformerConfig(registry);
|
||||
|
||||
String expected = "Transformer \"1\" ignored as step transforms (\"4\", \"5\", \"6\") do not exist. Read from readFromB";
|
||||
assertEquals(1, registry.warnMessages.size());
|
||||
assertEquals(expected, registry.warnMessages.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvalidCircularTransformStep()
|
||||
{
|
||||
final Transformer pipeline1 = Transformer.builder().withTransformerName("1")
|
||||
.withTransformerPipeline(List.of(
|
||||
new TransformStep("2", "mimetype/c"),
|
||||
new TransformStep("4", null)))
|
||||
.build();
|
||||
final Transformer pipeline4 = Transformer.builder().withTransformerName("4")
|
||||
.withTransformerPipeline(List.of(
|
||||
new TransformStep("3", "mimetype/d"),
|
||||
new TransformStep("5", "mimetype/f"),
|
||||
new TransformStep("1", null)))
|
||||
.build();
|
||||
final TransformConfig transformConfig = TransformConfig.builder()
|
||||
.withTransformers(ImmutableList.of(
|
||||
TRANSFORMER2_B2C,
|
||||
TRANSFORMER3_C2D,
|
||||
pipeline1,
|
||||
pipeline4))
|
||||
.build();
|
||||
|
||||
config.addTransformConfig(transformConfig, READ_FROM_B, BASE_URL_B, registry);
|
||||
config.combineTransformerConfig(registry);
|
||||
|
||||
assertEquals(2, registry.warnMessages.size());
|
||||
assertEquals("Transformer \"1\" ignored as step transforms (\"4\") do not exist. Read from readFromB",
|
||||
registry.warnMessages.get(0));
|
||||
assertEquals("Transformer \"4\" ignored as step transforms (\"1\", \"5\") do not exist. Read from readFromB",
|
||||
registry.warnMessages.get(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWildcardNoOp()
|
||||
{
|
||||
final TransformConfig transformConfig = TransformConfig.builder()
|
||||
.withTransformers(ImmutableList.of(
|
||||
TRANSFORMER1_A2B_A2E,
|
||||
TRANSFORMER2_B2C,
|
||||
TRANSFORMER3_C2D))
|
||||
.build();
|
||||
|
||||
config.addTransformConfig(transformConfig, READ_FROM_B, BASE_URL_B, registry);
|
||||
config.combineTransformerConfig(registry);
|
||||
config.registerCombinedTransformers(registry);
|
||||
|
||||
assertEquals(0, registry.errorMessages.size());
|
||||
assertEquals(3, config.buildTransformConfig().getTransformers().size());
|
||||
assertEquals("1", registry.findTransformerName("mimetype/a", -1,
|
||||
"mimetype/b", emptyMap(), null));
|
||||
assertEquals("2", registry.findTransformerName("mimetype/b", -1,
|
||||
"mimetype/c", emptyMap(), null));
|
||||
assertEquals("3", registry.findTransformerName("mimetype/c", -1,
|
||||
"mimetype/d", emptyMap(), null));
|
||||
}
|
||||
|
||||
// It is not possible to test for expectedWildcardError("one of the step transformers is missing") as
|
||||
// the sortTransformers() method will have already issued another error.
|
||||
|
||||
@Test
|
||||
public void testWildcardPipeline()
|
||||
{
|
||||
final TransformConfig transformConfig = TransformConfig.builder()
|
||||
.withTransformers(ImmutableList.of(
|
||||
TRANSFORMER1_A2B_A2E,
|
||||
TRANSFORMER2_B2C,
|
||||
TRANSFORMER3_C2D,
|
||||
PIPELINE4_1B2C3))
|
||||
.build();
|
||||
|
||||
config.addTransformConfig(transformConfig, READ_FROM_B, BASE_URL_B, registry);
|
||||
config.combineTransformerConfig(registry);
|
||||
config.registerCombinedTransformers(registry);
|
||||
|
||||
assertEquals(0, registry.errorMessages.size());
|
||||
assertEquals(4, config.buildTransformConfig().getTransformers().size());
|
||||
assertEquals("4", registry.findTransformerName("mimetype/a", -1,
|
||||
"mimetype/d", emptyMap(), null));
|
||||
assertEquals("1", registry.findTransformerName("mimetype/a", -1,
|
||||
"mimetype/b", emptyMap(), null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWildcardPipelineExcludeFirstTransformsSupportedFromCartesianProduct() // Exclude more complex path
|
||||
{
|
||||
final TransformConfig transformConfig = TransformConfig.builder()
|
||||
.withTransformers(ImmutableList.of(
|
||||
TRANSFORMER1_A2B_A2E,
|
||||
TRANSFORMER2_B2C,
|
||||
TRANSFORMER3_C2D_C2E,
|
||||
PIPELINE4_1B2C3))
|
||||
.build();
|
||||
|
||||
config.addTransformConfig(transformConfig, READ_FROM_B, BASE_URL_B, registry);
|
||||
config.combineTransformerConfig(registry);
|
||||
config.registerCombinedTransformers(registry);
|
||||
|
||||
assertEquals(0, registry.errorMessages.size());
|
||||
assertEquals(4, config.buildTransformConfig().getTransformers().size());
|
||||
assertEquals("4", registry.findTransformerName("mimetype/a", -1,
|
||||
"mimetype/d", emptyMap(), null));
|
||||
|
||||
// The pipeline could do A2D and A2E, but as A2E is also supported by the first transformer it is not included.
|
||||
assertEquals("1", registry.findTransformerName("mimetype/a", -1,
|
||||
"mimetype/e", emptyMap(), null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPipelineUnsupportedIntermediate()
|
||||
{
|
||||
final TransformConfig transformConfig = TransformConfig.builder()
|
||||
.withTransformers(ImmutableList.of(
|
||||
TRANSFORMER1_A2B_A2E,
|
||||
TRANSFORMER2_B2X,
|
||||
TRANSFORMER3_C2D,
|
||||
PIPELINE4_1B2C3))
|
||||
.build();
|
||||
|
||||
config.addTransformConfig(transformConfig, READ_FROM_B, BASE_URL_B, registry);
|
||||
config.combineTransformerConfig(registry);
|
||||
|
||||
String expected = expectedWildcardError("the step transformer \"2\" does not support \"mimetype/b\" to \"mimetype/c\"");
|
||||
assertEquals(1, registry.errorMessages.size());
|
||||
assertEquals(expected, registry.errorMessages.get(0));
|
||||
|
||||
// 4: the pipeline is not removed, but will not be used as it has no supported transforms.
|
||||
assertEquals(4, config.buildTransformConfig().getTransformers().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWildcardFailover()
|
||||
{
|
||||
final TransformConfig transformConfig = TransformConfig.builder()
|
||||
.withTransformers(ImmutableList.of(
|
||||
TRANSFORMER1_A2B_A2E,
|
||||
TRANSFORMER2_B2C,
|
||||
TRANSFORMER3_C2D,
|
||||
FAILOVER4_123))
|
||||
.build();
|
||||
|
||||
config.addTransformConfig(transformConfig, READ_FROM_B, BASE_URL_B, registry);
|
||||
config.combineTransformerConfig(registry);
|
||||
config.registerCombinedTransformers(registry);
|
||||
|
||||
assertEquals(0, registry.errorMessages.size());
|
||||
assertEquals(4, config.buildTransformConfig().getTransformers().size());
|
||||
assertEquals("4", registry.findTransformerName("mimetype/a", -1,
|
||||
"mimetype/b", emptyMap(), null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWildcardFailoverNoneSupported()
|
||||
{
|
||||
final TransformConfig transformConfig = TransformConfig.builder()
|
||||
.withTransformers(ImmutableList.of(
|
||||
TRANSFORMER1,
|
||||
TRANSFORMER2,
|
||||
TRANSFORMER3,
|
||||
FAILOVER4_123))
|
||||
.build();
|
||||
|
||||
config.addTransformConfig(transformConfig, READ_FROM_B, BASE_URL_B, registry);
|
||||
config.combineTransformerConfig(registry);
|
||||
|
||||
String expected = expectedWildcardError("the step transforms don't support any");
|
||||
assertEquals(1, registry.errorMessages.size());
|
||||
assertEquals(expected, registry.errorMessages.get(0));
|
||||
}
|
||||
}
|
@@ -0,0 +1,460 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Transform Model
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2021 Alfresco Software Limited
|
||||
* %%
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 General Lesser Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Lesser Public
|
||||
* License along with this program. If not, see
|
||||
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.transform.client.registry;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import org.alfresco.transform.client.model.config.AddSupported;
|
||||
import org.alfresco.transform.client.model.config.SupportedDefaults;
|
||||
import org.alfresco.transform.client.model.config.OverrideSupported;
|
||||
import org.alfresco.transform.client.model.config.RemoveSupported;
|
||||
import org.alfresco.transform.client.model.config.SupportedSourceAndTarget;
|
||||
import org.alfresco.transform.client.model.config.TransformConfig;
|
||||
import org.alfresco.transform.client.model.config.Transformer;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import static junit.framework.TestCase.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* Tests the json elements: {@code removeTransformers}, {@code addSupported}, {@code removeSupported},
|
||||
* {@code overrideSupported} and {@code supportedDefaults}.
|
||||
*/
|
||||
public class OverrideTransformConfigTests
|
||||
{
|
||||
private static final String READ_FROM_A = "readFromA";
|
||||
private static final String READ_FROM_B = "readFromB";
|
||||
private static final String BASE_URL_A = "baseUrlA";
|
||||
private static final String BASE_URL_B = "baseUrlB";
|
||||
|
||||
private final SupportedSourceAndTarget supported_A2B = SupportedSourceAndTarget.builder()
|
||||
.withSourceMediaType("mimetype/a")
|
||||
.withTargetMediaType("mimetype/b")
|
||||
.build();
|
||||
|
||||
private final SupportedSourceAndTarget supported_A2B__40 = SupportedSourceAndTarget.builder()
|
||||
.withSourceMediaType("mimetype/a")
|
||||
.withTargetMediaType("mimetype/b")
|
||||
.withPriority(40)
|
||||
.build();
|
||||
|
||||
private final SupportedSourceAndTarget supported_C2D = SupportedSourceAndTarget.builder()
|
||||
.withSourceMediaType("mimetype/c")
|
||||
.withTargetMediaType("mimetype/d")
|
||||
.build();
|
||||
|
||||
private final SupportedSourceAndTarget supported_A2D_1234_44 = SupportedSourceAndTarget.builder()
|
||||
.withSourceMediaType("mimetype/a")
|
||||
.withTargetMediaType("mimetype/d")
|
||||
.withMaxSourceSizeBytes(1234L)
|
||||
.withPriority(44)
|
||||
.build();
|
||||
|
||||
private final SupportedSourceAndTarget supported_X2Y_100_23 = SupportedSourceAndTarget.builder()
|
||||
.withSourceMediaType("mimetype/x")
|
||||
.withTargetMediaType("mimetype/y")
|
||||
.withMaxSourceSizeBytes(100L)
|
||||
.withPriority(23)
|
||||
.build();
|
||||
|
||||
private final SupportedSourceAndTarget supported_X2Y_200 = SupportedSourceAndTarget.builder()
|
||||
.withSourceMediaType("mimetype/x")
|
||||
.withTargetMediaType("mimetype/y")
|
||||
.withMaxSourceSizeBytes(200L)
|
||||
.build();
|
||||
|
||||
private final TransformConfig transformConfig_A2B_X2Y_100_23 = TransformConfig.builder()
|
||||
.withTransformers(ImmutableList.of(
|
||||
Transformer.builder().withTransformerName("1")
|
||||
.withSupportedSourceAndTargetList(new HashSet<>(Set.of(
|
||||
supported_A2B,
|
||||
supported_X2Y_100_23)))
|
||||
.build()))
|
||||
.build();
|
||||
|
||||
private final CombinedTransformConfig config = new CombinedTransformConfig();
|
||||
|
||||
private final TestTransformRegistry registry = new TestTransformRegistry();
|
||||
|
||||
@Test
|
||||
public void testRemoveTransformers()
|
||||
{
|
||||
final Transformer transformer1 = Transformer.builder().withTransformerName("1").build();
|
||||
final Transformer transformer2 = Transformer.builder().withTransformerName("2").build();
|
||||
final Transformer transformer3 = Transformer.builder().withTransformerName("3").build();
|
||||
final Transformer transformer4 = Transformer.builder().withTransformerName("4").build();
|
||||
|
||||
final TransformConfig firstConfig = TransformConfig.builder()
|
||||
.withTransformers(ImmutableList.of(
|
||||
transformer1,
|
||||
transformer2,
|
||||
transformer3,
|
||||
transformer4))
|
||||
.build();
|
||||
final TransformConfig secondConfig = TransformConfig.builder()
|
||||
.withTransformers(ImmutableList.of(
|
||||
transformer2)) // Puts transform 2 back again
|
||||
.withRemoveTransformers(ImmutableSet.of("2", "7", "3", "2", "5"))
|
||||
.build();
|
||||
|
||||
config.addTransformConfig(firstConfig, READ_FROM_A, BASE_URL_A, registry);
|
||||
TransformConfig resultConfig = config.buildTransformConfig();
|
||||
assertEquals(4, resultConfig.getTransformers().size());
|
||||
|
||||
config.addTransformConfig(secondConfig, READ_FROM_B, BASE_URL_B, registry);
|
||||
resultConfig = config.buildTransformConfig();
|
||||
assertEquals(3, resultConfig.getTransformers().size());
|
||||
|
||||
String expected = "Unable to process \"removeTransformers\": [\"7\", \"5\"]. Read from readFromB";
|
||||
assertEquals(1, registry.warnMessages.size());
|
||||
assertEquals(expected, registry.warnMessages.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSupportedDefaultsSet()
|
||||
{
|
||||
SupportedDefaults default_1A_100 = SupportedDefaults.builder()
|
||||
.withTransformerName("1")
|
||||
.withSourceMediaType("mimetype/a")
|
||||
.withMaxSourceSizeBytes(100L)
|
||||
.build();
|
||||
|
||||
SupportedDefaults default_1A_200 = SupportedDefaults.builder()
|
||||
.withTransformerName("1")
|
||||
.withSourceMediaType("mimetype/a")
|
||||
.withMaxSourceSizeBytes(200L)
|
||||
.build();
|
||||
|
||||
SupportedDefaults default_2A__45 = SupportedDefaults.builder()
|
||||
.withTransformerName("2")
|
||||
.withSourceMediaType("mimetype/a")
|
||||
.withPriority(45)
|
||||
.build();
|
||||
|
||||
SupportedDefaults default_3_400 = SupportedDefaults.builder()
|
||||
.withTransformerName("3")
|
||||
.withMaxSourceSizeBytes(400L)
|
||||
.build();
|
||||
|
||||
SupportedDefaults default_B_400 = SupportedDefaults.builder()
|
||||
.withSourceMediaType("mimetype/b")
|
||||
.withMaxSourceSizeBytes(400L)
|
||||
.build();
|
||||
|
||||
SupportedDefaults default_B_500 = SupportedDefaults.builder()
|
||||
.withSourceMediaType("mimetype/b")
|
||||
.withMaxSourceSizeBytes(500L)
|
||||
.build();
|
||||
|
||||
SupportedDefaults default__600 = SupportedDefaults.builder()
|
||||
.withMaxSourceSizeBytes(600L)
|
||||
.build();
|
||||
|
||||
SupportedDefaults default___45 = SupportedDefaults.builder()
|
||||
.withPriority(45)
|
||||
.build();
|
||||
|
||||
SupportedDefaults default___50 = SupportedDefaults.builder()
|
||||
.withPriority(50)
|
||||
.build();
|
||||
|
||||
SupportedDefaults default__500_50 = SupportedDefaults.builder()
|
||||
.withMaxSourceSizeBytes(500L)
|
||||
.withPriority(50)
|
||||
.build();
|
||||
|
||||
SupportedDefaults default__600_45 = SupportedDefaults.builder()
|
||||
.withMaxSourceSizeBytes(600L)
|
||||
.withPriority(45)
|
||||
.build();
|
||||
|
||||
final TransformConfig firstConfig = TransformConfig.builder()
|
||||
.build();
|
||||
|
||||
final TransformConfig secondConfig = TransformConfig.builder()
|
||||
.withSupportedDefaults(ImmutableSet.of(
|
||||
default_1A_100)) // 0: transformer and source media type default
|
||||
.build();
|
||||
|
||||
final TransformConfig thirdConfig = TransformConfig.builder()
|
||||
.withSupportedDefaults(ImmutableSet.of(
|
||||
default_1A_200, // 0: transformer and source media type default
|
||||
default_2A__45, // 0: transformer and source media type default
|
||||
default_3_400, // 1: transformer default
|
||||
default_B_400, // 2: source media type default
|
||||
default_B_500, // 2: source media type default - overrides the previous value 400 defined in the same config
|
||||
default__500_50, // 3: system wide default - totally overridden by the next lines.
|
||||
default__600, // 3: system wide default
|
||||
default___50, // 3: system wide default (combined with the other system default)
|
||||
default___45)) // 3: system wide default - overrides the value 45 defined in the same config
|
||||
.build();
|
||||
|
||||
final TransformConfig fourthConfig = TransformConfig.builder()
|
||||
.withSupportedDefaults(ImmutableSet.of(
|
||||
SupportedDefaults.builder() // 3: system wide default
|
||||
.withMaxSourceSizeBytes(-1L)
|
||||
.withPriority(45)
|
||||
.build()))
|
||||
.build();
|
||||
|
||||
final TransformConfig fifthConfig = TransformConfig.builder()
|
||||
.withSupportedDefaults(ImmutableSet.of(
|
||||
SupportedDefaults.builder() // 3: system wide default (reset to the default, so removed)
|
||||
.withPriority(50)
|
||||
.build(),
|
||||
SupportedDefaults.builder() // Invalid as neither priority nor maxSourceSizeBytes are set
|
||||
.withTransformerName("9")
|
||||
.withSourceMediaType("mimetype/z")
|
||||
.build()))
|
||||
.build();
|
||||
|
||||
|
||||
config.addTransformConfig(firstConfig, READ_FROM_A, BASE_URL_A, registry);
|
||||
TransformConfig resultConfig = config.buildTransformConfig();
|
||||
assertEquals(0, resultConfig.getSupportedDefaults().size());
|
||||
|
||||
config.addTransformConfig(secondConfig, READ_FROM_B, BASE_URL_B, registry);
|
||||
resultConfig = config.buildTransformConfig();
|
||||
assertEquals(ImmutableSet.of(
|
||||
default_1A_100),
|
||||
resultConfig.getSupportedDefaults());
|
||||
|
||||
config.addTransformConfig(thirdConfig, READ_FROM_B, BASE_URL_B, registry);
|
||||
resultConfig = config.buildTransformConfig();
|
||||
assertEquals(ImmutableSet.of(
|
||||
default_1A_200, // overrides default_1A_100
|
||||
default_2A__45,
|
||||
default_3_400,
|
||||
default_B_500,
|
||||
default__600_45), // default__600 + default___45
|
||||
resultConfig.getSupportedDefaults());
|
||||
|
||||
config.addTransformConfig(fourthConfig, READ_FROM_B, BASE_URL_B, registry);
|
||||
resultConfig = config.buildTransformConfig();
|
||||
assertEquals(5, resultConfig.getSupportedDefaults().size());
|
||||
|
||||
config.addTransformConfig(fifthConfig, READ_FROM_A, BASE_URL_A, registry);
|
||||
resultConfig = config.buildTransformConfig();
|
||||
assertEquals(4, resultConfig.getSupportedDefaults().size());
|
||||
assertEquals(ImmutableSet.of(
|
||||
default_1A_200, // overrides default_1A_100
|
||||
default_2A__45,
|
||||
default_3_400,
|
||||
default_B_500), // default__600_45 removed as the system defaults have been reset to the defaults -1 and 50
|
||||
resultConfig.getSupportedDefaults());
|
||||
|
||||
String expected = "Unable to process \"supportedDefaults\": [" +
|
||||
"{\"transformerName\": \"9\", \"sourceMediaType\": \"mimetype/z\"}]. Read from readFromA";
|
||||
assertEquals(1, registry.warnMessages.size());
|
||||
assertEquals(expected, registry.warnMessages.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoveSupported()
|
||||
{
|
||||
addTransformConfig_A2B_X2Y_100_23();
|
||||
|
||||
final TransformConfig secondConfig = TransformConfig.builder()
|
||||
.withRemoveSupported(ImmutableSet.of(
|
||||
RemoveSupported.builder()
|
||||
.withTransformerName("1") // c -> d does not exist
|
||||
.withSourceMediaType("mimetype/c")
|
||||
.withTargetMediaType("mimetype/d")
|
||||
.build(),
|
||||
RemoveSupported.builder()
|
||||
.withTransformerName("1")
|
||||
.withSourceMediaType("mimetype/a")
|
||||
.withTargetMediaType("mimetype/b")
|
||||
.build(),
|
||||
RemoveSupported.builder() // transformer does not exist
|
||||
.withTransformerName("bad")
|
||||
.withSourceMediaType("mimetype/a")
|
||||
.withTargetMediaType("mimetype/d")
|
||||
.build(),
|
||||
RemoveSupported.builder() // transform name not set
|
||||
.withSourceMediaType("mimetype/a")
|
||||
.withTargetMediaType("mimetype/d")
|
||||
.build(),
|
||||
RemoveSupported.builder() // source type not set
|
||||
.withTransformerName("1")
|
||||
.withTargetMediaType("mimetype/d")
|
||||
.build(),
|
||||
RemoveSupported.builder() // target type not set
|
||||
.withTransformerName("1")
|
||||
.withSourceMediaType("mimetype/a")
|
||||
.build()))
|
||||
.build();
|
||||
|
||||
String expectedWarnMessage = "Unable to process \"removeSupported\": [" +
|
||||
"{\"transformerName\": \"bad\", \"sourceMediaType\": \"mimetype/a\", \"targetMediaType\": \"mimetype/d\"}, " +
|
||||
"{\"transformerName\": \"1\", \"sourceMediaType\": \"mimetype/a\"}, " +
|
||||
"{\"transformerName\": \"1\", \"sourceMediaType\": \"mimetype/c\", \"targetMediaType\": \"mimetype/d\"}, " +
|
||||
"{\"sourceMediaType\": \"mimetype/a\", \"targetMediaType\": \"mimetype/d\"}, " +
|
||||
"{\"transformerName\": \"1\", \"targetMediaType\": \"mimetype/d\"}]. " +
|
||||
"Read from readFromB";
|
||||
ImmutableSet<SupportedSourceAndTarget> expectedSupported = ImmutableSet.of(supported_X2Y_100_23);
|
||||
String expectedToString = "[" +
|
||||
"{\"sourceMediaType\": \"mimetype/x\", \"targetMediaType\": \"mimetype/y\", \"maxSourceSizeBytes\": \"100\", \"priority\": \"23\"}" +
|
||||
"]";
|
||||
|
||||
addTransformConfig(secondConfig, expectedWarnMessage, expectedSupported, expectedToString);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddSupported()
|
||||
{
|
||||
addTransformConfig_A2B_X2Y_100_23();
|
||||
|
||||
final TransformConfig secondConfig = TransformConfig.builder()
|
||||
.withAddSupported(ImmutableSet.of(
|
||||
AddSupported.builder()
|
||||
.withTransformerName("1")
|
||||
.withSourceMediaType("mimetype/c")
|
||||
.withTargetMediaType("mimetype/d")
|
||||
.build(),
|
||||
AddSupported.builder() // duplicates original
|
||||
.withTransformerName("1")
|
||||
.withSourceMediaType("mimetype/a")
|
||||
.withTargetMediaType("mimetype/b")
|
||||
.withPriority(40)
|
||||
.build(),
|
||||
AddSupported.builder()
|
||||
.withTransformerName("1")
|
||||
.withSourceMediaType("mimetype/a")
|
||||
.withTargetMediaType("mimetype/d")
|
||||
.withPriority(44)
|
||||
.withMaxSourceSizeBytes(1234)
|
||||
.build(),
|
||||
AddSupported.builder() // transformer does not exist
|
||||
.withTransformerName("bad")
|
||||
.withSourceMediaType("mimetype/a")
|
||||
.withTargetMediaType("mimetype/d")
|
||||
.build(),
|
||||
AddSupported.builder() // transform name not set
|
||||
.withSourceMediaType("mimetype/a")
|
||||
.withTargetMediaType("mimetype/d")
|
||||
.build(),
|
||||
AddSupported.builder() // source type not set
|
||||
.withTransformerName("1")
|
||||
.withTargetMediaType("mimetype/d")
|
||||
.build(),
|
||||
AddSupported.builder() // target type not set
|
||||
.withTransformerName("1")
|
||||
.withSourceMediaType("mimetype/a")
|
||||
.build()))
|
||||
.build();
|
||||
|
||||
String expectedWarnMessage = "Unable to process \"addSupported\": [" +
|
||||
"{\"transformerName\": \"1\", \"sourceMediaType\": \"mimetype/a\"}, " +
|
||||
"{\"transformerName\": \"1\", \"targetMediaType\": \"mimetype/d\"}, " +
|
||||
"{\"transformerName\": \"1\", \"sourceMediaType\": \"mimetype/a\", \"targetMediaType\": \"mimetype/b\", \"priority\": \"40\"}, " +
|
||||
"{\"transformerName\": \"bad\", \"sourceMediaType\": \"mimetype/a\", \"targetMediaType\": \"mimetype/d\"}, " +
|
||||
"{\"sourceMediaType\": \"mimetype/a\", \"targetMediaType\": \"mimetype/d\"}]. " +
|
||||
"Read from readFromB";
|
||||
ImmutableSet<SupportedSourceAndTarget> expectedSupported = ImmutableSet.of(
|
||||
supported_A2B,
|
||||
supported_C2D,
|
||||
supported_X2Y_100_23,
|
||||
supported_A2D_1234_44);
|
||||
String expectedToString = "[" +
|
||||
"{\"sourceMediaType\": \"mimetype/x\", \"targetMediaType\": \"mimetype/y\", \"maxSourceSizeBytes\": \"100\", \"priority\": \"23\"}, " +
|
||||
"{\"sourceMediaType\": \"mimetype/a\", \"targetMediaType\": \"mimetype/d\", \"maxSourceSizeBytes\": \"1234\", \"priority\": \"44\"}, " +
|
||||
"{\"sourceMediaType\": \"mimetype/a\", \"targetMediaType\": \"mimetype/b\"}, " + // priority and size should be missing (i.e. use defaults)
|
||||
"{\"sourceMediaType\": \"mimetype/c\", \"targetMediaType\": \"mimetype/d\"}" +
|
||||
"]";
|
||||
|
||||
addTransformConfig(secondConfig, expectedWarnMessage, expectedSupported, expectedToString);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOverrideSupported()
|
||||
{
|
||||
addTransformConfig_A2B_X2Y_100_23();
|
||||
|
||||
final TransformConfig secondConfig = TransformConfig.builder()
|
||||
.withOverrideSupported(ImmutableSet.of(
|
||||
OverrideSupported.builder() // does not exist
|
||||
.withTransformerName("1")
|
||||
.withSourceMediaType("mimetype/c")
|
||||
.withTargetMediaType("mimetype/d")
|
||||
.build(),
|
||||
OverrideSupported.builder() // size default -> 200 and priority default -> 100
|
||||
.withTransformerName("1")
|
||||
.withSourceMediaType("mimetype/a")
|
||||
.withTargetMediaType("mimetype/b")
|
||||
.withPriority(40)
|
||||
.build(),
|
||||
OverrideSupported.builder() // size 100 -> 200 and change priority to default
|
||||
.withTransformerName("1")
|
||||
.withSourceMediaType("mimetype/x")
|
||||
.withTargetMediaType("mimetype/y")
|
||||
.withMaxSourceSizeBytes(200)
|
||||
.build(),
|
||||
OverrideSupported.builder() // transformer does not exist
|
||||
.withTransformerName("bad")
|
||||
.withSourceMediaType("mimetype/a")
|
||||
.withTargetMediaType("mimetype/d")
|
||||
.build()))
|
||||
// OverrideSupported values with missing fields are defaults, so no test values here
|
||||
.build();
|
||||
|
||||
String expectedWarnMessage = "Unable to process \"overrideSupported\": [" +
|
||||
"{\"transformerName\": \"1\", \"sourceMediaType\": \"mimetype/c\", \"targetMediaType\": \"mimetype/d\"}, " +
|
||||
"{\"transformerName\": \"bad\", \"sourceMediaType\": \"mimetype/a\", \"targetMediaType\": \"mimetype/d\"}]. " +
|
||||
"Read from readFromB";
|
||||
ImmutableSet<SupportedSourceAndTarget> expectedSupported = ImmutableSet.of(
|
||||
supported_X2Y_200,
|
||||
supported_A2B__40);
|
||||
String expectedToString = "[" +
|
||||
"{\"sourceMediaType\": \"mimetype/a\", \"targetMediaType\": \"mimetype/b\", \"priority\": \"40\"}, " +
|
||||
"{\"sourceMediaType\": \"mimetype/x\", \"targetMediaType\": \"mimetype/y\", \"maxSourceSizeBytes\": \"200\"}" +
|
||||
"]";
|
||||
|
||||
addTransformConfig(secondConfig, expectedWarnMessage, expectedSupported, expectedToString);
|
||||
}
|
||||
|
||||
private void addTransformConfig_A2B_X2Y_100_23()
|
||||
{
|
||||
config.addTransformConfig(transformConfig_A2B_X2Y_100_23, READ_FROM_A, BASE_URL_A, registry);
|
||||
TransformConfig resultConfig = config.buildTransformConfig();
|
||||
assertEquals(1, resultConfig.getTransformers().size());
|
||||
assertEquals(2, resultConfig.getTransformers().get(0).getSupportedSourceAndTargetList().size());
|
||||
}
|
||||
|
||||
private void addTransformConfig(TransformConfig secondConfig, String expectedWarnMessage,
|
||||
Set<SupportedSourceAndTarget> expectedSupported, String expectedToString)
|
||||
{
|
||||
config.addTransformConfig(secondConfig, READ_FROM_B, BASE_URL_B, registry);
|
||||
TransformConfig resultConfig = config.buildTransformConfig();
|
||||
|
||||
assertEquals(1, registry.warnMessages.size());
|
||||
assertEquals(expectedWarnMessage, registry.warnMessages.get(0));
|
||||
|
||||
Set<SupportedSourceAndTarget> supportedSourceAndTargetList = resultConfig.getTransformers().get(0).getSupportedSourceAndTargetList();
|
||||
assertTrue(supportedSourceAndTargetList.equals(expectedSupported));
|
||||
|
||||
assertEquals("toString() difference", expectedToString, supportedSourceAndTargetList.toString());
|
||||
}
|
||||
}
|
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Transform Model
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2021 Alfresco Software Limited
|
||||
* %%
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 General Lesser Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Lesser Public
|
||||
* License along with this program. If not, see
|
||||
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.transform.client.registry;
|
||||
|
||||
import org.alfresco.transform.client.model.config.TransformOption;
|
||||
import org.alfresco.transform.client.model.config.Transformer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Helper class for testing an {@link AbstractTransformRegistry}.
|
||||
*/
|
||||
public class TestTransformRegistry extends AbstractTransformRegistry
|
||||
{
|
||||
private static final String READ_FROM_A = "readFromA";
|
||||
private static final String BASE_URL_B = "baseUrlB";
|
||||
|
||||
private final TransformCache data = new TransformCache();
|
||||
|
||||
List<String> errorMessages = new ArrayList<>();
|
||||
List<String> warnMessages = new ArrayList<>();
|
||||
int registeredCount = 0;
|
||||
int readFromACount = 0;
|
||||
int baseUrlBCount = 0;
|
||||
Map<Transformer, String> transformerBaseUrls = new HashMap<>();
|
||||
|
||||
@Override
|
||||
protected void logError(String msg)
|
||||
{
|
||||
System.out.println(msg);
|
||||
errorMessages.add(msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void logWarn(String msg)
|
||||
{
|
||||
System.out.println(msg);
|
||||
warnMessages.add(msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransformCache getData()
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void register(final Transformer transformer,
|
||||
final Map<String, Set<TransformOption>> transformOptions, final String baseUrl,
|
||||
final String readFrom)
|
||||
{
|
||||
super.register(transformer, transformOptions, baseUrl, readFrom);
|
||||
|
||||
registeredCount++;
|
||||
if (READ_FROM_A.equals(readFrom))
|
||||
{
|
||||
readFromACount++;
|
||||
}
|
||||
if (BASE_URL_B.equals(baseUrl))
|
||||
{
|
||||
baseUrlBCount++;
|
||||
}
|
||||
transformerBaseUrls.put(transformer, baseUrl);
|
||||
}
|
||||
}
|
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Transform Core
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2022 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* -
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
* -
|
||||
* Alfresco is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* -
|
||||
* Alfresco is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
* -
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.transform.client.registry;
|
||||
|
||||
import org.alfresco.transform.exceptions.TransformException;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static java.util.Collections.emptySet;
|
||||
import static org.alfresco.transform.client.registry.TransformRegistryHelper.retrieveTransformListBySize;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
public class TransformRegistryHelperTest
|
||||
{
|
||||
@Test
|
||||
public void testListBySize()
|
||||
{
|
||||
// This test was inspired by a failure to pick libreoffice over textToPdf despite the fact libreoffice has a
|
||||
// higher priority.
|
||||
SupportedTransform libreoffice = new SupportedTransform("libreoffice", emptySet(), -1, 50);
|
||||
SupportedTransform textToPdf = new SupportedTransform("textToPdf", emptySet(), 100,55);
|
||||
|
||||
assertOrder(asList(libreoffice, textToPdf), asList(libreoffice));
|
||||
assertOrder(asList(textToPdf, libreoffice), asList(libreoffice));
|
||||
|
||||
// * If multiple transforms with the same priority can support the same size, the one with the highest size
|
||||
// limit (or no limit) is used.
|
||||
// * Transforms with a higher priority (lower numerically) are used up to their size limit in preference to
|
||||
// lower priority transforms. These lower priority transforms will be used above that limit.
|
||||
// * If there are multiple transforms with the same priority and size limit, the last one defined is used to
|
||||
// allow extensions to override standard transforms.
|
||||
// * In each of the above cases, it is possible for supplied transforms not to be returned from
|
||||
// retrieveTransformListBySize as they will never be used. However this method is currently only used
|
||||
// by (1) AbstractTransformRegistry.findTransformerName which filters out transformers that cannot support a
|
||||
// given size and then uses the lowest element and (2) AbstractTransformRegistry.findMaxSize and gets the last
|
||||
// element without filtering and returns its size limit. So there are opportunities to change the code so that
|
||||
// it does not actually have to remove transformers that will not be used.
|
||||
|
||||
// Test transforms
|
||||
SupportedTransform p45 = new SupportedTransform( "p45", emptySet(), -1, 45);
|
||||
SupportedTransform p50 = new SupportedTransform( "p50", emptySet(), -1, 50);
|
||||
SupportedTransform p55 = new SupportedTransform( "p55", emptySet(), -1, 55);
|
||||
SupportedTransform s100p45 = new SupportedTransform("s100p45", emptySet(), 100, 45);
|
||||
SupportedTransform s100p50 = new SupportedTransform("s100p50", emptySet(), 100, 50);
|
||||
SupportedTransform s100p55 = new SupportedTransform("s100p55", emptySet(), 100, 55);
|
||||
SupportedTransform s200p50 = new SupportedTransform("s200p50", emptySet(), 200, 50);
|
||||
SupportedTransform s200p50b = new SupportedTransform("s200p50b", emptySet(), 200, 50);
|
||||
SupportedTransform s200p55 = new SupportedTransform("s200p55", emptySet(), 200, 55);
|
||||
SupportedTransform s300p45 = new SupportedTransform("s300p45", emptySet(), 300, 45);
|
||||
SupportedTransform s300p50 = new SupportedTransform("s300p50", emptySet(), 300, 50);
|
||||
SupportedTransform s300p55 = new SupportedTransform("s300p55", emptySet(), 300, 55);
|
||||
|
||||
// Just considers the priority
|
||||
assertOrder(asList(p50), asList(p50));
|
||||
assertOrder(asList(p45, p50), asList(p45));
|
||||
assertOrder(asList(p50, p55), asList(p50));
|
||||
assertOrder(asList(p50, p45), asList(p45));
|
||||
assertOrder(asList(p45, p50, p55), asList(p45));
|
||||
assertOrder(asList(p50, p55, p45), asList(p45));
|
||||
assertOrder(asList(p50, p45, p55), asList(p45));
|
||||
|
||||
// Just considers the priority as the size limit is the same
|
||||
assertOrder(asList(s100p45, s100p50, s100p55), asList(s100p45));
|
||||
assertOrder(asList(s100p50, s100p45, s100p55), asList(s100p45));
|
||||
|
||||
// Just considers size as the priority is the same
|
||||
assertOrder(asList(s100p50), asList(s100p50));
|
||||
assertOrder(asList(s100p50, s200p50), asList(s200p50));
|
||||
assertOrder(asList(s200p50, s100p50), asList(s200p50));
|
||||
assertOrder(asList(s100p50, s200p50, s300p50), asList(s300p50));
|
||||
assertOrder(asList(s200p50, s100p50, s300p50), asList(s300p50));
|
||||
assertOrder(asList(s300p50, s200p50, s100p50), asList(s300p50));
|
||||
|
||||
// Just considers the order in which they were defined as the priority and size limit are the same.
|
||||
assertOrder(asList(s200p50, s200p50b), asList(s200p50b));
|
||||
assertOrder(asList(s200p50b, s200p50), asList(s200p50));
|
||||
|
||||
// Combinations of priority and a size limit (always set)
|
||||
assertOrder(asList(s100p45, s100p50, s200p50, s200p55, s300p45, s300p50, s300p55), asList(s300p45));
|
||||
assertOrder(asList(s200p50, s300p55, s300p45, s100p45, s100p50, s300p50, s200p55), asList(s300p45));
|
||||
assertOrder(asList(s100p45, s200p50, s300p55), asList(s100p45, s200p50, s300p55));
|
||||
assertOrder(asList(s200p50, s100p45, s300p55), asList(s100p45, s200p50, s300p55));
|
||||
|
||||
// Combinations of priority and a size limit or no size limit
|
||||
assertOrder(asList(p45, s100p50, s200p50, s300p55), asList(p45));
|
||||
assertOrder(asList(s100p50, s200p50, s300p55, p45), asList(p45));
|
||||
assertOrder(asList(p55, s100p50, s200p50, s300p55), asList(s200p50, p55));
|
||||
assertOrder(asList(p50, s100p50, s200p50, s300p55), asList(p50));
|
||||
assertOrder(asList(s100p50, s200p50, s300p55, p50), asList(p50));
|
||||
}
|
||||
|
||||
private void assertOrder(List<SupportedTransform> transformsInLoadOrder, List<SupportedTransform> expectedList)
|
||||
{
|
||||
TransformRegistryHelper helper = new TransformRegistryHelper();
|
||||
TransformCache data = new TransformCache();
|
||||
transformsInLoadOrder.forEach(t->data.appendTransform("text/plain", "application/pdf", t,
|
||||
null, null));
|
||||
|
||||
List<SupportedTransform> supportedTransforms = retrieveTransformListBySize(data,
|
||||
"text/plain", "application/pdf", null, null);
|
||||
|
||||
// Check the values used.
|
||||
String transformerName = findTransformerName(supportedTransforms, 1);
|
||||
long maxSize = findMaxSize(supportedTransforms);
|
||||
String expectedTransformerName = expectedList.get(0).getName();
|
||||
long expectedMaxSourceSizeBytes = findMaxSize(expectedList);
|
||||
assertEquals(expectedList, supportedTransforms);
|
||||
assertEquals("Transform name", expectedTransformerName, transformerName);
|
||||
assertEquals("MaxSize", expectedMaxSourceSizeBytes, maxSize);
|
||||
|
||||
// If the above two pass, we don't really need the following one, but if it is wrong it might indicate
|
||||
// something is wrong, where the sourceSizeInBytes is not just 1.
|
||||
assertEquals(expectedList, supportedTransforms);
|
||||
}
|
||||
|
||||
// Similar to the method in AbstractTransformRegistry
|
||||
private String findTransformerName(List<SupportedTransform> supportedTransforms, final long sourceSizeInBytes)
|
||||
{
|
||||
return supportedTransforms
|
||||
.stream()
|
||||
.filter(t -> t.getMaxSourceSizeBytes() == -1 ||
|
||||
t.getMaxSourceSizeBytes() >= sourceSizeInBytes)
|
||||
.findFirst()
|
||||
.map(SupportedTransform::getName)
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
// Similar to the method in AbstractTransformRegistry
|
||||
private long findMaxSize(List<SupportedTransform> supportedTransforms)
|
||||
{
|
||||
return supportedTransforms.isEmpty() ? 0 :
|
||||
supportedTransforms.get(supportedTransforms.size() - 1).getMaxSourceSizeBytes();
|
||||
}
|
||||
|
||||
@Test(expected = TransformException.class)
|
||||
public void buildTransformListSourceMimeTypeNullErrorTest()
|
||||
{
|
||||
TransformCache data = new TransformCache();
|
||||
|
||||
retrieveTransformListBySize(data, null, "application/pdf", null, null);
|
||||
|
||||
fail("No exception raised");
|
||||
}
|
||||
|
||||
@Test(expected = TransformException.class)
|
||||
public void buildTransformListTargetMimeTypeNullErrorTest()
|
||||
{
|
||||
TransformCache data = new TransformCache();
|
||||
|
||||
retrieveTransformListBySize(data, "text/plain", null, null, null);
|
||||
|
||||
fail("No exception raised");
|
||||
}
|
||||
}
|
@@ -0,0 +1,622 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Transform Model
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2021 Alfresco Software Limited
|
||||
* %%
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 General Lesser Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Lesser Public
|
||||
* License along with this program. If not, see
|
||||
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.transform.client.registry;
|
||||
|
||||
import static java.util.Collections.emptyMap;
|
||||
import static java.util.Collections.emptySet;
|
||||
import static java.util.Collections.singleton;
|
||||
import static java.util.Collections.singletonList;
|
||||
import static java.util.Collections.singletonMap;
|
||||
import static java.util.function.Function.identity;
|
||||
import static java.util.stream.Collectors.toMap;
|
||||
import static org.alfresco.transform.client.registry.TransformRegistryHelper.addToPossibleTransformOptions;
|
||||
import static org.alfresco.transform.client.registry.TransformRegistryHelper.optionsMatch;
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.transform.client.model.config.SupportedSourceAndTarget;
|
||||
import org.alfresco.transform.client.model.config.TransformConfig;
|
||||
import org.alfresco.transform.client.model.config.TransformOption;
|
||||
import org.alfresco.transform.client.model.config.TransformOptionGroup;
|
||||
import org.alfresco.transform.client.model.config.TransformOptionValue;
|
||||
import org.alfresco.transform.client.model.config.Transformer;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
/**
|
||||
* Test the AbstractTransformRegistry, extended by both T-Engines and ACS repository, which need to
|
||||
* read JSON config to understand what is supported.
|
||||
*
|
||||
* @author adavis
|
||||
*/
|
||||
public class TransformRegistryTest
|
||||
{
|
||||
protected static final String GIF = "image/gif";
|
||||
protected static final String JPEG = "image/jpeg";
|
||||
protected static final String PDF = "application/pdf";
|
||||
protected static final String DOC = "application/msword";
|
||||
protected static final String XLS = "application/vnd.ms-excel";
|
||||
protected static final String PPT = "application/vnd.ms-powerpoint";
|
||||
protected static final String MSG = "application/vnd.ms-outlook";
|
||||
protected static final String TXT = "text/plain";
|
||||
|
||||
protected AbstractTransformRegistry registry;
|
||||
protected Map<String, Set<TransformOption>> mapOfTransformOptions;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception
|
||||
{
|
||||
registry = buildTransformServiceRegistryImpl();
|
||||
mapOfTransformOptions = new HashMap<>();
|
||||
}
|
||||
|
||||
protected AbstractTransformRegistry buildTransformServiceRegistryImpl() throws Exception
|
||||
{
|
||||
return new AbstractTransformRegistry()
|
||||
{
|
||||
private TransformCache data = new TransformCache();
|
||||
|
||||
@Override
|
||||
protected void logError(String msg)
|
||||
{
|
||||
System.out.println(msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void logWarn(String msg)
|
||||
{
|
||||
System.out.println(msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransformCache getData()
|
||||
{
|
||||
return data;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void assertAddToPossibleOptions(final TransformOptionGroup transformOptionGroup,
|
||||
final Set<String> actualOptionNames, final Set<String> expectedNameSet,
|
||||
final Set<String> expectedRequiredSet)
|
||||
{
|
||||
final Map<String, Boolean> possibleTransformOptions = new HashMap<>();
|
||||
|
||||
addToPossibleTransformOptions(possibleTransformOptions, transformOptionGroup, true,
|
||||
buildActualOptions(actualOptionNames));
|
||||
|
||||
assertEquals("The expected options don't match", expectedNameSet,
|
||||
possibleTransformOptions.keySet());
|
||||
|
||||
possibleTransformOptions.forEach((name, required) -> {
|
||||
if (required)
|
||||
{
|
||||
assertTrue(name + " should be REQUIRED", expectedRequiredSet.contains(name));
|
||||
}
|
||||
else
|
||||
{
|
||||
assertFalse(name + " should be OPTIONAL", expectedRequiredSet.contains(name));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// transformOptionNames are upper case if required.
|
||||
private void assertIsSupported(final Set<String> actualOptionNames,
|
||||
final Set<String> transformOptionNames, final String unsupportedMsg)
|
||||
{
|
||||
final Map<String, Boolean> transformOptions = transformOptionNames
|
||||
.stream()
|
||||
.collect(toMap(identity(), name -> name.toUpperCase().equals(name)));
|
||||
|
||||
boolean supported = optionsMatch(transformOptions, buildActualOptions(actualOptionNames));
|
||||
if (isBlank(unsupportedMsg))
|
||||
{
|
||||
assertTrue("Expected these options to be SUPPORTED", supported);
|
||||
}
|
||||
else
|
||||
{
|
||||
assertFalse("Expected these options NOT to be supported, because " + unsupportedMsg,
|
||||
supported);
|
||||
}
|
||||
}
|
||||
|
||||
private void assertTransformOptions(Set<TransformOption> setOfTransformOptions) throws Exception
|
||||
{
|
||||
final Transformer transformer = new Transformer("name", singleton("testOptions"), set(
|
||||
SupportedSourceAndTarget.builder()
|
||||
.withSourceMediaType(DOC)
|
||||
.withTargetMediaType(TXT)
|
||||
.build(),
|
||||
SupportedSourceAndTarget.builder()
|
||||
.withSourceMediaType(XLS)
|
||||
.withTargetMediaType(TXT)
|
||||
.withMaxSourceSizeBytes(1024000L)
|
||||
.build()));
|
||||
final TransformConfig transformConfig = TransformConfig
|
||||
.builder()
|
||||
.withTransformers(singletonList(transformer))
|
||||
.withTransformOptions(singletonMap("testOptions", setOfTransformOptions))
|
||||
.build();
|
||||
|
||||
registry = buildTransformServiceRegistryImpl();
|
||||
CombinedTransformConfig.combineAndRegister(transformConfig, getClass().getName(), getBaseUrl(transformer), registry);
|
||||
|
||||
assertTrue(registry.isSupported(XLS, 1024, TXT, emptyMap(), null));
|
||||
assertTrue(registry.isSupported(XLS, 1024000, TXT, null, null));
|
||||
assertFalse(registry.isSupported(XLS, 1024001, TXT, emptyMap(), null));
|
||||
assertTrue(registry.isSupported(DOC, 1024001, TXT, null, null));
|
||||
}
|
||||
|
||||
protected String getBaseUrl(Transformer transformer)
|
||||
{
|
||||
return "xxx";
|
||||
}
|
||||
|
||||
private void assertTransformerName(String sourceMimetype, long sourceSizeInBytes,
|
||||
String targetMimetype, Map<String, String> actualOptions, String expectedTransformerName,
|
||||
Transformer... transformers) throws Exception
|
||||
{
|
||||
buildAndPopulateRegistry(transformers);
|
||||
String transformerName = registry.findTransformerName(sourceMimetype, sourceSizeInBytes,
|
||||
targetMimetype, actualOptions, null);
|
||||
assertEquals(
|
||||
sourceMimetype + " to " + targetMimetype + " should have returned " + expectedTransformerName,
|
||||
expectedTransformerName, transformerName);
|
||||
}
|
||||
|
||||
private void assertSupported(final Transformer transformer, final String sourceMimetype,
|
||||
final long sourceSizeInBytes, final String targetMimetype,
|
||||
final Map<String, String> actualOptions, final String unsupportedMsg) throws Exception
|
||||
{
|
||||
assertSupported(sourceMimetype, sourceSizeInBytes, targetMimetype, actualOptions,
|
||||
unsupportedMsg, transformer);
|
||||
}
|
||||
|
||||
private void assertSupported(String sourceMimetype, long sourceSizeInBytes,
|
||||
String targetMimetype, Map<String, String> actualOptions, String unsupportedMsg,
|
||||
Transformer... transformers) throws Exception
|
||||
{
|
||||
buildAndPopulateRegistry(transformers);
|
||||
assertSupported(sourceMimetype, sourceSizeInBytes, targetMimetype, actualOptions, null,
|
||||
unsupportedMsg);
|
||||
}
|
||||
|
||||
private void buildAndPopulateRegistry(Transformer[] transformers) throws Exception
|
||||
{
|
||||
registry = buildTransformServiceRegistryImpl();
|
||||
TransformConfig transformConfig = TransformConfig.builder()
|
||||
.withTransformers(Arrays.asList(transformers))
|
||||
.withTransformOptions(mapOfTransformOptions)
|
||||
.build();
|
||||
CombinedTransformConfig.combineAndRegister(transformConfig, getClass().getName(), "---", registry);
|
||||
}
|
||||
|
||||
protected void assertSupported(String sourceMimetype, long sourceSizeInBytes,
|
||||
String targetMimetype, Map<String, String> actualOptions, String renditionName,
|
||||
String unsupportedMsg)
|
||||
{
|
||||
boolean supported = registry.isSupported(sourceMimetype, sourceSizeInBytes, targetMimetype,
|
||||
actualOptions, renditionName);
|
||||
if (unsupportedMsg == null || unsupportedMsg.isEmpty())
|
||||
{
|
||||
assertTrue(sourceMimetype + " to " + targetMimetype + " should be SUPPORTED",
|
||||
supported);
|
||||
}
|
||||
else
|
||||
{
|
||||
assertFalse(sourceMimetype + " to " + targetMimetype + " should NOT be supported",
|
||||
supported);
|
||||
}
|
||||
}
|
||||
|
||||
private static Map<String, String> buildActualOptions(final Set<String> optionNames)
|
||||
{
|
||||
return optionNames
|
||||
.stream()
|
||||
.collect(toMap(identity(), name -> "value for " + name));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOptionalGroups()
|
||||
{
|
||||
final TransformOptionGroup transformOptionGroup =
|
||||
new TransformOptionGroup(true, set(
|
||||
new TransformOptionValue(false, "1"),
|
||||
new TransformOptionValue(true, "2"),
|
||||
new TransformOptionGroup(false, set(
|
||||
new TransformOptionValue(false, "3.1"),
|
||||
new TransformOptionValue(false, "3.2"),
|
||||
new TransformOptionValue(false, "3.3"))),
|
||||
new TransformOptionGroup(false, set( // OPTIONAL
|
||||
new TransformOptionValue(false, "4.1"),
|
||||
new TransformOptionValue(true, "4.2"),
|
||||
new TransformOptionValue(false, "4.3")))));
|
||||
|
||||
assertAddToPossibleOptions(transformOptionGroup, emptySet(),
|
||||
set("1", "2"), set("2"));
|
||||
assertAddToPossibleOptions(transformOptionGroup, set("1"),
|
||||
set("1", "2"), set("2"));
|
||||
assertAddToPossibleOptions(transformOptionGroup, set("2"),
|
||||
set("1", "2"), set("2"));
|
||||
assertAddToPossibleOptions(transformOptionGroup, set("2", "3.2"),
|
||||
set("1", "2", "3.1", "3.2", "3.3"), set("2"));
|
||||
assertAddToPossibleOptions(transformOptionGroup, set("2", "4.1"),
|
||||
set("1", "2", "4.1", "4.2", "4.3"), set("2", "4.2"));
|
||||
assertAddToPossibleOptions(transformOptionGroup, set("2", "4.2"),
|
||||
set("1", "2", "4.1", "4.2", "4.3"), set("2", "4.2"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequiredGroup()
|
||||
{
|
||||
TransformOptionGroup transformOptionGroup =
|
||||
new TransformOptionGroup(true, set(
|
||||
new TransformOptionValue(false, "1"),
|
||||
new TransformOptionValue(true, "2"),
|
||||
new TransformOptionGroup(false, set(
|
||||
new TransformOptionValue(false, "3.1"),
|
||||
new TransformOptionValue(false, "3.2"),
|
||||
new TransformOptionValue(false, "3.3"))),
|
||||
new TransformOptionGroup(true, set(
|
||||
new TransformOptionValue(false, "4.1"),
|
||||
new TransformOptionValue(true, "4.2"),
|
||||
new TransformOptionValue(false, "4.3")))));
|
||||
|
||||
assertAddToPossibleOptions(transformOptionGroup, emptySet(),
|
||||
set("1", "2", "4.1", "4.2", "4.3"), set("2", "4.2"));
|
||||
assertAddToPossibleOptions(transformOptionGroup, set("1"),
|
||||
set("1", "2", "4.1", "4.2", "4.3"), set("2", "4.2"));
|
||||
assertAddToPossibleOptions(transformOptionGroup, set("2", "3.2"),
|
||||
set("1", "2", "3.1", "3.2", "3.3", "4.1", "4.2", "4.3"), set("2", "4.2"));
|
||||
assertAddToPossibleOptions(transformOptionGroup, set("2", "4.1"),
|
||||
set("1", "2", "4.1", "4.2", "4.3"), set("2", "4.2"));
|
||||
assertAddToPossibleOptions(transformOptionGroup, set("2", "4.2"),
|
||||
set("1", "2", "4.1", "4.2", "4.3"), set("2", "4.2"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNestedGroups()
|
||||
{
|
||||
TransformOptionGroup transformOptionGroup =
|
||||
new TransformOptionGroup(false, set(
|
||||
new TransformOptionGroup(false, set(
|
||||
new TransformOptionValue(false, "1"),
|
||||
new TransformOptionGroup(false, set(
|
||||
new TransformOptionValue(false, "1.2"),
|
||||
new TransformOptionGroup(false, set(
|
||||
new TransformOptionValue(false, "1.2.3"))))))),
|
||||
new TransformOptionGroup(false, set(
|
||||
new TransformOptionValue(false, "2"),
|
||||
new TransformOptionGroup(false, set(
|
||||
new TransformOptionValue(false, "2.2"),
|
||||
new TransformOptionGroup(false, set(
|
||||
new TransformOptionGroup(false, set(
|
||||
new TransformOptionValue(false, "2.2.1.2"))))))))),
|
||||
new TransformOptionGroup(false, set(
|
||||
new TransformOptionValue(true, "3"),
|
||||
new TransformOptionGroup(false, set(
|
||||
new TransformOptionGroup(false, set(
|
||||
new TransformOptionGroup(false, set(
|
||||
new TransformOptionValue(false, "3.1.1.2"))))))))),
|
||||
new TransformOptionGroup(false, set(
|
||||
new TransformOptionValue(false, "4"),
|
||||
new TransformOptionGroup(true, set(
|
||||
new TransformOptionGroup(false, set(
|
||||
new TransformOptionGroup(false, set(
|
||||
new TransformOptionValue(false, "4.1.1.2"))))))))),
|
||||
new TransformOptionGroup(false, set(
|
||||
new TransformOptionValue(false, "5"),
|
||||
new TransformOptionGroup(false, set(
|
||||
new TransformOptionGroup(true, set(
|
||||
new TransformOptionGroup(false, set(
|
||||
new TransformOptionValue(false, "5.1.1.2"))))))))),
|
||||
new TransformOptionGroup(false, set(
|
||||
new TransformOptionValue(false, "6"),
|
||||
new TransformOptionGroup(false, set(
|
||||
new TransformOptionGroup(false, set(
|
||||
new TransformOptionGroup(true, set(
|
||||
new TransformOptionValue(false, "6.1.1.2"))))))))),
|
||||
new TransformOptionGroup(false, set(
|
||||
new TransformOptionValue(false, "7"),
|
||||
new TransformOptionGroup(false, set(
|
||||
new TransformOptionGroup(false, set(
|
||||
new TransformOptionGroup(false, set(
|
||||
new TransformOptionValue(true, "7.1.1.2")))))))))
|
||||
));
|
||||
|
||||
assertAddToPossibleOptions(transformOptionGroup, emptySet(),
|
||||
emptySet(), emptySet());
|
||||
assertAddToPossibleOptions(transformOptionGroup, set("1"),
|
||||
set("1"), emptySet());
|
||||
assertAddToPossibleOptions(transformOptionGroup, set("1", "7"),
|
||||
set("1", "7"), emptySet());
|
||||
assertAddToPossibleOptions(transformOptionGroup, set("1", "7.1.1.2"),
|
||||
set("1", "7", "7.1.1.2"), set("7.1.1.2"));
|
||||
assertAddToPossibleOptions(transformOptionGroup, set("1", "6"),
|
||||
set("1", "6"), emptySet());
|
||||
assertAddToPossibleOptions(transformOptionGroup, set("1", "6.1.1.2"),
|
||||
set("1", "6", "6.1.1.2"), emptySet());
|
||||
assertAddToPossibleOptions(transformOptionGroup, set("1", "5"),
|
||||
set("1", "5"), emptySet());
|
||||
assertAddToPossibleOptions(transformOptionGroup, set("1", "5.1.1.2"),
|
||||
set("1", "5", "5.1.1.2"), emptySet());
|
||||
assertAddToPossibleOptions(transformOptionGroup, set("1", "4"),
|
||||
set("1", "4"), emptySet());
|
||||
assertAddToPossibleOptions(transformOptionGroup, set("1", "4.1.1.2"),
|
||||
set("1", "4", "4.1.1.2"), emptySet());
|
||||
assertAddToPossibleOptions(transformOptionGroup, set("1", "3"),
|
||||
set("1", "3"), set("3"));
|
||||
assertAddToPossibleOptions(transformOptionGroup, set("1", "3.1.1.2"),
|
||||
set("1", "3", "3.1.1.2"), set("3"));
|
||||
|
||||
assertAddToPossibleOptions(transformOptionGroup, set("2"),
|
||||
set("2"), emptySet());
|
||||
assertAddToPossibleOptions(transformOptionGroup, set("2", "2.2"),
|
||||
set("2", "2.2"), emptySet());
|
||||
assertAddToPossibleOptions(transformOptionGroup, set("3"),
|
||||
set("3"), set("3"));
|
||||
assertAddToPossibleOptions(transformOptionGroup, set("3.1.1.2"),
|
||||
set("3", "3.1.1.2"), set("3"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegistryIsSupportedMethod()
|
||||
{
|
||||
assertIsSupported(set("a"), set("a", "B", "c"), "required option B is missing");
|
||||
assertIsSupported(emptySet(), set("a", "B", "c"), "required option B is missing");
|
||||
assertIsSupported(set("B"), set("a", "B", "c"), null);
|
||||
assertIsSupported(set("B", "c"), set("a", "B", "c"), null);
|
||||
assertIsSupported(set("B", "a", "c"), set("a", "B", "c"), null);
|
||||
|
||||
assertIsSupported(set("B", "d"), set("a", "B", "c"), "there is an extra option d");
|
||||
assertIsSupported(set("B", "c", "d"), set("a", "B", "c"), "there is an extra option d");
|
||||
assertIsSupported(set("d"), set("a", "B", "c"),
|
||||
"required option B is missing and there is an extra option d");
|
||||
|
||||
assertIsSupported(set("a"), set("a", "b", "c"), null);
|
||||
assertIsSupported(emptySet(), set("a", "b", "c"), null);
|
||||
assertIsSupported(set("a", "b", "c"), set("a", "b", "c"), null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoActualOptions() throws Exception
|
||||
{
|
||||
assertTransformOptions(set(
|
||||
new TransformOptionValue(false, "option1"),
|
||||
new TransformOptionValue(false, "option2")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoTransformOptions() throws Exception
|
||||
{
|
||||
assertTransformOptions(emptySet());
|
||||
assertTransformOptions(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSupported() throws Exception
|
||||
{
|
||||
mapOfTransformOptions.put("options1", set(
|
||||
new TransformOptionValue(false, "page"),
|
||||
new TransformOptionValue(false, "width"),
|
||||
new TransformOptionValue(false, "height")));
|
||||
final Transformer transformer = new Transformer("name", singleton("options1"), set(
|
||||
SupportedSourceAndTarget.builder()
|
||||
.withSourceMediaType(DOC)
|
||||
.withTargetMediaType(GIF)
|
||||
.withMaxSourceSizeBytes(102400L)
|
||||
.build(),
|
||||
SupportedSourceAndTarget.builder()
|
||||
.withSourceMediaType(DOC)
|
||||
.withTargetMediaType(JPEG)
|
||||
.build(),
|
||||
SupportedSourceAndTarget.builder()
|
||||
.withSourceMediaType(MSG)
|
||||
.withTargetMediaType(GIF)
|
||||
.build()));
|
||||
|
||||
assertSupported(transformer, DOC, 1024, GIF, emptyMap(), null);
|
||||
assertSupported(transformer, DOC, 102400, GIF, emptyMap(), null);
|
||||
assertSupported(transformer, DOC, 102401, GIF, emptyMap(), "source is too large");
|
||||
assertSupported(transformer, DOC, 1024, JPEG, emptyMap(), null);
|
||||
assertSupported(transformer, GIF, 1024, DOC, emptyMap(),
|
||||
GIF + " is not a source of this transformer");
|
||||
assertSupported(transformer, MSG, 1024, GIF, emptyMap(), null);
|
||||
assertSupported(transformer, MSG, 1024, JPEG, emptyMap(),
|
||||
MSG + " to " + JPEG + " is not supported by this transformer");
|
||||
|
||||
assertSupported(transformer, DOC, 1024, GIF, buildActualOptions(set("page", "width")),
|
||||
null);
|
||||
assertSupported(transformer, DOC, 1024, GIF,
|
||||
buildActualOptions(set("page", "width", "startPage")), "startPage is not an option");
|
||||
}
|
||||
|
||||
@Test
|
||||
// renditionName used as the cache key, is an alias for a set of actualOptions and the target mimetype.
|
||||
// The source mimetype may change.
|
||||
public void testCache()
|
||||
{
|
||||
mapOfTransformOptions.put("options1", set(
|
||||
new TransformOptionValue(false, "page"),
|
||||
new TransformOptionValue(false, "width"),
|
||||
new TransformOptionValue(false, "height")));
|
||||
|
||||
final Transformer transformer = new Transformer("name", singleton("options1"), set(
|
||||
SupportedSourceAndTarget.builder()
|
||||
.withSourceMediaType(DOC)
|
||||
.withTargetMediaType(GIF)
|
||||
.withMaxSourceSizeBytes(102400L)
|
||||
.build(),
|
||||
SupportedSourceAndTarget.builder()
|
||||
.withSourceMediaType(MSG)
|
||||
.withTargetMediaType(GIF)
|
||||
.build()));
|
||||
|
||||
TransformConfig transformConfig = TransformConfig.builder()
|
||||
.withTransformers(Collections.singletonList(transformer))
|
||||
.withTransformOptions(mapOfTransformOptions)
|
||||
.build();
|
||||
CombinedTransformConfig.combineAndRegister(transformConfig, getClass().getName(), getBaseUrl(transformer), registry);
|
||||
|
||||
assertSupported(DOC, 1024, GIF, emptyMap(), "doclib", "");
|
||||
assertSupported(MSG, 1024, GIF, emptyMap(), "doclib", "");
|
||||
|
||||
assertEquals(102400L, registry.findMaxSize(DOC, GIF, emptyMap(), "doclib"));
|
||||
assertEquals(-1L, registry.findMaxSize(MSG, GIF, emptyMap(), "doclib"));
|
||||
|
||||
// check we are now using the cached value.
|
||||
final SupportedTransform cachedSupportedTransform = new SupportedTransform("name1",
|
||||
emptySet(), 999999L, 0);
|
||||
|
||||
registry.getData()
|
||||
.retrieveCached("doclib", DOC)
|
||||
.add(cachedSupportedTransform);
|
||||
assertEquals(999999L, registry.findMaxSize(DOC, GIF, emptyMap(), "doclib"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetTransformerName() throws Exception
|
||||
{
|
||||
Transformer t1 = newTransformer("transformer1", MSG, GIF, 100, 50);
|
||||
Transformer t2 = newTransformer("transformer2", MSG, GIF, 200, 60);
|
||||
Transformer t3 = newTransformer("transformer3", MSG, GIF, 200, 40);
|
||||
Transformer t4 = newTransformer("transformer4", MSG, GIF, -1, 100);
|
||||
Transformer t5 = newTransformer("transformer5", MSG, GIF, -1, 80);
|
||||
|
||||
// Select on size - priority is ignored
|
||||
assertTransformerName(MSG, 100, GIF, emptyMap(), "transformer1", t1, t2);
|
||||
assertTransformerName(MSG, 150, GIF, emptyMap(), "transformer2", t1, t2);
|
||||
assertTransformerName(MSG, 250, GIF, emptyMap(), null, t1, t2);
|
||||
// Select on priority - t1, t2 and t4 are discarded.
|
||||
// t3 is a higher priority and has a larger size than t1 and t2.
|
||||
// Similar story fo t4 with t5.
|
||||
assertTransformerName(MSG, 100, GIF, emptyMap(), "transformer3", t1, t2, t3, t4, t5);
|
||||
assertTransformerName(MSG, 200, GIF, emptyMap(), "transformer3", t1, t2, t3, t4, t5);
|
||||
// Select on size and priority, t1 and t2 discarded
|
||||
assertTransformerName(MSG, 200, GIF, emptyMap(), "transformer3", t1, t2, t3, t4);
|
||||
assertTransformerName(MSG, 300, GIF, emptyMap(), "transformer4", t1, t2, t3, t4);
|
||||
assertTransformerName(MSG, 300, GIF, emptyMap(), "transformer5", t1, t2, t3, t4, t5);
|
||||
}
|
||||
|
||||
private Transformer newTransformer(String transformerName, String sourceMediaType, String targetMediaType,
|
||||
long maxSourceSizeBytes, int priority)
|
||||
{
|
||||
return Transformer.builder().withTransformerName(transformerName)
|
||||
.withSupportedSourceAndTargetList(ImmutableSet.of(
|
||||
SupportedSourceAndTarget.builder()
|
||||
.withSourceMediaType(sourceMediaType)
|
||||
.withTargetMediaType(targetMediaType)
|
||||
.withMaxSourceSizeBytes(maxSourceSizeBytes)
|
||||
.withPriority(priority)
|
||||
.build()))
|
||||
.build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultipleTransformers() throws Exception
|
||||
{
|
||||
mapOfTransformOptions.put("options1", set(
|
||||
new TransformOptionValue(false, "page"),
|
||||
new TransformOptionValue(false, "width"),
|
||||
new TransformOptionValue(false, "height")));
|
||||
mapOfTransformOptions.put("options2", set(
|
||||
new TransformOptionValue(false, "opt1"),
|
||||
new TransformOptionValue(false, "opt2")));
|
||||
mapOfTransformOptions.put("options3", new HashSet<>(singletonList(
|
||||
new TransformOptionValue(false, "opt1"))));
|
||||
|
||||
Transformer transformer1 = new Transformer("transformer1", singleton("options1"), set(
|
||||
SupportedSourceAndTarget.builder()
|
||||
.withSourceMediaType(DOC)
|
||||
.withTargetMediaType(GIF)
|
||||
.withMaxSourceSizeBytes(102400L)
|
||||
.build(),
|
||||
SupportedSourceAndTarget.builder()
|
||||
.withSourceMediaType(DOC)
|
||||
.withTargetMediaType(JPEG)
|
||||
.build(),
|
||||
SupportedSourceAndTarget.builder()
|
||||
.withSourceMediaType(MSG)
|
||||
.withTargetMediaType(GIF)
|
||||
.build()));
|
||||
|
||||
Transformer transformer2 = new Transformer("transformer2", singleton("options2"), set(
|
||||
SupportedSourceAndTarget.builder()
|
||||
.withSourceMediaType(PDF)
|
||||
.withTargetMediaType(GIF)
|
||||
.build(),
|
||||
SupportedSourceAndTarget.builder()
|
||||
.withSourceMediaType(PPT)
|
||||
.withTargetMediaType(JPEG)
|
||||
.build()));
|
||||
|
||||
Transformer transformer3 = new Transformer("transformer3", singleton("options3"),
|
||||
new HashSet(singletonList(SupportedSourceAndTarget.builder()
|
||||
.withSourceMediaType(DOC)
|
||||
.withTargetMediaType(GIF)
|
||||
.build())));
|
||||
|
||||
assertSupported(DOC, 1024, GIF, emptyMap(), null, transformer1);
|
||||
assertSupported(DOC, 1024, GIF, emptyMap(), null, transformer1, transformer2);
|
||||
assertSupported(DOC, 1024, GIF, emptyMap(), null, transformer1, transformer2,
|
||||
transformer3);
|
||||
|
||||
assertSupported(DOC, 102401, GIF, emptyMap(), "source is too large", transformer1);
|
||||
assertSupported(DOC, 102401, GIF, emptyMap(), null, transformer1, transformer3);
|
||||
|
||||
assertSupported(PDF, 1024, GIF, emptyMap(), "Only transformer2 supports these mimetypes",
|
||||
transformer1);
|
||||
assertSupported(PDF, 1024, GIF, emptyMap(), null, transformer1, transformer2);
|
||||
assertSupported(PDF, 1024, GIF, emptyMap(), null, transformer1, transformer2,
|
||||
transformer3);
|
||||
|
||||
final Map<String, String> actualOptions = buildActualOptions(set("opt1"));
|
||||
assertSupported(PDF, 1024, GIF, actualOptions, "Only transformer2/4 supports these options",
|
||||
transformer1);
|
||||
assertSupported(PDF, 1024, GIF, actualOptions, null, transformer1, transformer2);
|
||||
assertSupported(PDF, 1024, GIF, actualOptions, null, transformer1, transformer2,
|
||||
transformer3);
|
||||
assertSupported(PDF, 1024, GIF, actualOptions,
|
||||
"transformer4 supports opt1 but not the source mimetype ", transformer1, transformer3);
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
private static <T> Set<T> set(T... elements)
|
||||
{
|
||||
if (elements == null || elements.length == 0)
|
||||
{
|
||||
return emptySet();
|
||||
}
|
||||
return ImmutableSet.copyOf(elements);
|
||||
}
|
||||
}
|
@@ -0,0 +1,537 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Transform Model
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2022 Alfresco Software Limited
|
||||
* %%
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 General Lesser Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Lesser Public
|
||||
* License along with this program. If not, see
|
||||
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.transform.router;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import org.alfresco.transform.client.model.InternalContext;
|
||||
import org.alfresco.transform.client.model.MultiStep;
|
||||
import org.alfresco.transform.client.model.TransformReply;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.alfresco.transform.router.TransformStack.OPTIONS_LEVEL;
|
||||
import static org.alfresco.transform.router.TransformStack.SEPARATOR;
|
||||
import static org.alfresco.transform.router.TransformStack.TOP_STACK_LEVEL;
|
||||
import static org.alfresco.transform.router.TransformStack.getInitialSourceReference;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
|
||||
class TransformStackTest
|
||||
{
|
||||
private static long START = System.currentTimeMillis();
|
||||
private static String STEP = SEPARATOR + "name" + SEPARATOR + "source" + SEPARATOR + "target";
|
||||
|
||||
@Mock
|
||||
private TransformerDebug transformerDebug;
|
||||
|
||||
@Mock
|
||||
private TransformReply reply;
|
||||
|
||||
// Note: If you change this also change AbstractRouterTest.testNestedTransform as they match
|
||||
public static final ImmutableMap<String, TransformStack.LevelBuilder> TEST_LEVELS = ImmutableMap.of(
|
||||
"top", TransformStack.levelBuilder(TransformStack.PIPELINE_FLAG)
|
||||
.withStep("pipeline 1-N", "type1", "typeN"),
|
||||
"pipeline 1-N", TransformStack.levelBuilder(TransformStack.PIPELINE_FLAG)
|
||||
.withStep("transform1-2", "type1", "type2")
|
||||
.withStep("pipeline 2-3", "type2", "type3")
|
||||
.withStep("failover 3-N", "type3", "typeN"),
|
||||
"pipeline 2-3", TransformStack.levelBuilder(TransformStack.PIPELINE_FLAG)
|
||||
.withStep("transform2-4", "type2", "type4")
|
||||
.withStep("transform4-3", "type4", "type3"),
|
||||
"failover 3-N", TransformStack.levelBuilder(TransformStack.FAILOVER_FLAG)
|
||||
.withStep("transform3-Na", "type3", "typeN")
|
||||
.withStep("transform3-Nb", "type3", "typeN")
|
||||
.withStep("pipeline 3-Nc", "type3", "typeN"),
|
||||
"pipeline 3-Nc", TransformStack.levelBuilder(TransformStack.PIPELINE_FLAG)
|
||||
.withStep("transform3-5", "type3", "type5")
|
||||
.withStep("pipeline 5-N", "type5", "typeN"),
|
||||
"pipeline 5-N", TransformStack.levelBuilder(TransformStack.PIPELINE_FLAG)
|
||||
.withStep("transform5-6", "type5", "type6")
|
||||
.withStep("transform6-N", "type6", "typeN"));
|
||||
private final InternalContext internalContext = new InternalContext();
|
||||
private final Map<String, String> options = ImmutableMap.of("key1", "value1", "key2", "", "key3", "value3");
|
||||
private final String sourceReference = UUID.randomUUID().toString();
|
||||
|
||||
@BeforeEach
|
||||
void setUp()
|
||||
{
|
||||
MockitoAnnotations.openMocks(this);
|
||||
|
||||
// Repeat what is done by Router.initialiseContext
|
||||
internalContext.setMultiStep(new MultiStep());
|
||||
internalContext.getMultiStep().setTransformsToBeDone(new ArrayList<>());
|
||||
TransformStack.setInitialTransformRequestOptions(internalContext, options);
|
||||
TransformStack.setInitialSourceReference(internalContext, sourceReference);
|
||||
doReturn(internalContext).when(reply).getInternalContext();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOptions()
|
||||
{
|
||||
assertEquals(options, TransformStack.getInitialTransformRequestOptions(internalContext));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOptionsEmpty()
|
||||
{
|
||||
ImmutableMap<String, String> options = ImmutableMap.of();
|
||||
|
||||
TransformStack.setInitialTransformRequestOptions(internalContext, options);
|
||||
assertEquals(options, TransformStack.getInitialTransformRequestOptions(internalContext));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOptionsEmptyLastValue()
|
||||
{
|
||||
ImmutableMap<String, String> options = ImmutableMap.of("key1", "value1", "key2", "");
|
||||
|
||||
TransformStack.setInitialTransformRequestOptions(internalContext, options);
|
||||
assertEquals(options, TransformStack.getInitialTransformRequestOptions(internalContext));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSourceReference()
|
||||
{
|
||||
assertEquals(sourceReference, getInitialSourceReference(internalContext));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSourceReferenceNull()
|
||||
{
|
||||
TransformStack.setInitialSourceReference(internalContext, null);
|
||||
assertEquals(null, getInitialSourceReference(internalContext));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSourceReferenceBlank()
|
||||
{
|
||||
TransformStack.setInitialSourceReference(internalContext, "");
|
||||
assertEquals("", getInitialSourceReference(internalContext));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLevelBuilder()
|
||||
{
|
||||
assertEquals("P⏐1⏐0⏐0⏐pipeline 1-N⏐type1⏐typeN", TEST_LEVELS.get("top").build());
|
||||
assertEquals("P⏐1⏐0⏐0⏐failover 3-N⏐type3⏐typeN⏐pipeline 2-3⏐type2⏐type3⏐transform1-2⏐type1⏐type2", TEST_LEVELS.get("pipeline 1-N").build());
|
||||
assertEquals("F⏐1⏐0⏐0⏐pipeline 3-Nc⏐type3⏐typeN⏐transform3-Nb⏐type3⏐typeN⏐transform3-Na⏐type3⏐typeN", TEST_LEVELS.get("failover 3-N").build());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAttemptedRetries()
|
||||
{
|
||||
TransformStack.addTransformLevel(internalContext, TEST_LEVELS.get("top"));
|
||||
assertEquals(0, TransformStack.getAttemptedRetries(internalContext));
|
||||
|
||||
TransformStack.incrementAttemptedRetries(internalContext);
|
||||
assertEquals(1, TransformStack.getAttemptedRetries(internalContext));
|
||||
|
||||
TransformStack.incrementAttemptedRetries(internalContext);
|
||||
assertEquals(2, TransformStack.getAttemptedRetries(internalContext));
|
||||
|
||||
TransformStack.resetAttemptedRetries(internalContext);
|
||||
assertEquals(0, TransformStack.getAttemptedRetries(internalContext));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReference()
|
||||
{
|
||||
TransformStack.addTransformLevel(internalContext, TEST_LEVELS.get("top"));
|
||||
assertEquals("1", TransformStack.getReference(internalContext));
|
||||
|
||||
TransformStack.setReference(internalContext, 123);
|
||||
assertEquals("123", TransformStack.getReference(internalContext));
|
||||
|
||||
TransformStack.addTransformLevel(internalContext, TEST_LEVELS.get("pipeline 1-N"));
|
||||
assertEquals("123.1", TransformStack.getReference(internalContext));
|
||||
|
||||
TransformStack.incrementReference(internalContext);
|
||||
assertEquals("123.2", TransformStack.getReference(internalContext));
|
||||
|
||||
TransformStack.addTransformLevel(internalContext, TEST_LEVELS.get("pipeline 2-3"));
|
||||
assertEquals("123.2.1", TransformStack.getReference(internalContext));
|
||||
|
||||
TransformStack.removeTransformLevel(internalContext);
|
||||
TransformStack.incrementReference(internalContext);
|
||||
assertEquals("123.3", TransformStack.getReference(internalContext));
|
||||
|
||||
TransformStack.removeTransformLevel(internalContext);
|
||||
assertEquals("123", TransformStack.getReference(internalContext));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetReferenceInADummyTopLevelIfUnset()
|
||||
{
|
||||
// Used when creating a TransformRouterException prior to setting the reference
|
||||
|
||||
// Undo setup()
|
||||
internalContext.getMultiStep().setTransformsToBeDone(new ArrayList<>());
|
||||
|
||||
TransformStack.setReferenceInADummyTopLevelIfUnset(internalContext, 23);
|
||||
assertEquals("23", TransformStack.getReference(internalContext));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReplicateWorkflowWithSuccess()
|
||||
{
|
||||
replicateWorkflowStepsPriorToFailureOrSuccess();
|
||||
|
||||
// Assume a successful transform, so successful there should be no more steps or levels after this
|
||||
TransformStack.removeSuccessfulStep(reply, transformerDebug);
|
||||
assertTrue(TransformStack.isFinished(internalContext));
|
||||
}
|
||||
|
||||
@Test
|
||||
// Tests the failure on a transform indirectly (it is a step in a pipeline) under a failover transformer.
|
||||
public void testReplicateWorkflowWithFailure()
|
||||
{
|
||||
replicateWorkflowStepsPriorToFailureOrSuccess();
|
||||
|
||||
// Assume a transform failure. While loop should remove the 2 indirect pipeline levels
|
||||
int removedLevels = 0;
|
||||
while (!TransformStack.isParentAFailover(internalContext))
|
||||
{
|
||||
removedLevels++;
|
||||
TransformStack.removeTransformLevel(internalContext);
|
||||
}
|
||||
assertEquals(2, removedLevels);
|
||||
assertTrue(TransformStack.isLastStepInTransformLevel(internalContext));
|
||||
TransformStack.removeFailedStep(reply, transformerDebug); // Should remove the rest as failure was last step in failover
|
||||
assertTrue(TransformStack.isFinished(internalContext));
|
||||
}
|
||||
|
||||
// Replicates the sequence of TransformStack method calls for a workflow. Steps through each transform, with
|
||||
// some failures in a failover transformer, before returning to allow the calling test method to either fail the
|
||||
// next step or not.
|
||||
private void replicateWorkflowStepsPriorToFailureOrSuccess()
|
||||
{
|
||||
// Initial transform request, so add a level
|
||||
TransformStack.addTransformLevel(internalContext, TEST_LEVELS.get("top"));
|
||||
assertFalse(TransformStack.isFinished(internalContext));
|
||||
TransformStack.Step step = TransformStack.currentStep(internalContext);
|
||||
|
||||
assertEquals("pipeline 1-N", step.getTransformerName());
|
||||
assertEquals("type1", step.getSourceMediaType());
|
||||
assertEquals("typeN", step.getTargetMediaType());
|
||||
assertEquals(null, TransformStack.getParentName(internalContext));
|
||||
assertFalse(TransformStack.isParentAFailover(internalContext));
|
||||
|
||||
// Because it is a pipeline, add a level
|
||||
TransformStack.addTransformLevel(internalContext, TEST_LEVELS.get("pipeline 1-N"));
|
||||
assertFalse(TransformStack.isFinished(internalContext));
|
||||
step = TransformStack.currentStep(internalContext);
|
||||
|
||||
assertEquals("transform1-2", step.getTransformerName());
|
||||
assertEquals("type1", step.getSourceMediaType());
|
||||
assertEquals("type2", step.getTargetMediaType());
|
||||
assertEquals("pipeline 1-N", TransformStack.getParentName(internalContext));
|
||||
assertFalse(TransformStack.isParentAFailover(internalContext));
|
||||
|
||||
// Assume a successful transform, so move on to next step add a level
|
||||
TransformStack.removeSuccessfulStep(reply, transformerDebug);
|
||||
assertFalse(TransformStack.isFinished(internalContext));
|
||||
step = TransformStack.currentStep(internalContext);
|
||||
|
||||
assertEquals("pipeline 2-3", step.getTransformerName());
|
||||
assertEquals("type2", step.getSourceMediaType());
|
||||
assertEquals("type3", step.getTargetMediaType());
|
||||
assertEquals("pipeline 1-N", TransformStack.getParentName(internalContext));
|
||||
assertFalse(TransformStack.isParentAFailover(internalContext));
|
||||
|
||||
// Because it is a pipeline, add a level
|
||||
TransformStack.addTransformLevel(internalContext, TEST_LEVELS.get("pipeline 2-3"));
|
||||
assertFalse(TransformStack.isFinished(internalContext));
|
||||
step = TransformStack.currentStep(internalContext);
|
||||
|
||||
assertEquals("transform2-4", step.getTransformerName());
|
||||
assertEquals("type2", step.getSourceMediaType());
|
||||
assertEquals("type4", step.getTargetMediaType());
|
||||
assertEquals("pipeline 2-3", TransformStack.getParentName(internalContext));
|
||||
assertFalse(TransformStack.isParentAFailover(internalContext));
|
||||
|
||||
// Assume a successful transform, so move on to next step add a level
|
||||
TransformStack.removeSuccessfulStep(reply, transformerDebug);
|
||||
assertFalse(TransformStack.isFinished(internalContext));
|
||||
step = TransformStack.currentStep(internalContext);
|
||||
|
||||
assertEquals("transform4-3", step.getTransformerName());
|
||||
assertEquals("type4", step.getSourceMediaType());
|
||||
assertEquals("type3", step.getTargetMediaType());
|
||||
assertEquals("pipeline 2-3", TransformStack.getParentName(internalContext));
|
||||
assertFalse(TransformStack.isParentAFailover(internalContext));
|
||||
|
||||
// Assume a successful transform, so move on to next step add a level
|
||||
TransformStack.removeSuccessfulStep(reply, transformerDebug);
|
||||
assertFalse(TransformStack.isFinished(internalContext));
|
||||
step = TransformStack.currentStep(internalContext);
|
||||
|
||||
assertEquals("failover 3-N", step.getTransformerName());
|
||||
assertEquals("type3", step.getSourceMediaType());
|
||||
assertEquals("typeN", step.getTargetMediaType());
|
||||
assertEquals("pipeline 1-N", TransformStack.getParentName(internalContext));
|
||||
assertFalse(TransformStack.isParentAFailover(internalContext));
|
||||
|
||||
// Because it is a failover, add a level
|
||||
TransformStack.addTransformLevel(internalContext, TEST_LEVELS.get("failover 3-N"));
|
||||
step = TransformStack.currentStep(internalContext);
|
||||
|
||||
assertEquals("transform3-Na", step.getTransformerName());
|
||||
assertEquals("type3", step.getSourceMediaType());
|
||||
assertEquals("typeN", step.getTargetMediaType());
|
||||
assertEquals("failover 3-N", TransformStack.getParentName(internalContext));
|
||||
assertTrue(TransformStack.isParentAFailover(internalContext));
|
||||
|
||||
// Assume 1st failover step fails
|
||||
while (!TransformStack.isParentAFailover(internalContext))
|
||||
{
|
||||
TransformStack.removeTransformLevel(internalContext);
|
||||
}
|
||||
assertFalse(TransformStack.isLastStepInTransformLevel(internalContext));
|
||||
TransformStack.removeFailedStep(reply, transformerDebug);
|
||||
assertFalse(TransformStack.isFinished(internalContext));
|
||||
step = TransformStack.currentStep(internalContext);
|
||||
|
||||
assertEquals("transform3-Nb", step.getTransformerName());
|
||||
assertEquals("type3", step.getSourceMediaType());
|
||||
assertEquals("typeN", step.getTargetMediaType());
|
||||
assertEquals("failover 3-N", TransformStack.getParentName(internalContext));
|
||||
assertTrue(TransformStack.isParentAFailover(internalContext));
|
||||
|
||||
// Assume 2nd failover step fails
|
||||
while (!TransformStack.isParentAFailover(internalContext))
|
||||
{
|
||||
TransformStack.removeTransformLevel(internalContext);
|
||||
}
|
||||
assertFalse(TransformStack.isLastStepInTransformLevel(internalContext));
|
||||
TransformStack.removeFailedStep(reply, transformerDebug);
|
||||
assertFalse(TransformStack.isFinished(internalContext));
|
||||
step = TransformStack.currentStep(internalContext);
|
||||
|
||||
assertEquals("pipeline 3-Nc", step.getTransformerName());
|
||||
assertEquals("type3", step.getSourceMediaType());
|
||||
assertEquals("typeN", step.getTargetMediaType());
|
||||
assertEquals("failover 3-N", TransformStack.getParentName(internalContext));
|
||||
assertTrue(TransformStack.isParentAFailover(internalContext));
|
||||
|
||||
// Because it is a pipeline, add a level
|
||||
TransformStack.addTransformLevel(internalContext, TEST_LEVELS.get("pipeline 3-Nc"));
|
||||
assertFalse(TransformStack.isFinished(internalContext));
|
||||
step = TransformStack.currentStep(internalContext);
|
||||
|
||||
assertEquals("transform3-5", step.getTransformerName());
|
||||
assertEquals("type3", step.getSourceMediaType());
|
||||
assertEquals("type5", step.getTargetMediaType());
|
||||
assertEquals("pipeline 3-Nc", TransformStack.getParentName(internalContext));
|
||||
assertFalse(TransformStack.isParentAFailover(internalContext));
|
||||
|
||||
// Assume a successful transform, so move on to next step add a level
|
||||
TransformStack.removeSuccessfulStep(reply, transformerDebug);
|
||||
assertFalse(TransformStack.isFinished(internalContext));
|
||||
step = TransformStack.currentStep(internalContext);
|
||||
|
||||
assertEquals("pipeline 5-N", step.getTransformerName());
|
||||
assertEquals("type5", step.getSourceMediaType());
|
||||
assertEquals("typeN", step.getTargetMediaType());
|
||||
assertEquals("pipeline 3-Nc", TransformStack.getParentName(internalContext));
|
||||
assertFalse(TransformStack.isParentAFailover(internalContext));
|
||||
|
||||
// Because it is a pipeline, add a level
|
||||
TransformStack.addTransformLevel(internalContext, TEST_LEVELS.get("pipeline 5-N"));
|
||||
assertFalse(TransformStack.isFinished(internalContext));
|
||||
step = TransformStack.currentStep(internalContext);
|
||||
|
||||
assertEquals("transform5-6", step.getTransformerName());
|
||||
assertEquals("type5", step.getSourceMediaType());
|
||||
assertEquals("type6", step.getTargetMediaType());
|
||||
assertEquals("pipeline 5-N", TransformStack.getParentName(internalContext));
|
||||
assertFalse(TransformStack.isParentAFailover(internalContext));
|
||||
|
||||
// Assume a successful transform, so move on to next step add a level
|
||||
TransformStack.removeSuccessfulStep(reply, transformerDebug);
|
||||
assertFalse(TransformStack.isFinished(internalContext));
|
||||
step = TransformStack.currentStep(internalContext);
|
||||
|
||||
assertEquals("transform6-N", step.getTransformerName());
|
||||
assertEquals("type6", step.getSourceMediaType());
|
||||
assertEquals("typeN", step.getTargetMediaType());
|
||||
assertEquals("pipeline 5-N", TransformStack.getParentName(internalContext));
|
||||
assertFalse(TransformStack.isParentAFailover(internalContext));
|
||||
}
|
||||
|
||||
@Test
|
||||
// Tests a workflow where all transforms are successful, using a loop.
|
||||
public void testWorkflowWithLoop()
|
||||
{
|
||||
TransformStack.addTransformLevel(internalContext, TEST_LEVELS.get("top"));
|
||||
int transformStepCount = 0;
|
||||
do
|
||||
{
|
||||
transformStepCount++;
|
||||
TransformStack.Step step = TransformStack.currentStep(internalContext);
|
||||
String transformerName = step.getTransformerName();
|
||||
int depth = internalContext.getMultiStep().getTransformsToBeDone().size() - 2;
|
||||
System.out.println(transformStepCount + " ".substring(0, depth*2+1) + transformerName);
|
||||
TransformStack.LevelBuilder nextLevel = TEST_LEVELS.get(transformerName);
|
||||
if (nextLevel == null)
|
||||
{
|
||||
TransformStack.removeSuccessfulStep(reply, transformerDebug);
|
||||
}
|
||||
else
|
||||
{
|
||||
TransformStack.addTransformLevel(internalContext, nextLevel);
|
||||
}
|
||||
if (transformStepCount >= 25)
|
||||
{
|
||||
fail("Appear to be in an infinite loop");
|
||||
}
|
||||
} while (!TransformStack.isFinished(internalContext));
|
||||
assertEquals(7, transformStepCount);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckStructureNoOptions()
|
||||
{
|
||||
internalContext.getMultiStep().setTransformsToBeDone(new ArrayList<>());
|
||||
|
||||
assertEquals("T-Reply InternalContext did not have the Stack set",
|
||||
TransformStack.checkStructure(internalContext, "T-Reply"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckStructureNoSourceRef()
|
||||
{
|
||||
internalContext.getMultiStep().setTransformsToBeDone(new ArrayList<>());
|
||||
TransformStack.setInitialTransformRequestOptions(internalContext, options);
|
||||
|
||||
assertEquals("T-Request InternalContext did not have the Stack set",
|
||||
TransformStack.checkStructure(internalContext, "T-Request"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckStructureNoStack()
|
||||
{
|
||||
internalContext.getMultiStep().setTransformsToBeDone(new ArrayList<>());
|
||||
TransformStack.setInitialTransformRequestOptions(internalContext, options);
|
||||
TransformStack.setInitialSourceReference(internalContext, sourceReference);
|
||||
|
||||
assertEquals("T-something InternalContext did not have the Stack set",
|
||||
TransformStack.checkStructure(internalContext, "T-something"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckStructureOptionsOk()
|
||||
{
|
||||
TransformStack.addTransformLevel(internalContext, TEST_LEVELS.get("top"));
|
||||
|
||||
for (String value : Arrays.asList(
|
||||
"",
|
||||
"key1" + SEPARATOR + "value1",
|
||||
"key1" + SEPARATOR + "value1" + SEPARATOR + "key2" + SEPARATOR + "value2"))
|
||||
{
|
||||
System.out.println("TransformOptions value: " + value);
|
||||
internalContext.getMultiStep().getTransformsToBeDone().set(OPTIONS_LEVEL, value);
|
||||
assertNull(TransformStack.checkStructure(internalContext, "T-Reply"));
|
||||
// call the getter just in case we have missed something
|
||||
TransformStack.getInitialTransformRequestOptions(internalContext);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckStructureOptionsBad()
|
||||
{
|
||||
TransformStack.addTransformLevel(internalContext, TEST_LEVELS.get("top"));
|
||||
|
||||
for (String value : Arrays.asList(
|
||||
null,
|
||||
"noValue",
|
||||
SEPARATOR + "noKey",
|
||||
"key" + SEPARATOR + "value" + SEPARATOR + "noKey"))
|
||||
{
|
||||
System.out.println("TransformOptions value: " + value);
|
||||
internalContext.getMultiStep().getTransformsToBeDone().set(OPTIONS_LEVEL, value);
|
||||
assertEquals("T-Reply InternalContext did not have the TransformOptions set correctly",
|
||||
TransformStack.checkStructure(internalContext, "T-Reply"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckStructureStackLevelsOk()
|
||||
{
|
||||
TransformStack.addTransformLevel(internalContext, TEST_LEVELS.get("top"));
|
||||
|
||||
for (String value : Arrays.asList(
|
||||
"P" + SEPARATOR + "20" + SEPARATOR + START + SEPARATOR + "1" + STEP,
|
||||
"P" + SEPARATOR + "4" + SEPARATOR + "123" + SEPARATOR + "12" + STEP + STEP))
|
||||
{
|
||||
System.out.println("TransformLevel value: " + value);
|
||||
internalContext.getMultiStep().getTransformsToBeDone().set(TOP_STACK_LEVEL, value);
|
||||
assertNull(TransformStack.checkStructure(internalContext, "T-Reply"));
|
||||
// call a getter just in case we have missed something
|
||||
TransformStack.currentStep(internalContext);
|
||||
};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckStructureStackLevelsBad()
|
||||
{
|
||||
TransformStack.addTransformLevel(internalContext, TEST_LEVELS.get("top"));
|
||||
|
||||
String MAX_INT_PLUS_1 = BigInteger.valueOf(Integer.MAX_VALUE + 1).toString();
|
||||
String MAX_LONG_PLUS_1 = BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.ONE).toString();
|
||||
|
||||
for (String value : Arrays.asList(
|
||||
null,
|
||||
"",
|
||||
"F" + SEPARATOR + "12" + SEPARATOR + START + SEPARATOR + "2",
|
||||
"F" + SEPARATOR + "-1" + SEPARATOR + START + SEPARATOR + "2" + STEP,
|
||||
"F" + SEPARATOR + "1" + SEPARATOR + "-3" + SEPARATOR + "2" + STEP,
|
||||
"F" + SEPARATOR + "1" + SEPARATOR + START + SEPARATOR + "-2" + STEP,
|
||||
"F" + SEPARATOR + "a" + SEPARATOR + START + SEPARATOR + "-2" + STEP,
|
||||
"F" + SEPARATOR + "1" + SEPARATOR + START + SEPARATOR + "b" + STEP,
|
||||
"P" + SEPARATOR + "0" + SEPARATOR + START + SEPARATOR + "12" + SEPARATOR + "name",
|
||||
"P" + SEPARATOR + "0" + SEPARATOR + START + SEPARATOR + "12" + SEPARATOR + "name" + SEPARATOR + "source",
|
||||
"P" + SEPARATOR + "0" + SEPARATOR + START + SEPARATOR + "12" + SEPARATOR + "name" + SEPARATOR + "source" + SEPARATOR + "",
|
||||
"P" + SEPARATOR + "0" + SEPARATOR + START + SEPARATOR + "12" + SEPARATOR + "name" + SEPARATOR + "" + SEPARATOR + "target",
|
||||
"F" + SEPARATOR + MAX_INT_PLUS_1 + SEPARATOR + START + SEPARATOR + "2" + STEP,
|
||||
"F" + SEPARATOR + "1" + SEPARATOR + MAX_LONG_PLUS_1 + SEPARATOR + "2" + STEP,
|
||||
"F" + SEPARATOR + "1" + SEPARATOR + START + SEPARATOR + MAX_INT_PLUS_1 + STEP
|
||||
))
|
||||
{
|
||||
System.out.println("TransformLevel value: " + value);
|
||||
internalContext.getMultiStep().getTransformsToBeDone().set(TOP_STACK_LEVEL, value);
|
||||
assertEquals("T-Reply InternalContext did not have levels set correctly",
|
||||
TransformStack.checkStructure(internalContext, "T-Reply"));
|
||||
};
|
||||
}
|
||||
}
|
@@ -0,0 +1,218 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Transform Model
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2022 Alfresco Software Limited
|
||||
* %%
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 General Lesser Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Lesser Public
|
||||
* License along with this program. If not, see
|
||||
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.transform.router;
|
||||
|
||||
import ch.qos.logback.classic.Level;
|
||||
import ch.qos.logback.classic.Logger;
|
||||
import ch.qos.logback.classic.LoggerContext;
|
||||
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||
import ch.qos.logback.core.AppenderBase;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import org.alfresco.transform.client.model.InternalContext;
|
||||
import org.alfresco.transform.client.model.TransformReply;
|
||||
import org.alfresco.transform.client.model.TransformRequest;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.StringJoiner;
|
||||
|
||||
import static org.alfresco.transform.client.model.Mimetype.MIMETYPE_TEXT_PLAIN;
|
||||
import static org.alfresco.transform.client.model.Mimetype.MIMETYPE_WORD;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* Tests TransformerDebug. AbstractRouterTest in the t-router contains more complete end to end tests. The tests in this
|
||||
* class are a smoke test at the moment.
|
||||
*/
|
||||
class TransformerDebugTest
|
||||
{
|
||||
private static String MIMETYPE_PDF = "application/pdf";
|
||||
|
||||
TransformerDebug transformerDebug = new TransformerDebug();
|
||||
|
||||
private StringJoiner transformerDebugOutput = new StringJoiner("\n");
|
||||
|
||||
public String getTransformerDebugOutput()
|
||||
{
|
||||
return transformerDebugOutput.toString()
|
||||
.replaceAll(" [\\d,]+ ms", " -- ms");
|
||||
}
|
||||
|
||||
private void twoStepTransform(boolean isTEngine, boolean fail, Level logLevel)
|
||||
{
|
||||
transformerDebug.setIsTEngine(isTEngine);
|
||||
monitorLogs(logLevel);
|
||||
|
||||
TransformRequest request = TransformRequest.builder()
|
||||
.withSourceSize(1234L)
|
||||
.withInternalContext(InternalContext.initialise(null))
|
||||
.build();
|
||||
TransformStack.setInitialSourceReference(request.getInternalContext(), "fileRef");
|
||||
|
||||
TransformReply reply = TransformReply.builder()
|
||||
.withInternalContext(request.getInternalContext())
|
||||
.build();
|
||||
|
||||
TransformStack.addTransformLevel(request.getInternalContext(),
|
||||
TransformStack.levelBuilder(TransformStack.PIPELINE_FLAG)
|
||||
.withStep("wrapper", MIMETYPE_TEXT_PLAIN, MIMETYPE_PDF));
|
||||
transformerDebug.pushTransform(request);
|
||||
|
||||
TransformStack.addTransformLevel(request.getInternalContext(),
|
||||
TransformStack.levelBuilder(TransformStack.PIPELINE_FLAG)
|
||||
.withStep("transformer1", MIMETYPE_TEXT_PLAIN, MIMETYPE_WORD)
|
||||
.withStep("transformer2", MIMETYPE_WORD, MIMETYPE_PDF));
|
||||
transformerDebug.pushTransform(request);
|
||||
transformerDebug.logOptions(request);
|
||||
TransformStack.removeSuccessfulStep(reply, transformerDebug);
|
||||
|
||||
request.setTransformRequestOptions(ImmutableMap.of("k1", "v1", "k2","v2"));
|
||||
transformerDebug.pushTransform(request);
|
||||
transformerDebug.logOptions(request);
|
||||
if (fail)
|
||||
{
|
||||
reply.setErrorDetails("Dummy error");
|
||||
transformerDebug.logFailure(reply);
|
||||
}
|
||||
else
|
||||
{
|
||||
TransformStack.removeSuccessfulStep(reply, transformerDebug);
|
||||
TransformStack.removeTransformLevel(reply.getInternalContext());
|
||||
}
|
||||
}
|
||||
|
||||
private void monitorLogs(Level logLevel)
|
||||
{
|
||||
Logger logger = (Logger)LoggerFactory.getLogger(TransformerDebug.class);
|
||||
AppenderBase<ILoggingEvent> logAppender = new AppenderBase<>()
|
||||
{
|
||||
@Override
|
||||
protected void append(ILoggingEvent iLoggingEvent)
|
||||
{
|
||||
transformerDebugOutput.add(iLoggingEvent.getMessage());
|
||||
}
|
||||
};
|
||||
logAppender.setContext((LoggerContext)LoggerFactory.getILoggerFactory());
|
||||
logger.setLevel(logLevel);
|
||||
logger.addAppender(logAppender);
|
||||
logAppender.start();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRouterTwoStepTransform()
|
||||
{
|
||||
twoStepTransform(false, false, Level.DEBUG);
|
||||
|
||||
assertEquals("" +
|
||||
"1 txt pdf 1.2 KB wrapper\n" +
|
||||
"1.1 txt doc transformer1\n" +
|
||||
"1.2 doc pdf transformer2\n" +
|
||||
"1.2 k1=\"v1\"\n" +
|
||||
"1.2 k2=\"v2\"\n" +
|
||||
"1 Finished in -- ms",
|
||||
getTransformerDebugOutput());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRouterTwoStepTransformWithTrace()
|
||||
{
|
||||
twoStepTransform(false, false, Level.TRACE);
|
||||
|
||||
// With trace there are "Finished" lines for nested transforms, like a T-Engine's debug but still without
|
||||
// the size and rendition name
|
||||
assertEquals("" +
|
||||
"1 txt pdf 1.2 KB wrapper\n" +
|
||||
"1.1 txt doc transformer1\n" +
|
||||
"1.1 Finished in -- ms\n" +
|
||||
"1.2 doc pdf transformer2\n" +
|
||||
"1.2 k1=\"v1\"\n" +
|
||||
"1.2 k2=\"v2\"\n" +
|
||||
"1.2 Finished in -- ms\n" +
|
||||
"1 Finished in -- ms",
|
||||
getTransformerDebugOutput());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testEngineTwoStepTransform()
|
||||
{
|
||||
twoStepTransform(true, false, Level.DEBUG);
|
||||
|
||||
// Note the first and last lines would only ever be logged on the router, but the expected data includes
|
||||
// the extra "Finished" lines, sizes and renditions (if set in client data).
|
||||
assertEquals("" +
|
||||
"1 txt pdf 1.2 KB wrapper\n" +
|
||||
"1.1 txt doc 1.2 KB transformer1\n" +
|
||||
"1.1 Finished in -- ms\n" +
|
||||
"1.2 doc pdf 1.2 KB transformer2\n" +
|
||||
"1.2 k1=\"v1\"\n" +
|
||||
"1.2 k2=\"v2\"\n" +
|
||||
"1.2 Finished in -- ms\n" +
|
||||
"1 Finished in -- ms",
|
||||
getTransformerDebugOutput());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRouterTwoStepTransformWithFailure()
|
||||
{
|
||||
twoStepTransform(false, true, Level.DEBUG);
|
||||
|
||||
assertEquals("" +
|
||||
"1 txt pdf 1.2 KB wrapper\n" +
|
||||
"1.1 txt doc transformer1\n" +
|
||||
"1.2 doc pdf transformer2\n" +
|
||||
"1.2 k1=\"v1\"\n" +
|
||||
"1.2 k2=\"v2\"\n" +
|
||||
"1.2 Dummy error",
|
||||
getTransformerDebugOutput());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLogFailure()
|
||||
{
|
||||
monitorLogs(Level.TRACE);
|
||||
|
||||
TransformReply reply = TransformReply.builder()
|
||||
.withInternalContext(InternalContext.initialise(null))
|
||||
.withErrorDetails("T-Request was null - a major error")
|
||||
.build();
|
||||
|
||||
transformerDebug.logFailure(reply);
|
||||
|
||||
assertEquals(" T-Request was null - a major error", getTransformerDebugOutput());
|
||||
}
|
||||
|
||||
@Test
|
||||
void tesGetOptionAndValue()
|
||||
{
|
||||
String sixtyChars = "12345678 10 345678 20 345678 30 345678 40 345678 50 abcdefgh";
|
||||
String sixtyOneChars = "12345678 10 345678 20 345678 30 345678 40 345678 50 abcd12345";
|
||||
String expected = "12345678 10 345678 20 345678 30 345678 40 345678 50 ...12345";
|
||||
|
||||
assertEquals("ref key=\"value\"",
|
||||
transformerDebug.getOptionAndValue("ref", "key", "value"));
|
||||
assertEquals("ref key=\""+sixtyChars+"\"",
|
||||
transformerDebug.getOptionAndValue("ref", "key", sixtyChars));
|
||||
assertEquals("ref key=\""+expected+"\"",
|
||||
transformerDebug.getOptionAndValue("ref", "key", sixtyOneChars));
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user