REPO-4639 Content conversion failed using Tika (#587)

The Tika T-Engine was not being called by the Transform Service or Local transforms, because the sub-transform name was required.

Moved common classes (with repo) to alfresco-transform-model so that it can be used by the T-Engines to work out which sub transformer to use. InT also performed a refactor on these classes (alfresco-transform-model 1.0.2.7). Also includes changes to legacy transformers so that they don't pass the sub transformer name any more.
This commit is contained in:
CezarLeahu
2019-09-12 23:49:17 +03:00
committed by alandavis
parent 7e1ec3300d
commit 3225f63f94
35 changed files with 848 additions and 2160 deletions

View File

@@ -64,11 +64,11 @@ jobs:
before_install: before_install:
- docker run -d -p 5433:5432 -e POSTGRES_PASSWORD=alfresco -e POSTGRES_USER=alfresco -e POSTGRES_DB=alfresco postgres:11.4 postgres -c 'max_connections=300' - docker run -d -p 5433:5432 -e POSTGRES_PASSWORD=alfresco -e POSTGRES_USER=alfresco -e POSTGRES_DB=alfresco postgres:11.4 postgres -c 'max_connections=300'
- docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.15.8 - docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.15.8
- docker run -d -p 8090:8090 -e JAVA_OPTS=" -Xms256m -Xmx256m" alfresco/alfresco-pdf-renderer:2.1.0-EA4 - docker run -d -p 8090:8090 -e JAVA_OPTS=" -Xms256m -Xmx256m" alfresco/alfresco-pdf-renderer:2.1.0-DEV1
- docker run -d -p 8091:8090 -e JAVA_OPTS=" -Xms256m -Xmx256m" alfresco/alfresco-imagemagick:2.1.0-EA4 - docker run -d -p 8091:8090 -e JAVA_OPTS=" -Xms256m -Xmx256m" alfresco/alfresco-imagemagick:2.1.0-DEV1
- docker run -d -p 8092:8090 -e JAVA_OPTS=" -Xms256m -Xmx256m" alfresco/alfresco-libreoffice:2.1.0-EA4 - docker run -d -p 8092:8090 -e JAVA_OPTS=" -Xms256m -Xmx256m" alfresco/alfresco-libreoffice:2.1.0-DEV1
- docker run -d -p 8093:8090 -e JAVA_OPTS=" -Xms256m -Xmx256m" alfresco/alfresco-tika:2.1.0-EA4 - docker run -d -p 8093:8090 -e JAVA_OPTS=" -Xms256m -Xmx256m" alfresco/alfresco-tika:2.1.0-DEV1
- docker run -d -p 8094:8090 -e JAVA_OPTS=" -Xms256m -Xmx256m" alfresco/alfresco-transform-misc:2.1.0-EA4 - docker run -d -p 8094:8090 -e JAVA_OPTS=" -Xms256m -Xmx256m" alfresco/alfresco-transform-misc:2.1.0-DEV1
script: travis_wait 20 mvn test -B -Dtest=AppContext06TestSuite -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco -Dalfresco-pdf-renderer.url=http://localhost:8090/ -Djodconverter.url=http://localhost:8092/ -Dimg.url=http://localhost:8091/ -Dtika.url=http://localhost:8093/ -Dtransform.misc.url=http://localhost:8094/ script: travis_wait 20 mvn test -B -Dtest=AppContext06TestSuite -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco -Dalfresco-pdf-renderer.url=http://localhost:8090/ -Djodconverter.url=http://localhost:8092/ -Dimg.url=http://localhost:8091/ -Dtika.url=http://localhost:8093/ -Dtransform.misc.url=http://localhost:8094/
- name: "AppContextExtraTestSuite" - name: "AppContextExtraTestSuite"
before_install: before_install:
@@ -79,11 +79,11 @@ jobs:
before_install: before_install:
- docker run -d -p 5433:5432 -e POSTGRES_PASSWORD=alfresco -e POSTGRES_USER=alfresco -e POSTGRES_DB=alfresco postgres:11.4 postgres -c 'max_connections=300' - docker run -d -p 5433:5432 -e POSTGRES_PASSWORD=alfresco -e POSTGRES_USER=alfresco -e POSTGRES_DB=alfresco postgres:11.4 postgres -c 'max_connections=300'
- docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.15.8 - docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.15.8
- docker run -d -p 8090:8090 -e JAVA_OPTS=" -Xms256m -Xmx256m" alfresco/alfresco-pdf-renderer:2.1.0-EA4 - docker run -d -p 8090:8090 -e JAVA_OPTS=" -Xms256m -Xmx256m" alfresco/alfresco-pdf-renderer:2.1.0-DEV1
- docker run -d -p 8091:8090 -e JAVA_OPTS=" -Xms256m -Xmx256m" alfresco/alfresco-imagemagick:2.1.0-EA4 - docker run -d -p 8091:8090 -e JAVA_OPTS=" -Xms256m -Xmx256m" alfresco/alfresco-imagemagick:2.1.0-DEV1
- docker run -d -p 8092:8090 -e JAVA_OPTS=" -Xms256m -Xmx256m" alfresco/alfresco-libreoffice:2.1.0-EA4 - docker run -d -p 8092:8090 -e JAVA_OPTS=" -Xms256m -Xmx256m" alfresco/alfresco-libreoffice:2.1.0-DEV1
- docker run -d -p 8093:8090 -e JAVA_OPTS=" -Xms256m -Xmx256m" alfresco/alfresco-tika:2.1.0-EA4 - docker run -d -p 8093:8090 -e JAVA_OPTS=" -Xms256m -Xmx256m" alfresco/alfresco-tika:2.1.0-DEV1
- docker run -d -p 8094:8090 -e JAVA_OPTS=" -Xms256m -Xmx256m" alfresco/alfresco-transform-misc:2.1.0-EA4 - docker run -d -p 8094:8090 -e JAVA_OPTS=" -Xms256m -Xmx256m" alfresco/alfresco-transform-misc:2.1.0-DEV1
script: travis_wait 20 mvn test -B -Dtest=MiscContextTestSuite -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco -Dalfresco-pdf-renderer.url=http://localhost:8090/ -Djodconverter.url=http://localhost:8092/ -Dimg.url=http://localhost:8091/ -Dtika.url=http://localhost:8093/ -Dtransform.misc.url=http://localhost:8094/ script: travis_wait 20 mvn test -B -Dtest=MiscContextTestSuite -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco -Dalfresco-pdf-renderer.url=http://localhost:8090/ -Djodconverter.url=http://localhost:8092/ -Dimg.url=http://localhost:8091/ -Dtika.url=http://localhost:8093/ -Dtransform.misc.url=http://localhost:8094/
- name: "MySQL tests" - name: "MySQL tests"
before_install: before_install:

14
pom.xml
View File

@@ -40,11 +40,11 @@
<dependency.alfresco-legacy-lucene.version>6.2</dependency.alfresco-legacy-lucene.version> <dependency.alfresco-legacy-lucene.version>6.2</dependency.alfresco-legacy-lucene.version>
<dependency.alfresco-core.version>7.21</dependency.alfresco-core.version> <dependency.alfresco-core.version>7.21</dependency.alfresco-core.version>
<dependency.alfresco-greenmail.version>6.1</dependency.alfresco-greenmail.version> <dependency.alfresco-greenmail.version>6.1</dependency.alfresco-greenmail.version>
<dependency.alfresco-data-model.version>8.48</dependency.alfresco-data-model.version> <dependency.alfresco-data-model.version>8.49</dependency.alfresco-data-model.version>
<dependency.alfresco-jlan.version>7.1</dependency.alfresco-jlan.version> <dependency.alfresco-jlan.version>7.1</dependency.alfresco-jlan.version>
<dependency.alfresco-pdf-renderer.version>1.1</dependency.alfresco-pdf-renderer.version> <dependency.alfresco-pdf-renderer.version>1.1</dependency.alfresco-pdf-renderer.version>
<dependency.alfresco-hb-data-sender.version>1.0.11</dependency.alfresco-hb-data-sender.version> <dependency.alfresco-hb-data-sender.version>1.0.11</dependency.alfresco-hb-data-sender.version>
<dependency.transform.model.version>1.0.2.7</dependency.transform.model.version>
<dependency.spring.version>5.1.8.RELEASE</dependency.spring.version> <dependency.spring.version>5.1.8.RELEASE</dependency.spring.version>
<dependency.httpcomponents.version>4.5.9</dependency.httpcomponents.version> <dependency.httpcomponents.version>4.5.9</dependency.httpcomponents.version>
@@ -66,7 +66,6 @@
<dependency.cxf.version>3.3.2</dependency.cxf.version> <dependency.cxf.version>3.3.2</dependency.cxf.version>
<dependency.jackson.version>2.9.9</dependency.jackson.version> <dependency.jackson.version>2.9.9</dependency.jackson.version>
<dependency.jackson-databind.version>2.9.9.3</dependency.jackson-databind.version> <dependency.jackson-databind.version>2.9.9.3</dependency.jackson-databind.version>
<dependency.transform.model.version>1.0.2.5</dependency.transform.model.version>
</properties> </properties>
<dependencyManagement> <dependencyManagement>
@@ -194,7 +193,7 @@
<dependency> <dependency>
<groupId>org.apache.commons</groupId> <groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId> <artifactId>commons-compress</artifactId>
<version>1.18</version> <version>1.19</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.commons</groupId> <groupId>org.apache.commons</groupId>
@@ -1052,6 +1051,13 @@
<version>4.12</version> <version>4.12</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-transform-model</artifactId>
<version>${dependency.transform.model.version}</version>
<classifier>tests</classifier>
<scope>test</scope>
</dependency>
<dependency> <dependency>
<groupId>org.alfresco</groupId> <groupId>org.alfresco</groupId>
<artifactId>alfresco-core</artifactId> <artifactId>alfresco-core</artifactId>

View File

@@ -141,12 +141,6 @@ public class ArchiveContentTransformer extends TikaPoweredContentTransformer
return context; return context;
} }
@Override
protected String getTransform()
{
return "Archive";
}
@Override @Override
protected void transformRemote(RemoteTransformerClient remoteTransformerClient, ContentReader reader, protected void transformRemote(RemoteTransformerClient remoteTransformerClient, ContentReader reader,
ContentWriter writer, TransformationOptions options, ContentWriter writer, TransformationOptions options,
@@ -154,7 +148,6 @@ public class ArchiveContentTransformer extends TikaPoweredContentTransformer
String sourceExtension, String targetExtension, String sourceExtension, String targetExtension,
String targetEncoding) throws Exception String targetEncoding) throws Exception
{ {
String transform = getTransform();
long timeoutMs = options.getTimeoutMs(); long timeoutMs = options.getTimeoutMs();
boolean recurse = includeContents; boolean recurse = includeContents;
if(options.getIncludeEmbedded() != null) if(options.getIncludeEmbedded() != null)
@@ -162,7 +155,10 @@ public class ArchiveContentTransformer extends TikaPoweredContentTransformer
recurse = options.getIncludeEmbedded(); recurse = options.getIncludeEmbedded();
} }
remoteTransformerClient.request(reader, writer, sourceMimetype, sourceExtension, targetExtension, remoteTransformerClient.request(reader, writer, sourceMimetype, sourceExtension, targetExtension,
timeoutMs, logger, "transform", transform, "includeContents", Boolean.toString(recurse), timeoutMs, logger,
"targetMimetype", targetMimetype, "targetEncoding", targetEncoding); "includeContents", Boolean.toString(recurse),
"sourceMimetype", sourceMimetype,
"targetMimetype", targetMimetype,
"targetEncoding", targetEncoding);
} }
} }

View File

@@ -143,11 +143,11 @@ public class LocalTransformImpl extends AbstractLocalTransform
String sourceExtension, String targetExtension, String sourceExtension, String targetExtension,
String renditionName, NodeRef sourceNodeRef) throws Exception String renditionName, NodeRef sourceNodeRef) throws Exception
{ {
// At some point in the future, we may decide to only pass the sourceEncoding and other dynamic values like // Only pass the sourceEncoding and other dynamic values like it if they were supplied in the rendition
// it if they were supplied in the rendition definition without a value. The sourceEncoding value is also // definition without a value. The sourceEncoding value is also supplied in the RenditionEventProducer in
// supplied in the TransformRequest (message to the T-Router). // the message to the T-Router.
transformOptions = new HashMap<>(transformOptions); transformOptions = new HashMap<>(transformOptions);
if (transformOptions.get(SOURCE_ENCODING) == null) if (transformOptions.containsKey(SOURCE_ENCODING) && transformOptions.get(SOURCE_ENCODING) == null)
{ {
String sourceEncoding = reader.getEncoding(); String sourceEncoding = reader.getEncoding();
transformOptions.put(SOURCE_ENCODING, sourceEncoding); transformOptions.put(SOURCE_ENCODING, sourceEncoding);

View File

@@ -25,20 +25,6 @@
*/ */
package org.alfresco.repo.content.transform; package org.alfresco.repo.content.transform;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.MimetypeService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.transform.client.model.config.CombinedConfig;
import org.alfresco.transform.client.model.config.InlineTransformer;
import org.alfresco.transform.client.model.config.TransformServiceRegistry;
import org.alfresco.transform.client.model.config.TransformServiceRegistryImpl;
import org.alfresco.transform.client.model.config.TransformStep;
import org.alfresco.util.PropertyCheck;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
@@ -48,6 +34,21 @@ import java.util.Map;
import java.util.Properties; import java.util.Properties;
import java.util.Set; import java.util.Set;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.MimetypeService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.transform.client.registry.CombinedConfig;
import org.alfresco.transform.client.model.config.TransformOption;
import org.alfresco.transform.client.registry.TransformServiceRegistryImpl;
import org.alfresco.transform.client.model.config.TransformStep;
import org.alfresco.transform.client.model.config.Transformer;
import org.alfresco.transform.client.registry.TransformServiceRegistry;
import org.alfresco.util.PropertyCheck;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
/** /**
* Implements {@link TransformServiceRegistry} providing a mechanism of validating if a local transformation * Implements {@link TransformServiceRegistry} providing a mechanism of validating if a local transformation
* (based on {@link LocalTransform} request is supported. It also extends this interface to provide a * (based on {@link LocalTransform} request is supported. It also extends this interface to provide a
@@ -156,7 +157,8 @@ public class LocalTransformServiceRegistry extends TransformServiceRegistryImpl
} }
@Override @Override
protected void register(InlineTransformer transformer, String baseUrl, String readFrom) public void register(Transformer transformer, Map<String, Set<TransformOption>> transformOptions,
String baseUrl, String readFrom)
{ {
try try
{ {
@@ -242,7 +244,7 @@ public class LocalTransformServiceRegistry extends TransformServiceRegistryImpl
} }
} }
localTransforms.put(name, localTransform); localTransforms.put(name, localTransform);
super.register(transformer, baseUrl, readFrom); super.register(transformer, transformOptions, baseUrl, readFrom);
} }
catch (IllegalArgumentException e) catch (IllegalArgumentException e)
{ {
@@ -394,7 +396,7 @@ public class LocalTransformServiceRegistry extends TransformServiceRegistryImpl
} }
@Override @Override
public long getMaxSize(String sourceMimetype, String targetMimetype, Map<String, String> options, String renditionName) public long findMaxSize(String sourceMimetype, String targetMimetype, Map<String, String> options, String renditionName)
{ {
// This message is not logged if placed in afterPropertiesSet // This message is not logged if placed in afterPropertiesSet
if (getFirstTime()) if (getFirstTime())
@@ -404,7 +406,7 @@ public class LocalTransformServiceRegistry extends TransformServiceRegistryImpl
} }
return enabled return enabled
? super.getMaxSize(sourceMimetype, targetMimetype, options, renditionName) ? super.findMaxSize(sourceMimetype, targetMimetype, options, renditionName)
: 0; : 0;
} }
@@ -422,7 +424,7 @@ public class LocalTransformServiceRegistry extends TransformServiceRegistryImpl
public LocalTransform getLocalTransform(Map<String, String> actualOptions, String renditionName, public LocalTransform getLocalTransform(Map<String, String> actualOptions, String renditionName,
String sourceMimetype, String targetMimetype, long sourceSizeInBytes) String sourceMimetype, String targetMimetype, long sourceSizeInBytes)
{ {
String name = getTransformerName(sourceMimetype, sourceSizeInBytes, targetMimetype, actualOptions, renditionName); String name = findTransformerName(sourceMimetype, sourceSizeInBytes, targetMimetype, actualOptions, renditionName);
LocalData data = getData(); LocalData data = getData();
Map<String, LocalTransform> localTransforms = data.localTransforms; Map<String, LocalTransform> localTransforms = data.localTransforms;
return localTransforms.get(name); return localTransforms.get(name);

View File

@@ -51,10 +51,4 @@ public class MailContentTransformer extends TikaPoweredContentTransformer
protected Parser getParser() { protected Parser getParser() {
return new OfficeParser(); return new OfficeParser();
} }
@Override
protected String getTransform()
{
return "OutlookMsg";
}
} }

View File

@@ -98,13 +98,6 @@ public class PdfBoxContentTransformer extends TikaPoweredContentTransformer
return context; return context;
} }
@Override
protected String getTransform()
{
return "PdfBox";
}
@Override @Override
protected void transformRemote(RemoteTransformerClient remoteTransformerClient, ContentReader reader, protected void transformRemote(RemoteTransformerClient remoteTransformerClient, ContentReader reader,
ContentWriter writer, TransformationOptions options, ContentWriter writer, TransformationOptions options,
@@ -112,8 +105,6 @@ public class PdfBoxContentTransformer extends TikaPoweredContentTransformer
String sourceExtension, String targetExtension, String sourceExtension, String targetExtension,
String targetEncoding) throws Exception String targetEncoding) throws Exception
{ {
String transform = getTransform();
long timeoutMs = options.getTimeoutMs(); long timeoutMs = options.getTimeoutMs();
String notExtractBookmarksText = null; String notExtractBookmarksText = null;
@@ -124,8 +115,8 @@ public class PdfBoxContentTransformer extends TikaPoweredContentTransformer
remoteTransformerClient.request(reader, writer, sourceMimetype, sourceExtension, targetExtension, remoteTransformerClient.request(reader, writer, sourceMimetype, sourceExtension, targetExtension,
timeoutMs, logger, timeoutMs, logger,
"transform", transform,
"notExtractBookmarksText", notExtractBookmarksText, "notExtractBookmarksText", notExtractBookmarksText,
"sourceMimetype", sourceMimetype,
"targetMimetype", targetMimetype, "targetMimetype", targetMimetype,
"targetEncoding", targetEncoding); "targetEncoding", targetEncoding);
} }

View File

@@ -76,10 +76,4 @@ public class PoiContentTransformer extends TikaPoweredContentTransformer
protected Parser getParser() { protected Parser getParser() {
return new OfficeParser(); return new OfficeParser();
} }
@Override
protected String getTransform()
{
return "Office";
}
} }

View File

@@ -211,10 +211,4 @@ public class PoiHssfContentTransformer extends TikaPoweredContentTransformer
} }
} }
} }
@Override
protected String getTransform()
{
return "Poi";
}
} }

View File

@@ -65,10 +65,4 @@ public class PoiOOXMLContentTransformer extends TikaPoweredContentTransformer
protected Parser getParser() { protected Parser getParser() {
return new OOXMLParser(); return new OOXMLParser();
} }
@Override
protected String getTransform()
{
return "OOXML";
}
} }

View File

@@ -51,10 +51,4 @@ public class TextMiningContentTransformer extends TikaPoweredContentTransformer
protected Parser getParser() { protected Parser getParser() {
return new OfficeParser(); return new OfficeParser();
} }
@Override
protected String getTransform()
{
return "TextMining";
}
} }

View File

@@ -131,10 +131,4 @@ public class TikaAutoContentTransformer extends TikaPoweredContentTransformer
{ {
return parser; return parser;
} }
@Override
protected String getTransform()
{
return "TikaAuto";
}
} }

View File

@@ -292,18 +292,15 @@ public abstract class TikaPoweredContentTransformer extends AbstractRemoteConten
String sourceExtension, String targetExtension, String sourceExtension, String targetExtension,
String targetEncoding) throws Exception String targetEncoding) throws Exception
{ {
String transform = getTransform();
long timeoutMs = options.getTimeoutMs(); long timeoutMs = options.getTimeoutMs();
remoteTransformerClient.request(reader, writer, sourceMimetype, sourceExtension, targetExtension, remoteTransformerClient.request(reader, writer, sourceMimetype, sourceExtension, targetExtension,
timeoutMs, logger, timeoutMs, logger,
"transform", transform, "sourceMimetype", sourceMimetype,
"targetMimetype", targetMimetype, "targetMimetype", targetMimetype,
"targetEncoding", targetEncoding); "targetEncoding", targetEncoding);
} }
protected abstract String getTransform();
private String calculateMemoryAndTimeUsage(ContentReader reader, long startTime) private String calculateMemoryAndTimeUsage(ContentReader reader, long startTime)
{ {
long endTime = System.currentTimeMillis(); long endTime = System.currentTimeMillis();

View File

@@ -107,10 +107,4 @@ public class TikaSpringConfiguredContentTransformer extends TikaPoweredContentTr
throw new AlfrescoRuntimeException("Unable to create specified Parser", e); throw new AlfrescoRuntimeException("Unable to create specified Parser", e);
} }
} }
@Override
protected String getTransform()
{
return "tikaspring"; // This transformer is no longer created by Spring, so is not supported by the Tika transformer image
}
} }

View File

@@ -25,10 +25,10 @@
*/ */
package org.alfresco.repo.rendition2; package org.alfresco.repo.rendition2;
import org.alfresco.transform.client.model.config.TransformServiceRegistry;
import java.util.Map; import java.util.Map;
import org.alfresco.transform.client.registry.TransformServiceRegistry;
/** /**
* Contains common code used in TransformServiceRegistries. * Contains common code used in TransformServiceRegistries.
* *
@@ -37,9 +37,8 @@ import java.util.Map;
public abstract class AbstractTransformServiceRegistry implements TransformServiceRegistry public abstract class AbstractTransformServiceRegistry implements TransformServiceRegistry
{ {
@Override @Override
public boolean isSupported(String sourceMimetype, long size, String targetMimetype, Map<String, String> options, String renditionName) public String findTransformerName(String sourceMimetype, long sourceSizeInBytes, String targetMimetype, Map<String, String> actualOptions, String renditionName)
{ {
long maxSize = getMaxSize(sourceMimetype, targetMimetype, options, renditionName); throw new UnsupportedOperationException("AbstractTransformServiceRegistry.findTransformerName(...) is not supported. Only supported in ");
return maxSize != 0 && (maxSize == -1L || maxSize >= size);
} }
} }

View File

@@ -28,7 +28,7 @@ package org.alfresco.repo.rendition2;
import org.alfresco.repo.content.transform.TransformerDebug; import org.alfresco.repo.content.transform.TransformerDebug;
import org.alfresco.service.cmr.repository.ContentService; import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.TransformationOptions; import org.alfresco.service.cmr.repository.TransformationOptions;
import org.alfresco.transform.client.model.config.TransformServiceRegistry; import org.alfresco.transform.client.registry.TransformServiceRegistry;
import org.alfresco.util.PropertyCheck; import org.alfresco.util.PropertyCheck;
import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.InitializingBean;
@@ -84,7 +84,7 @@ public class LegacyTransformServiceRegistry extends AbstractTransformServiceRegi
} }
@Override @Override
public long getMaxSize(String sourceMimetype, String targetMimetype, Map<String, String> options, String renditionName) public long findMaxSize(String sourceMimetype, String targetMimetype, Map<String, String> options, String renditionName)
{ {
// This message is not logged if placed in afterPropertiesSet // This message is not logged if placed in afterPropertiesSet
if (firstTime) if (firstTime)

View File

@@ -27,7 +27,7 @@ package org.alfresco.repo.rendition2;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import org.alfresco.transform.client.model.config.TransformServiceRegistry; import org.alfresco.transform.client.registry.TransformServiceRegistry;
import org.alfresco.util.ConfigFileFinder; import org.alfresco.util.ConfigFileFinder;
import org.alfresco.util.ConfigScheduler; import org.alfresco.util.ConfigScheduler;
import org.alfresco.util.Pair; import org.alfresco.util.Pair;
@@ -343,7 +343,7 @@ public class RenditionDefinitionRegistry2Impl implements RenditionDefinitionRegi
String targetMimetype = renditionDefinition2.getTargetMimetype(); String targetMimetype = renditionDefinition2.getTargetMimetype();
String renditionName = renditionDefinition2.getRenditionName(); String renditionName = renditionDefinition2.getRenditionName();
Map<String, String> options = renditionDefinition2.getTransformOptions(); Map<String, String> options = renditionDefinition2.getTransformOptions();
Long maxSize = transformServiceRegistry.getMaxSize(sourceMimetype, targetMimetype, options, renditionName); Long maxSize = transformServiceRegistry.findMaxSize(sourceMimetype, targetMimetype, options, renditionName);
if (maxSize != null) if (maxSize != null)
{ {
String renditionNameMaxSizePair = entry.getKey(); String renditionNameMaxSizePair = entry.getKey();

View File

@@ -25,7 +25,7 @@
*/ */
package org.alfresco.repo.rendition2; package org.alfresco.repo.rendition2;
import org.alfresco.transform.client.model.config.TransformServiceRegistry; import org.alfresco.transform.client.registry.TransformServiceRegistry;
import java.util.Map; import java.util.Map;
@@ -46,17 +46,17 @@ public class SwitchingTransformServiceRegistry extends AbstractTransformServiceR
} }
@Override @Override
public long getMaxSize(String sourceMimetype, String targetMimetype, Map<String, String> options, String renditionName) public long findMaxSize(String sourceMimetype, String targetMimetype, Map<String, String> options, String renditionName)
{ {
long maxSize; long maxSize;
long primaryMaxSize = primary.getMaxSize(sourceMimetype, targetMimetype, options, renditionName); long primaryMaxSize = primary.findMaxSize(sourceMimetype, targetMimetype, options, renditionName);
if (primaryMaxSize == -1L) if (primaryMaxSize == -1L)
{ {
maxSize = -1L; maxSize = -1L;
} }
else else
{ {
long secondaryMaxSize = secondary.getMaxSize(sourceMimetype, targetMimetype, options, renditionName); long secondaryMaxSize = secondary.findMaxSize(sourceMimetype, targetMimetype, options, renditionName);
maxSize = primaryMaxSize == 0 maxSize = primaryMaxSize == 0
? secondaryMaxSize ? secondaryMaxSize
: secondaryMaxSize == 0 : secondaryMaxSize == 0

View File

@@ -45,7 +45,7 @@ import org.alfresco.service.cmr.thumbnail.ThumbnailException;
import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.QName;
import org.alfresco.service.transaction.TransactionService; import org.alfresco.service.transaction.TransactionService;
import org.alfresco.transform.client.model.config.TransformServiceRegistry; import org.alfresco.transform.client.registry.TransformServiceRegistry;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException; import org.springframework.beans.BeansException;
@@ -457,7 +457,7 @@ public class ThumbnailRegistry implements ApplicationContextAware, ApplicationLi
{ {
Map<String, String> options = renditionDefinition.getTransformOptions(); Map<String, String> options = renditionDefinition.getTransformOptions();
String renditionName = renditionDefinition.getRenditionName(); String renditionName = renditionDefinition.getRenditionName();
maxSize = transformServiceRegistry.getMaxSize(sourceMimetype, targetMimetype, options, renditionName); maxSize = transformServiceRegistry.findMaxSize(sourceMimetype, targetMimetype, options, renditionName);
} }
else else
{ {

View File

@@ -1,66 +0,0 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2018 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.transform.client.model.config;
/**
* Represents a single transformer in a pipeline of multiple transformers. A transformer's options may be optional or
* required in the containing transformer. Historically in ACS only options for the final transformer were provided.
*/
public class ChildTransformer
{
private boolean required;
private InlineTransformer transformer;
public ChildTransformer()
{
}
public ChildTransformer(boolean required, InlineTransformer transformer)
{
this.required = required;
this.transformer = transformer;
}
public boolean isRequired()
{
return required;
}
public void setRequired(boolean required)
{
this.required = required;
}
public InlineTransformer getTransformer()
{
return transformer;
}
public void setTransformer(InlineTransformer transformer)
{
this.transformer = transformer;
}
}

View File

@@ -1,440 +0,0 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2019 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.model.config;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.util.ConfigFileFinder;
import org.apache.commons.logging.Log;
import org.apache.http.HttpEntity;
import org.apache.http.StatusLine;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* This class recreates the json format used in ACS 6.1 where we just had an array of transformers and each
* transformer has a list of node options. The idea of this code is that it replaces the references with the
* actual node options that have been separated out into their own section.<p>
*
* The T-Router and T-Engines return the format with the node option separated into their own section. Pipeline
* definitions used by the LocalTransformServiceRegistry may use node reference options defined in the json
* returned by T-Engines. with the actual definitions from the node options
* reference section. It also combines multiple json sources into a single jsonNode structure that can be parsed as
* before.
*/
public class CombinedConfig
{
private static final String TRANSFORMER_NAME = "transformerName";
private static final String TRANSFORM_CONFIG = "/transform/config";
private static final String TRANSFORM_OPTIONS = "transformOptions";
private static final String GROUP = "group";
private static final String TRANSFORMERS = "transformers";
private final Log log;
private Map<String, ArrayNode> allTransformOptions = new HashMap<>();
private List<TransformNodeAndItsOrigin> allTransforms = new ArrayList<>();
private ObjectMapper jsonObjectMapper = new ObjectMapper();
private ConfigFileFinder configFileFinder;
private int tEngineCount;
static class TransformNodeAndItsOrigin
{
final ObjectNode node;
final String baseUrl;
final String readFrom;
TransformNodeAndItsOrigin(ObjectNode node, String baseUrl, String readFrom)
{
this.node = node;
this.baseUrl = baseUrl;
this.readFrom = readFrom;
}
}
static class TransformAndItsOrigin
{
final InlineTransformer transform;
final String baseUrl;
final String readFrom;
TransformAndItsOrigin(InlineTransformer transform, String baseUrl, String readFrom)
{
this.transform = transform;
this.baseUrl = baseUrl;
this.readFrom = readFrom;
}
}
public CombinedConfig(Log log)
{
this.log = log;
configFileFinder = new ConfigFileFinder(jsonObjectMapper)
{
@Override
protected void readJson(JsonNode jsonNode, String readFromMessage, String baseUrl) throws IOException
{
JsonNode transformOptions = jsonNode.get(TRANSFORM_OPTIONS);
if (transformOptions != null && transformOptions.isObject())
{
Iterator<Map.Entry<String, JsonNode>> iterator = transformOptions.fields();
while (iterator.hasNext())
{
Map.Entry<String, JsonNode> entry = iterator.next();
JsonNode options = entry.getValue();
if (options.isArray())
{
String optionsName = entry.getKey();
allTransformOptions.put(optionsName, (ArrayNode)options);
}
}
}
JsonNode transformers = jsonNode.get(TRANSFORMERS);
if (transformers != null && transformers.isArray())
{
for (JsonNode transformer : transformers)
{
if (transformer.isObject())
{
allTransforms.add(new TransformNodeAndItsOrigin((ObjectNode)transformer, baseUrl, readFromMessage));
}
}
}
}
};
}
public boolean addRemoteConfig(List<String> urls, String remoteType)
{
boolean successReadingConfig = true;
for (String url : urls)
{
if (addRemoteConfig(url, remoteType))
{
tEngineCount++ ;
}
else
{
successReadingConfig = false;
}
}
return successReadingConfig;
}
private boolean addRemoteConfig(String baseUrl, String remoteType)
{
String url = baseUrl + TRANSFORM_CONFIG;
HttpGet httpGet = new HttpGet(url);
boolean successReadingConfig = true;
try
{
try (CloseableHttpClient httpclient = HttpClients.createDefault())
{
try (CloseableHttpResponse response = execute(httpclient, httpGet))
{
StatusLine statusLine = response.getStatusLine();
if (statusLine == null)
{
throw new AlfrescoRuntimeException(remoteType+" on " + url+" returned no status ");
}
HttpEntity resEntity = response.getEntity();
if (resEntity != null)
{
int statusCode = statusLine.getStatusCode();
if (statusCode == 200)
{
try
{
String content = getContent(resEntity);
try (StringReader reader = new StringReader(content))
{
int transformCount = allTransforms.size();
configFileFinder.readFile(reader, remoteType+" on "+baseUrl, "json", baseUrl, log);
if (transformCount == allTransforms.size())
{
successReadingConfig = false;
}
}
EntityUtils.consume(resEntity);
}
catch (IOException e)
{
throw new AlfrescoRuntimeException("Failed to read the returned content from "+
remoteType+" on " + url, e);
}
}
else
{
String message = getErrorMessage(resEntity);
throw new AlfrescoRuntimeException(remoteType+" on " + url+" returned a " + statusCode +
" status " + message);
}
}
else
{
throw new AlfrescoRuntimeException(remoteType+" on " + url+" did not return an entity " + url);
}
}
catch (IOException e)
{
throw new AlfrescoRuntimeException("Failed to connect or to read the response from "+remoteType+
" on " + url, e);
}
}
catch (IOException e)
{
throw new AlfrescoRuntimeException(remoteType+" on " + url+" failed to create an HttpClient", e);
}
}
catch (AlfrescoRuntimeException e)
{
log.error(e.getMessage());
successReadingConfig = false;
}
return successReadingConfig;
}
// Tests mock the return values
CloseableHttpResponse execute(CloseableHttpClient httpclient, HttpGet httpGet) throws IOException
{
return httpclient.execute(httpGet);
}
// Tests mock the return values
String getContent(HttpEntity resEntity) throws IOException
{
return EntityUtils.toString(resEntity);
}
// Strip out just the error message in the response
private String getErrorMessage(HttpEntity resEntity) throws IOException
{
String message = "";
String content = getContent(resEntity);
int i = content.indexOf("\"message\":\"");
if (i != -1)
{
int j = content.indexOf("\",\"path\":", i);
if (j != -1)
{
message = content.substring(i+11, j);
}
}
return message;
}
public boolean addLocalConfig(String path) throws IOException
{
return configFileFinder.readFiles(path, log);
}
public void register(TransformServiceRegistryImpl registry) throws IOException
{
TransformServiceRegistryImpl.Data data = registry.getData();
data.setTEngineCount(tEngineCount);
data.setFileCount(configFileFinder.getFileCount());
List<TransformAndItsOrigin> transformers = getTransforms();
transformers.forEach(t->registry.register(t.transform, t.baseUrl, t.readFrom));
}
public List<TransformAndItsOrigin> getTransforms() throws IOException
{
List<TransformAndItsOrigin> transforms = new ArrayList<>();
// After all json input has been loaded build the output with the options in place.
ArrayNode transformersNode = jsonObjectMapper.createArrayNode();
for (TransformNodeAndItsOrigin entity : allTransforms)
{
transformersNode.add(entity.node);
try
{
ArrayNode transformOptions = (ArrayNode) entity.node.get(TRANSFORM_OPTIONS);
if (transformOptions != null)
{
ArrayNode options;
int size = transformOptions.size();
if (size == 1)
{
// If there is a single node option reference, we can just use it.
int i = 0;
options = getTransformOptions(transformOptions, i, entity.node);
}
else
{
// If there are many node option references (typically in a pipeline), then each element
// has a group for each set of node options.
options = jsonObjectMapper.createArrayNode();
for (int i = size - 1; i >= 0; i--)
{
JsonNode referencedTransformOptions = getTransformOptions(transformOptions, i, entity.node);
if (referencedTransformOptions != null)
{
ObjectNode element = jsonObjectMapper.createObjectNode();
options.add(element);
ObjectNode group = jsonObjectMapper.createObjectNode();
group.set(TRANSFORM_OPTIONS, referencedTransformOptions);
element.set(GROUP, group);
}
}
}
if (options == null || options.size() == 0)
{
entity.node.remove(TRANSFORM_OPTIONS);
}
else
{
entity.node.set(TRANSFORM_OPTIONS, options);
}
}
try
{
InlineTransformer transform = jsonObjectMapper.convertValue(entity.node, InlineTransformer.class);
transforms.add(new TransformAndItsOrigin(transform, entity.baseUrl, entity.readFrom));
}
catch (IllegalArgumentException e)
{
log.error("Invalid transformer "+getTransformName(entity.node)+" "+e.getMessage()+" baseUrl="+entity.baseUrl);
}
}
catch (IllegalArgumentException e)
{
String transformString = jsonObjectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(entity.node);
log.error(e.getMessage());
log.debug(transformString);
}
}
if (log.isTraceEnabled())
{
log.trace("Combined config:\n"+jsonObjectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(transformersNode));
}
transforms = sortTransformers(transforms);
return transforms;
}
// Sort transformers so there are no forward references, if that is possible.
private List<TransformAndItsOrigin> sortTransformers(List<TransformAndItsOrigin> original)
{
List<TransformAndItsOrigin> transformers = new ArrayList<>(original.size());
List<TransformAndItsOrigin> todo = new ArrayList<>(original.size());
Set<String> transformerNames = new HashSet<>();
boolean added;
do
{
added = false;
for (TransformAndItsOrigin entry : original)
{
String name = entry.transform.getTransformerName();
List<TransformStep> pipeline = entry.transform.getTransformerPipeline();
boolean addEntry = true;
if (pipeline != null && !pipeline.isEmpty())
{
for (TransformStep step : pipeline)
{
String stepName = step.getTransformerName();
if (!transformerNames.contains(stepName))
{
todo.add(entry);
addEntry = false;
break;
}
}
}
if (addEntry)
{
transformers.add(entry);
added = true;
if (name != null)
{
transformerNames.add(name);
}
}
}
original.clear();
original.addAll(todo);
todo.clear();
}
while (added && !original.isEmpty());
transformers.addAll(todo);
return transformers;
}
private ArrayNode getTransformOptions(ArrayNode transformOptions, int i, ObjectNode transform)
{
ArrayNode options = null;
JsonNode optionName = transformOptions.get(i);
if (optionName.isTextual())
{
String name = optionName.asText();
options = allTransformOptions.get(name);
if (options == null)
{
String message = "Reference to \"transformOptions\": \"" + name + "\" not found. Transformer " +
getTransformName(transform) + " ignored.";
throw new IllegalArgumentException(message);
}
}
return options;
}
private String getTransformName(ObjectNode transform)
{
String name = "Unknown";
JsonNode nameNode = transform.get(TRANSFORMER_NAME);
if (nameNode != null && nameNode.isTextual())
{
name = '"'+nameNode.asText()+'"';
}
return name;
}
}

View File

@@ -1,67 +0,0 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2018 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.transform.client.model.config;
import org.quartz.CronExpression;
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
* {@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 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.
*/
boolean isSupported(String sourceMimetype, long sourceSizeInBytes, String targetMimetype,
Map<String, String> actualOptions, String transformName);
/**
* 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 getMaxSize(String sourceMimetype, String targetMimetype,
Map<String, String> actualOptions, String transformName);
}

View File

@@ -1,459 +0,0 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2018 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.transform.client.model.config;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.alfresco.util.ConfigScheduler;
import org.alfresco.util.PropertyCheck;
import org.apache.commons.logging.Log;
import org.quartz.CronExpression;
import org.springframework.beans.factory.InitializingBean;
import java.io.IOException;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import static org.alfresco.repo.rendition2.RenditionDefinition2.TIMEOUT;
/**
* Used by clients to work out if a transformation is supported by the Transform Service.
*/
public abstract class TransformServiceRegistryImpl implements TransformServiceRegistry, InitializingBean
{
public static class Data
{
ConcurrentMap<String, ConcurrentMap<String, List<SupportedTransform>>> transformers = new ConcurrentHashMap<>();
ConcurrentMap<String, ConcurrentMap<String, List<SupportedTransform>>> cachedSupportedTransformList = new ConcurrentHashMap<>();
private int transformerCount = 0;
private int transformCount = 0;
private int tEngineCount = 0;
private int fileCount;
boolean firstTime = true;
@Override
public String toString()
{
return transformerCount == 0 && transformCount == 0 && tEngineCount == 0 && fileCount == 0
? ""
: "(transformers: "+transformerCount+" transforms: "+transformCount+" t-engines: "+tEngineCount+" files: "+fileCount+")";
}
public void setTEngineCount(int tEngineCount)
{
this.tEngineCount = tEngineCount;
}
public void setFileCount(int fileCount)
{
this.fileCount = fileCount;
}
}
static class SupportedTransform
{
TransformOptionGroup transformOptions;
long maxSourceSizeBytes;
private String name;
private int priority;
public SupportedTransform(Data data, 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;
data.transformCount++;
}
}
protected boolean enabled = true;
private ObjectMapper jsonObjectMapper;
private CronExpression cronExpression;
private CronExpression initialAndOnErrorCronExpression;
private ConfigScheduler<Data> configScheduler = new ConfigScheduler(this)
{
@Override
public boolean readConfig() throws IOException
{
return TransformServiceRegistryImpl.this.readConfig();
}
@Override
public Object createData()
{
return TransformServiceRegistryImpl.this.createData();
}
};
public void setJsonObjectMapper(ObjectMapper jsonObjectMapper)
{
this.jsonObjectMapper = jsonObjectMapper;
}
public CronExpression getCronExpression()
{
return cronExpression;
}
public void setCronExpression(CronExpression cronExpression)
{
this.cronExpression = cronExpression;
}
public CronExpression getInitialAndOnErrorCronExpression()
{
return initialAndOnErrorCronExpression;
}
public void setInitialAndOnErrorCronExpression(CronExpression initialAndOnErrorCronExpression)
{
this.initialAndOnErrorCronExpression = initialAndOnErrorCronExpression;
}
@Override
public void afterPropertiesSet() throws Exception
{
PropertyCheck.mandatory(this, "jsonObjectMapper", jsonObjectMapper);
// If we have a cronExpression it indicates that we will schedule reading.
if (cronExpression != null)
{
PropertyCheck.mandatory(this, "initialAndOnErrorCronExpression", initialAndOnErrorCronExpression);
}
Log log = getLog();
configScheduler.run(enabled, log, cronExpression, initialAndOnErrorCronExpression);
}
public Data createData()
{
return new Data();
}
public Data getData()
{
return configScheduler.getData();
}
public abstract boolean readConfig() throws IOException;
public boolean isEnabled()
{
return enabled;
}
public void setEnabled(boolean enabled)
{
this.enabled = enabled;
setFirstTime(true);
}
protected void setFirstTime(boolean firstTime)
{
getData().firstTime = firstTime;
}
protected boolean getFirstTime()
{
return getData().firstTime;
}
protected abstract Log getLog();
public void register(Reader reader, String readFrom) throws IOException
{
List<InlineTransformer> transformers = jsonObjectMapper.readValue(reader, new TypeReference<List<InlineTransformer>>(){});
transformers.forEach(t -> register(t, null, readFrom));
}
protected void register(InlineTransformer transformer, String baseUrl, String readFrom)
{
Data data = getData();
data.transformerCount++;
transformer.getSupportedSourceAndTargetList().forEach(
e -> data.transformers.computeIfAbsent(e.getSourceMediaType(),
k -> new ConcurrentHashMap<>()).computeIfAbsent(e.getTargetMediaType(),
k -> new ArrayList<>()).add(
new SupportedTransform(data, transformer.getTransformerName(),
transformer.getTransformOptions(), e.getMaxSourceSizeBytes(), e.getPriority())));
}
@Override
public boolean isSupported(String sourceMimetype, long sourceSizeInBytes, String targetMimetype,
Map<String, String> actualOptions, String renditionName)
{
long maxSize = getMaxSize(sourceMimetype, targetMimetype, actualOptions, renditionName);
return maxSize != 0 && (maxSize == -1L || maxSize >= sourceSizeInBytes);
}
/**
* 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.
*/
protected String getTransformerName(String sourceMimetype, long sourceSizeInBytes, String targetMimetype, Map<String, String> actualOptions, String renditionName)
{
List<SupportedTransform> supportedTransforms = getTransformListBySize(sourceMimetype, targetMimetype, actualOptions, renditionName);
for (SupportedTransform supportedTransform : supportedTransforms)
{
if (supportedTransform.maxSourceSizeBytes == -1 || supportedTransform.maxSourceSizeBytes >= sourceSizeInBytes)
{
return supportedTransform.name;
}
}
return null;
}
@Override
public long getMaxSize(String sourceMimetype, String targetMimetype,
Map<String, String> actualOptions, String renditionName)
{
List<SupportedTransform> supportedTransforms = getTransformListBySize(sourceMimetype, targetMimetype, actualOptions, renditionName);
return supportedTransforms.isEmpty() ? 0 : supportedTransforms.get(supportedTransforms.size()-1).maxSourceSizeBytes;
}
// Returns transformers in increasing supported size order, where lower priority transformers for the same size have
// been discarded.
private List<SupportedTransform> getTransformListBySize(String sourceMimetype, String targetMimetype,
Map<String, String> actualOptions, String renditionName)
{
if (actualOptions == null)
{
actualOptions = Collections.EMPTY_MAP;
}
if (renditionName != null && renditionName.trim().isEmpty())
{
renditionName = null;
}
Data data = getData();
List<SupportedTransform> transformListBySize = renditionName == null ? null
: data.cachedSupportedTransformList.computeIfAbsent(renditionName, k -> new ConcurrentHashMap<>()).get(sourceMimetype);
if (transformListBySize != null)
{
return transformListBySize;
}
// Remove the "timeout" property from the actualOptions as it is not used to select a transformer.
if (actualOptions.containsKey(TIMEOUT))
{
actualOptions = new HashMap(actualOptions);
actualOptions.remove(TIMEOUT);
}
transformListBySize = new ArrayList<>();
ConcurrentMap<String, List<SupportedTransform>> targetMap = data.transformers.get(sourceMimetype);
if (targetMap != null)
{
List<SupportedTransform> supportedTransformList = targetMap.get(targetMimetype);
if (supportedTransformList != null)
{
for (SupportedTransform supportedTransform : supportedTransformList)
{
TransformOptionGroup transformOptions = supportedTransform.transformOptions;
Map<String, Boolean> possibleTransformOptions = new HashMap<>();
addToPossibleTransformOptions(possibleTransformOptions, transformOptions, true, actualOptions);
if (isSupported(possibleTransformOptions, actualOptions))
{
addToSupportedTransformList(transformListBySize, supportedTransform);
}
}
}
}
if (renditionName != null)
{
data.cachedSupportedTransformList.get(renditionName).put(sourceMimetype, transformListBySize);
}
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 void addToSupportedTransformList(List<SupportedTransform> transformListBySize, SupportedTransform newTransform)
{
for (int i=0; i < transformListBySize.size(); i++)
{
SupportedTransform existingTransform = transformListBySize.get(i);
int added = -1;
int compare = compare(newTransform.maxSourceSizeBytes, existingTransform.maxSourceSizeBytes);
if (compare < 0)
{
transformListBySize.add(i, newTransform);
added = i;
}
else if (compare == 0)
{
if (newTransform.priority < existingTransform.priority)
{
transformListBySize.set(i, newTransform);
added = i;
}
}
if (added == i)
{
for (i--; i >= 0; i--)
{
existingTransform = transformListBySize.get(i);
if (newTransform.priority <= existingTransform.priority)
{
transformListBySize.remove(i);
}
}
return;
}
}
transformListBySize.add(newTransform);
}
// compare where -1 is unlimited.
private int compare(long a, long b)
{
return a == -1
? b == -1 ? 0 : 1
: b == -1 ? -1
: a == b ? 0
: a > b ? 1 : -1;
}
/**
* 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 isSupported 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.
*/
boolean addToPossibleTransformOptions(Map<String, Boolean> possibleTransformOptions,
TransformOptionGroup transformOptionGroup,
Boolean parentGroupRequired, Map<String, String> actualOptions)
{
boolean added = false;
boolean required = false;
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 (TransformOption transformOption : optionList)
{
if (transformOption instanceof TransformOptionGroup)
{
added = addToPossibleTransformOptions(possibleTransformOptions, (TransformOptionGroup) transformOption,
transformOptionGroupRequired, actualOptions);
required |= added;
}
else
{
String name = ((TransformOptionValue) transformOption).getName();
if (actualOptions.containsKey(name))
{
required = true;
}
}
}
if (required || transformOptionGroupRequired)
{
for (TransformOption transformOption : optionList)
{
if (transformOption instanceof TransformOptionValue)
{
added = true;
TransformOptionValue transformOptionValue = (TransformOptionValue) transformOption;
String name = transformOptionValue.getName();
boolean optionValueRequired = transformOptionValue.isRequired();
possibleTransformOptions.put(name, optionValueRequired);
}
}
}
}
return added;
}
boolean isSupported(Map<String, Boolean> transformOptions, Map<String, String> actualOptions)
{
boolean supported = true;
// Check all required transformOptions are supplied
for (Map.Entry<String, Boolean> transformOption : transformOptions.entrySet())
{
Boolean required = transformOption.getValue();
if (required)
{
String name = transformOption.getKey();
if (!actualOptions.containsKey(name))
{
supported = false;
break;
}
}
}
if (supported)
{
// Check there are no extra unused actualOptions
for (String actualOption : actualOptions.keySet())
{
if (!transformOptions.containsKey(actualOption))
{
supported = false;
break;
}
}
}
return supported;
}
}

View File

@@ -0,0 +1,241 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2019 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 com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.transform.client.model.config.TransformConfig;
import org.alfresco.transform.client.model.config.TransformOption;
import org.alfresco.transform.client.model.config.Transformer;
import org.alfresco.util.ConfigFileFinder;
import org.apache.commons.logging.Log;
import org.apache.http.HttpEntity;
import org.apache.http.StatusLine;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* This class reads multiple T-Engine config and local files and registers them all with a registry as if they were all
* in one file. Transform options are shared between all sources.<p>
*
* The caller should make calls to {@link #addRemoteConfig(List, String)} and {@link #addLocalConfig(String)} followed
* by a call to {@link #register(TransformServiceRegistryImpl)}.
*
* @author adavis
*/
public class CombinedConfig
{
private static final String TRANSFORM_CONFIG = "/transform/config";
private final Log log;
static class TransformAndItsOrigin
{
final Transformer transformer;
final String baseUrl;
final String readFrom;
TransformAndItsOrigin(Transformer transformer, String baseUrl, String readFrom)
{
this.transformer = transformer;
this.baseUrl = baseUrl;
this.readFrom = readFrom;
}
}
Map<String, Set<TransformOption>> combinedTransformOptions = new HashMap<>();
List<TransformAndItsOrigin> combinedTransformers = new ArrayList<>();
private ObjectMapper jsonObjectMapper = new ObjectMapper();
private ConfigFileFinder configFileFinder;
private int tEngineCount;
public CombinedConfig(Log log)
{
this.log = log;
configFileFinder = new ConfigFileFinder(jsonObjectMapper)
{
@Override
protected void readJson(JsonNode jsonNode, String readFrom, String baseUrl)
{
TransformConfig transformConfig = jsonObjectMapper.convertValue(jsonNode, TransformConfig.class);
transformConfig.getTransformOptions().forEach((key, map) -> combinedTransformOptions.put(key, map));
transformConfig.getTransformers().forEach(transformer -> combinedTransformers.add(
new TransformAndItsOrigin(transformer, baseUrl, readFrom)));
}
};
}
public boolean addLocalConfig(String path)
{
return configFileFinder.readFiles(path, log);
}
public boolean addRemoteConfig(List<String> urls, String remoteType)
{
boolean successReadingConfig = true;
for (String url : urls)
{
if (addRemoteConfig(url, remoteType))
{
tEngineCount++ ;
}
else
{
successReadingConfig = false;
}
}
return successReadingConfig;
}
private boolean addRemoteConfig(String baseUrl, String remoteType)
{
String url = baseUrl + TRANSFORM_CONFIG;
HttpGet httpGet = new HttpGet(url);
boolean successReadingConfig = true;
try
{
try (CloseableHttpClient httpclient = HttpClients.createDefault())
{
try (CloseableHttpResponse response = execute(httpclient, httpGet))
{
StatusLine statusLine = response.getStatusLine();
if (statusLine == null)
{
throw new AlfrescoRuntimeException(remoteType+" on " + url+" returned no status ");
}
HttpEntity resEntity = response.getEntity();
if (resEntity != null)
{
int statusCode = statusLine.getStatusCode();
if (statusCode == 200)
{
try
{
String content = getContent(resEntity);
try (StringReader reader = new StringReader(content))
{
int transformCount = combinedTransformers.size();
configFileFinder.readFile(reader, remoteType+" on "+baseUrl, "json", baseUrl, log);
if (transformCount == combinedTransformers.size())
{
successReadingConfig = false;
}
}
EntityUtils.consume(resEntity);
}
catch (IOException e)
{
throw new AlfrescoRuntimeException("Failed to read the returned content from "+
remoteType+" on " + url, e);
}
}
else
{
String message = getErrorMessage(resEntity);
throw new AlfrescoRuntimeException(remoteType+" on " + url+" returned a " + statusCode +
" status " + message);
}
}
else
{
throw new AlfrescoRuntimeException(remoteType+" on " + url+" did not return an entity " + url);
}
}
catch (IOException e)
{
throw new AlfrescoRuntimeException("Failed to connect or to read the response from "+remoteType+
" on " + url, e);
}
}
catch (IOException e)
{
throw new AlfrescoRuntimeException(remoteType+" on " + url+" failed to create an HttpClient", e);
}
}
catch (AlfrescoRuntimeException e)
{
log.error(e.getMessage());
successReadingConfig = false;
}
return successReadingConfig;
}
// Tests mock the return values
CloseableHttpResponse execute(CloseableHttpClient httpclient, HttpGet httpGet) throws IOException
{
return httpclient.execute(httpGet);
}
// Tests mock the return values
String getContent(HttpEntity resEntity) throws IOException
{
return EntityUtils.toString(resEntity);
}
// Strip out just the error message in the response
private String getErrorMessage(HttpEntity resEntity) throws IOException
{
String message = "";
String content = getContent(resEntity);
int i = content.indexOf("\"message\":\"");
if (i != -1)
{
int j = content.indexOf("\",\"path\":", i);
if (j != -1)
{
message = content.substring(i+11, j);
}
}
return message;
}
public void register(TransformServiceRegistryImpl registry)
{
TransformServiceRegistryImpl.Data data = registry.getData();
data.setTEngineCount(tEngineCount);
data.setFileCount(configFileFinder.getFileCount());
combinedTransformers.forEach(transformer ->
registry.register(transformer.transformer, combinedTransformOptions,
transformer.baseUrl, transformer.readFrom));
}
}

View File

@@ -0,0 +1,169 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2018 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.transform.client.registry;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.alfresco.transform.client.registry.AbstractTransformRegistry;
import org.alfresco.transform.client.registry.TransformCache;
import org.alfresco.util.ConfigScheduler;
import org.alfresco.util.PropertyCheck;
import org.apache.commons.logging.Log;
import org.quartz.CronExpression;
import org.springframework.beans.factory.InitializingBean;
import java.io.IOException;
/**
* Used by clients to work out if a transformation is supported by the Transform Service.
*/
public abstract class TransformServiceRegistryImpl extends AbstractTransformRegistry implements InitializingBean
{
public static class Data extends TransformCache
{
private int tEngineCount = 0;
private int fileCount;
boolean firstTime = true;
@Override
public String toString()
{
return transformerCount == 0 && transformCount == 0 && tEngineCount == 0 && fileCount == 0
? ""
: "(transformers: "+transformerCount+" transforms: "+transformCount+" t-engines: "+tEngineCount+" files: "+fileCount+")";
}
public void setTEngineCount(int tEngineCount)
{
this.tEngineCount = tEngineCount;
}
public void setFileCount(int fileCount)
{
this.fileCount = fileCount;
}
}
protected boolean enabled = true;
private ObjectMapper jsonObjectMapper;
private CronExpression cronExpression;
private CronExpression initialAndOnErrorCronExpression;
private ConfigScheduler<Data> configScheduler = new ConfigScheduler<>(this)
{
@Override
public boolean readConfig() throws IOException
{
return TransformServiceRegistryImpl.this.readConfig();
}
@Override
public Data createData()
{
return TransformServiceRegistryImpl.this.createData();
}
};
public void setJsonObjectMapper(ObjectMapper jsonObjectMapper)
{
this.jsonObjectMapper = jsonObjectMapper;
}
public CronExpression getCronExpression()
{
return cronExpression;
}
public void setCronExpression(CronExpression cronExpression)
{
this.cronExpression = cronExpression;
}
public CronExpression getInitialAndOnErrorCronExpression()
{
return initialAndOnErrorCronExpression;
}
public void setInitialAndOnErrorCronExpression(CronExpression initialAndOnErrorCronExpression)
{
this.initialAndOnErrorCronExpression = initialAndOnErrorCronExpression;
}
@Override
public void afterPropertiesSet() throws Exception
{
PropertyCheck.mandatory(this, "jsonObjectMapper", jsonObjectMapper);
// If we have a cronExpression it indicates that we will schedule reading.
if (cronExpression != null)
{
PropertyCheck.mandatory(this, "initialAndOnErrorCronExpression", initialAndOnErrorCronExpression);
}
Log log = getLog();
configScheduler.run(enabled, log, cronExpression, initialAndOnErrorCronExpression);
}
public Data createData()
{
return new Data();
}
public Data getData()
{
return configScheduler.getData();
}
public abstract boolean readConfig() throws IOException;
public boolean isEnabled()
{
return enabled;
}
public void setEnabled(boolean enabled)
{
this.enabled = enabled;
setFirstTime(true);
}
protected void setFirstTime(boolean firstTime)
{
getData().firstTime = firstTime;
}
protected boolean getFirstTime()
{
return getData().firstTime;
}
protected abstract Log getLog();
@Override
protected void logError(String msg)
{
getLog().error(msg);
}
}

View File

@@ -201,7 +201,7 @@ import org.junit.runners.Suite;
org.alfresco.util.resource.HierarchicalResourceLoaderTest.class, org.alfresco.util.resource.HierarchicalResourceLoaderTest.class,
org.alfresco.repo.events.ClientUtilTest.class, org.alfresco.repo.events.ClientUtilTest.class,
org.alfresco.repo.rendition2.RenditionService2Test.class, org.alfresco.repo.rendition2.RenditionService2Test.class,
org.alfresco.transform.client.model.config.TransformServiceRegistryConfigTest.class org.alfresco.transform.client.registry.TransformServiceRegistryConfigTest.class
}) })
public class AllUnitTestsSuite public class AllUnitTestsSuite
{ {

View File

@@ -49,7 +49,7 @@ import org.junit.runners.Suite;
org.alfresco.repo.rawevents.TransactionAwareEventProducerTest.class, org.alfresco.repo.rawevents.TransactionAwareEventProducerTest.class,
// Requires running transformers // Requires running transformers
org.alfresco.transform.client.model.config.LocalTransformServiceRegistryConfigTest.class, org.alfresco.transform.client.registry.LocalTransformServiceRegistryConfigTest.class,
org.alfresco.repo.rendition2.RenditionService2IntegrationTest.class, org.alfresco.repo.rendition2.RenditionService2IntegrationTest.class,
org.alfresco.repo.rendition2.LocalTransformServiceRegistryIntegrationTest.class, org.alfresco.repo.rendition2.LocalTransformServiceRegistryIntegrationTest.class,
org.alfresco.repo.rendition2.LocalTransformClientIntegrationTest.class, org.alfresco.repo.rendition2.LocalTransformClientIntegrationTest.class,

View File

@@ -45,7 +45,7 @@ import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.cmr.security.PersonService; import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.QName;
import org.alfresco.service.transaction.TransactionService; import org.alfresco.service.transaction.TransactionService;
import org.alfresco.transform.client.model.config.TransformServiceRegistry; import org.alfresco.transform.client.registry.TransformServiceRegistry;
import org.alfresco.util.BaseSpringTest; import org.alfresco.util.BaseSpringTest;
import org.alfresco.util.GUID; import org.alfresco.util.GUID;
import org.alfresco.util.PropertyMap; import org.alfresco.util.PropertyMap;

View File

@@ -59,6 +59,6 @@ public class LocalRenditionTest extends AbstractRenditionTest
@Test @Test
public void testAllSourceExtensions() throws Exception public void testAllSourceExtensions() throws Exception
{ {
internalTestAllSourceExtensions(57, 0); internalTestAllSourceExtensions(81, 0);
} }
} }

View File

@@ -26,8 +26,8 @@
package org.alfresco.repo.rendition2; package org.alfresco.repo.rendition2;
import org.alfresco.repo.content.transform.LocalTransformServiceRegistry; import org.alfresco.repo.content.transform.LocalTransformServiceRegistry;
import org.alfresco.transform.client.model.config.TransformServiceRegistry; import org.alfresco.transform.client.registry.TransformServiceRegistry;
import org.alfresco.transform.client.model.config.TransformServiceRegistryImpl; import org.alfresco.transform.client.registry.TransformServiceRegistryImpl;
import org.junit.After; import org.junit.After;
import org.junit.AfterClass; import org.junit.AfterClass;
import org.junit.Assert; import org.junit.Assert;

View File

@@ -39,7 +39,7 @@ import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.rule.RuleService; import org.alfresco.service.cmr.rule.RuleService;
import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.QName;
import org.alfresco.service.transaction.TransactionService; import org.alfresco.service.transaction.TransactionService;
import org.alfresco.transform.client.model.config.TransformServiceRegistryImpl; import org.alfresco.transform.client.registry.TransformServiceRegistryImpl;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;

View File

@@ -1,54 +0,0 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2018 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.transform.client.model.config;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* Helper class that builds a {@link InlineTransformer} given the source and target types and a pipeline of Transformers
* for creating intermediary content.
*/
public class TransformBuilder
{
public InlineTransformer buildPipeLine(String name, Set<SupportedSourceAndTarget> sourceAndTargetList,
List<ChildTransformer> transformerList)
{
Set<TransformOption> options = new HashSet<>(transformerList.size());
transformerList.forEach(t ->
{
// Avoid creating an enpty TransformOptionGroup if the transformer has no options.
// Works with an empty TransformOptionGroup but adds to the complexity.
if (t.getTransformer().getTransformOptions() != null)
{
options.add(new TransformOptionGroup(t.isRequired(), t.getTransformer().getTransformOptions()));
}
});
return new InlineTransformer(name, options, sourceAndTargetList);
}
}

View File

@@ -1,896 +0,0 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2019 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.model.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.log4j.Level;
import org.apache.log4j.LogManager;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.quartz.CronExpression;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
/**
* Test the config received from the Transform Service about what it supports.
*/
public class TransformServiceRegistryConfigTest
{
private static Log log = LogFactory.getLog(TransformServiceRegistryConfigTest.class);
public static final String GIF = "image/gif";
public static final String JPEG = "image/jpeg";
public static final String PNG = "image/png";
public static final String TIFF = "image/tiff";
public static final String PDF = "application/pdf";
public static final String DOC = "application/msword";
public static final String XLS = "application/vnd.ms-excel";
public static final String PPT = "application/vnd.ms-powerpoint";
public static final String MSG = "application/vnd.ms-outlook";
public static final String TXT = "text/plain";
private static final String TRANSFORM_SERVICE_CONFIG = "alfresco/transform-service-config-test.json";
private static final String TRANSFORM_SERVICE_CONFIG_PIPELINE = "alfresco/transform-service-config-pipeline-test.json";
public static final ObjectMapper JSON_OBJECT_MAPPER = new ObjectMapper();
private TransformServiceRegistryImpl registry;
protected TransformBuilder builder;
protected InlineTransformer transformer;
@Before
public void setUp() throws Exception
{
registry = buildTransformServiceRegistryImpl();
builder = new TransformBuilder();
LogManager.getLogger(TransformServiceRegistryConfigTest.class).setLevel(Level.DEBUG);
}
protected TransformServiceRegistryImpl buildTransformServiceRegistryImpl() throws Exception
{
TransformServiceRegistryImpl registry = new TransformServiceRegistryImpl()
{
@Override
public boolean readConfig() throws IOException
{
return true;
}
@Override
protected Log getLog()
{
return log;
}
};
registry.setJsonObjectMapper(JSON_OBJECT_MAPPER);
registry.setCronExpression(null); // just read once
registry.afterPropertiesSet();
return registry;
}
@After
public void tearDown()
{
// shut down
}
protected String getTransformServiceConfig()
{
return TRANSFORM_SERVICE_CONFIG;
}
protected String getTransformServiceConfigPipeline()
{
return TRANSFORM_SERVICE_CONFIG_PIPELINE;
}
private void assertAddToPossibleOptions(TransformOptionGroup transformOptionGroup, String actualOptionNames, String expectedNames, String expectedRequired)
{
Map<String, String> actualOptions = buildActualOptions(actualOptionNames);
Set<String> expectedNameSet = expectedNames == null || expectedNames.isEmpty() ? Collections.EMPTY_SET : new HashSet(Arrays.asList(expectedNames.split(", ")));
Set<String> expectedRequiredSet = expectedRequired == null || expectedRequired.isEmpty() ? Collections.EMPTY_SET : new HashSet(Arrays.asList(expectedRequired.split(", ")));
Map<String, Boolean> possibleTransformOptions = new HashMap<>();
registry.addToPossibleTransformOptions(possibleTransformOptions, transformOptionGroup, true, actualOptions);
assertEquals("The expected options don't match", expectedNameSet, possibleTransformOptions.keySet());
for (String name: possibleTransformOptions.keySet())
{
Boolean required = possibleTransformOptions.get(name);
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(String actualOptionNames, String transformOptionNames, String unsupportedMsg)
{
Map<String, String> actualOptions = buildActualOptions(actualOptionNames);
Map<String, Boolean> transformOptions = new HashMap<>();
Set<String> transformOptionNameSet = transformOptionNames == null || transformOptionNames.isEmpty() ? Collections.EMPTY_SET : new HashSet(Arrays.asList(transformOptionNames.split(", ")));
for (String name : transformOptionNameSet)
{
Boolean required = name.toUpperCase().equals(name);
transformOptions.put(name, required);
}
boolean supported = registry.isSupported(transformOptions, actualOptions);
if (unsupportedMsg == null || unsupportedMsg.isEmpty())
{
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> transformOptions) throws Exception
{
transformer = new InlineTransformer("name",
transformOptions,
Set.of(
new SupportedSourceAndTarget(DOC, TXT, -1),
new SupportedSourceAndTarget(XLS, TXT, 1024000)));
registry = buildTransformServiceRegistryImpl();
registry.register(transformer, getBaseUrl(transformer), getClass().getName());
assertTrue(registry.isSupported(XLS, 1024, TXT, Collections.emptyMap(), null));
assertTrue(registry.isSupported(XLS, 1024000, TXT, null, null));
assertFalse(registry.isSupported(XLS, 1024001, TXT, Collections.emptyMap(), null));
assertTrue(registry.isSupported(DOC, 1024001, TXT, null, null));
}
protected String getBaseUrl(InlineTransformer transformer)
{
return null;
}
private void assertTransformerName(String sourceMimetype, long sourceSizeInBytes, String targetMimetype,
Map<String, String> actualOptions, String expectedTransformerName,
InlineTransformer... transformers) throws Exception
{
buildAndPopulateRegistry(transformers);
String transformerName = registry.getTransformerName(sourceMimetype, sourceSizeInBytes, targetMimetype, actualOptions, null);
assertEquals(sourceMimetype+" to "+targetMimetype+" should have returned "+expectedTransformerName, expectedTransformerName, transformerName);
}
private void assertSupported(String sourceMimetype, long sourceSizeInBytes, String targetMimetype,
Map<String, String> actualOptions, 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,
InlineTransformer... transformers) throws Exception
{
buildAndPopulateRegistry(transformers);
assertSupported(sourceMimetype, sourceSizeInBytes, targetMimetype, actualOptions, null, unsupportedMsg);
}
private void buildAndPopulateRegistry(InlineTransformer[] transformers) throws Exception
{
registry = buildTransformServiceRegistryImpl();
for (InlineTransformer transformer : transformers)
{
registry.register(transformer, getBaseUrl(transformer), getClass().getName());
}
}
private 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 Map<String, String> buildActualOptions(String actualOptionNames)
{
Map<String, String> actualOptions = new HashMap<>();
Set<String> actualOptionNamesSet = actualOptionNames == null || actualOptionNames.isEmpty() ? Collections.EMPTY_SET : new HashSet(Arrays.asList(actualOptionNames.split(", ")));
for (String name : actualOptionNamesSet)
{
actualOptions.put(name, "value for " + name);
}
return actualOptions;
}
private void register(String path) throws IOException
{
CombinedConfig combinedConfig = new CombinedConfig(log);
combinedConfig.addLocalConfig(path);
combinedConfig.register(registry);
}
@Test
public void testReadWriteJson() throws IOException
{
InlineTransformer libreoffice = new InlineTransformer("libreoffice",
null, // there are no options
Set.of(
new SupportedSourceAndTarget(DOC, PDF, -1),
new SupportedSourceAndTarget(XLS, PDF, 1024000),
new SupportedSourceAndTarget(PPT, PDF, -1),
new SupportedSourceAndTarget(MSG, PDF, -1)));
InlineTransformer pdfrenderer = new InlineTransformer("pdfrenderer",
Set.of(
new TransformOptionValue(false, "page"),
new TransformOptionValue(false, "width"),
new TransformOptionValue(false, "height"),
new TransformOptionValue(false, "allowPdfEnlargement"),
new TransformOptionValue(false, "maintainPdfAspectRatio")),
Set.of(
new SupportedSourceAndTarget(PDF, PNG, -1)));
InlineTransformer tika = new InlineTransformer("tika",
Set.of(
new TransformOptionValue(false, "transform"),
new TransformOptionValue(false, "includeContents"),
new TransformOptionValue(false, "notExtractBookmarksText"),
new TransformOptionValue(false, "targetMimetype"),
new TransformOptionValue(false, "targetEncoding")),
Set.of(
new SupportedSourceAndTarget(PDF, TXT, -1),
new SupportedSourceAndTarget(DOC, TXT, -1),
new SupportedSourceAndTarget(XLS, TXT, 1024000),
new SupportedSourceAndTarget(PPT, TXT, -1),
new SupportedSourceAndTarget(MSG, TXT, -1)));
InlineTransformer imagemagick = new InlineTransformer("imagemagick",
Set.of(
new TransformOptionValue(false, "alphaRemove"),
new TransformOptionValue(false, "autoOrient"),
new TransformOptionGroup(false, Set.of(
new TransformOptionValue(false, "cropGravity"),
new TransformOptionValue(false, "cropWidth"),
new TransformOptionValue(false, "cropHeight"),
new TransformOptionValue(false, "cropPercentage"),
new TransformOptionValue(false, "cropXOffset"),
new TransformOptionValue(false, "cropYOffset"))),
new TransformOptionGroup(false, Set.of(
new TransformOptionValue(false, "thumbnail"),
new TransformOptionValue(false, "resizeHeight"),
new TransformOptionValue(false, "resizeWidth"),
new TransformOptionValue(false, "resizePercentage"),
new TransformOptionValue(false, "maintainAspectRatio")))),
Set.of(
new SupportedSourceAndTarget(GIF, GIF, -1),
new SupportedSourceAndTarget(GIF, JPEG, -1),
new SupportedSourceAndTarget(GIF, PNG, -1),
new SupportedSourceAndTarget(GIF, TIFF, -1),
new SupportedSourceAndTarget(JPEG, GIF, -1),
new SupportedSourceAndTarget(JPEG, JPEG, -1),
new SupportedSourceAndTarget(JPEG, PNG, -1),
new SupportedSourceAndTarget(JPEG, TIFF, -1),
new SupportedSourceAndTarget(PNG, GIF, -1),
new SupportedSourceAndTarget(PNG, JPEG, -1),
new SupportedSourceAndTarget(PNG, PNG, -1),
new SupportedSourceAndTarget(PNG, TIFF, -1),
new SupportedSourceAndTarget(TIFF, GIF, -1),
new SupportedSourceAndTarget(TIFF, JPEG, -1),
new SupportedSourceAndTarget(TIFF, PNG, -1),
new SupportedSourceAndTarget(TIFF, TIFF, -1)));
InlineTransformer officeToImage = builder.buildPipeLine("transformer1",
Set.of(
new SupportedSourceAndTarget(DOC, GIF, -1),
new SupportedSourceAndTarget(DOC, JPEG, -1),
new SupportedSourceAndTarget(DOC, PNG, -1),
new SupportedSourceAndTarget(DOC, TIFF, -1),
new SupportedSourceAndTarget(XLS, GIF, -1),
new SupportedSourceAndTarget(XLS, JPEG, -1),
new SupportedSourceAndTarget(XLS, PNG, -1),
new SupportedSourceAndTarget(XLS, TIFF, -1),
new SupportedSourceAndTarget(PPT, GIF, -1),
new SupportedSourceAndTarget(PPT, JPEG, -1),
new SupportedSourceAndTarget(PPT, PNG, -1),
new SupportedSourceAndTarget(PPT, TIFF, -1),
new SupportedSourceAndTarget(MSG, GIF, -1),
new SupportedSourceAndTarget(MSG, JPEG, -1),
new SupportedSourceAndTarget(MSG, PNG, -1),
new SupportedSourceAndTarget(MSG, TIFF, -1)),
Arrays.asList(
new ChildTransformer(false, libreoffice), // to pdf
new ChildTransformer(false, pdfrenderer), // to png
new ChildTransformer(true, imagemagick))); // to other image formats
List<InlineTransformer> transformers1 = Arrays.asList(libreoffice, tika, pdfrenderer, imagemagick, officeToImage);
File tempFile = File.createTempFile("test", ".json");
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.writerWithDefaultPrettyPrinter().writeValue(new FileWriter(tempFile), transformers1);
try (Reader reader = new BufferedReader(new FileReader(tempFile)))
{
registry.register(reader, getClass().getName());
// Check the count of transforms supported
assertEquals("The number of UNIQUE source to target mimetypes transforms has changed. Config change?",
42, countSupportedTransforms(true));
assertEquals("The number of source to target mimetypes transforms has changed. " +
"There may be multiple transformers for the same combination. Config change?",
42, countSupportedTransforms(false));
// Check a supported transform for each transformer.
assertSupported(DOC, 1234, PDF, null, null, ""); // libreoffice
assertSupported(DOC, 1234, PDF, null, null, ""); // libreoffice
assertSupported(PDF, 1234, PNG, null, null, ""); // pdfrenderer
assertSupported(JPEG,1234, GIF, null, null, ""); // imagemagick
assertSupported(MSG, 1234, TXT, null, null, ""); // tika
assertSupported(MSG, 1234, GIF, null, null, ""); // transformer1 (officeToImageViaPdf)
assertSupported(DOC, 1234, PNG, null, null, ""); // transformer1 (officeToImageViaPdf)
}
}
@Test
public void testJsonConfig() throws IOException
{
register(getTransformServiceConfig());
// Check the count of transforms supported
assertEquals("The number of UNIQUE source to target mimetypes transforms has changed. Config change?",
60, countSupportedTransforms(true));
assertEquals("The number of source to target mimetypes transforms has changed. " +
"There may be multiple transformers for the same combination. Config change?",
60, countSupportedTransforms(false));
// Check a supported transform for each transformer.
assertSupported(DOC, 1234, PDF, null, null, ""); // libreoffice
assertSupported(DOC, 1234, PDF, null, null, ""); // libreoffice
assertSupported(PDF, 1234, PNG, null, null, ""); // pdfrenderer
assertSupported(JPEG,1234, GIF, null, null, ""); // imagemagick
assertSupported(MSG, 1234, TXT, null, null, ""); // tika
assertSupported(MSG, 1234, GIF, null, null, ""); // officeToImageViaPdf
Map<String, String> invalidPdfOptions = new HashMap<>();
invalidPdfOptions.put("allowEnlargement", "false");
assertSupported(DOC, 1234, PDF, invalidPdfOptions, null, "Invalid as there is a extra option");
}
@Test
public void testJsonPipeline() throws IOException
{
register(getTransformServiceConfigPipeline());
// Check the count of transforms supported
int expectedTransforms = getExpectedTransformsForTestJsonPipeline();
assertEquals("The number of UNIQUE source to target mimetypes transforms has changed. Config change?",
expectedTransforms, countSupportedTransforms(true));
assertEquals("The number of source to target mimetypes transforms has changed. " +
"There may be multiple transformers for the same combination. Config change?",
expectedTransforms, countSupportedTransforms(false));
ConcurrentMap<String, List<TransformServiceRegistryImpl.SupportedTransform>> transformer =
registry.getData().transformers.get("officeToImageViaPdf");
// Check required and optional default correctly
ConcurrentMap<String, List<TransformServiceRegistryImpl.SupportedTransform>> transformsToWord =
registry.getData().transformers.get(DOC);
List<TransformServiceRegistryImpl.SupportedTransform> supportedTransforms = transformsToWord.get(GIF);
TransformServiceRegistryImpl.SupportedTransform supportedTransform = supportedTransforms.get(0);
Set<TransformOption> transformOptionsSet = supportedTransform.transformOptions.getTransformOptions();
System.out.println("Nothing");
Iterator<TransformOption> iterator = transformOptionsSet.iterator();
assertTrue("Expected transform values", iterator.hasNext());
// Because Set is unordered we don't know which TransformOptionGroup we retrieve
TransformOptionGroup transformOptions1 = (TransformOptionGroup)iterator.next();
assertTrue("Expected transform values", iterator.hasNext());
TransformOptionGroup transformOptions2 = (TransformOptionGroup)iterator.next();
TransformOptionGroup imagemagick;
TransformOptionGroup pdf;
if(containsTransformOptionValueName(transformOptions1, "alphaRemove"))
{
imagemagick = transformOptions1;
pdf = transformOptions2;
}
else
{
imagemagick = transformOptions2;
pdf = transformOptions1;
}
TransformOptionValue alphaRemove = (TransformOptionValue)retrieveTransformOptionByPropertyName(imagemagick, "alphaRemove", "TransformOptionValue");
TransformOptionGroup crop = (TransformOptionGroup)retrieveTransformOptionByPropertyName(imagemagick, "crop", "TransformOptionGroup");
TransformOptionValue cropGravity = (TransformOptionValue)retrieveTransformOptionByPropertyName(crop, "cropGravity", "TransformOptionValue");
TransformOptionValue cropWidth = (TransformOptionValue)retrieveTransformOptionByPropertyName(crop, "cropWidth", "TransformOptionValue");
assertTrue("The holding group should be required", supportedTransform.transformOptions.isRequired());
assertFalse("imagemagick should be optional as it is not set", imagemagick.isRequired());
assertFalse("pdf should be optional as required is not set", pdf.isRequired());
assertEquals("alphaRemove", alphaRemove.getName());
assertEquals("cropGravity", cropGravity.getName());
assertEquals("cropWidth", cropWidth.getName());
assertFalse("alphaRemove should be optional as required is not set", alphaRemove.isRequired());
assertFalse("crop should be optional as required is not set", crop.isRequired());
assertTrue("cropGravity should be required as it is set", cropGravity.isRequired());
assertFalse("cropWidth should be optional as required is not set", cropWidth.isRequired());
// Check a supported transform for each transformer.
assertSupported(DOC,1234, GIF, null, null, "");
assertSupported(DOC,1234, PNG, null, null, "");
assertSupported(DOC,1234, JPEG, null, null, "");
assertSupported(DOC,1234, TIFF, null, null, "");
Map<String, String> actualOptions = new HashMap<>();
actualOptions.put("thumbnail", "true");
actualOptions.put("resizeWidth", "100");
actualOptions.put("resizeHeight", "100");
actualOptions.put("allowEnlargement", "false");
actualOptions.put("maintainAspectRatio", "true");
assertSupported(DOC,1234, PNG, actualOptions, null, "");
}
private TransformOption retrieveTransformOptionByPropertyName (TransformOptionGroup transformOptionGroup, String propertyName, String propertyType)
{
Iterator<TransformOption> iterator = transformOptionGroup.getTransformOptions().iterator();
List<TransformOption> transformOptionsList = new ArrayList<>();
while(iterator.hasNext())
{
transformOptionsList.add(iterator.next());
}
for (TransformOption t : transformOptionsList)
{
if (t instanceof TransformOptionValue)
{
TransformOptionValue value = (TransformOptionValue) t;
if (propertyType.equalsIgnoreCase("TransformOptionValue"))
{
if (value.getName().equalsIgnoreCase(propertyName))
return value;
}
else
{
if (value.getName().contains(propertyName))
return transformOptionGroup;
}
}
else
{
TransformOption result = retrieveTransformOptionByPropertyName((TransformOptionGroup)t, propertyName, propertyType);
if (result != null)
return result;
}
}
return null;
}
private boolean containsTransformOptionValueName (TransformOptionGroup transformOptionGroup, String propertyName)
{
if (retrieveTransformOptionByPropertyName(transformOptionGroup, propertyName, "TransformOptionValue") != null)
return true;
return false;
}
private boolean containsTransformOptionGroupeName (TransformOptionGroup transformOptionGroup, String propertyName)
{
if (retrieveTransformOptionByPropertyName(transformOptionGroup, propertyName, "TransformOptionGroup") != null)
return true;
return false;
}
protected int getExpectedTransformsForTestJsonPipeline()
{
return 4;
}
private int countSupportedTransforms(boolean unique)
{
int count = 0;
int uniqueCount = 0;
for (ConcurrentMap<String, List<TransformServiceRegistryImpl.SupportedTransform>> targetMap : registry.getData().transformers.values())
{
for (List<TransformServiceRegistryImpl.SupportedTransform> supportedTransforms : targetMap.values())
{
uniqueCount++;
count += supportedTransforms.size();
}
}
return unique ? uniqueCount : count;
}
@Test
public void testOptionalGroups()
{
TransformOptionGroup transformOptionGroup =
new TransformOptionGroup(true, Set.of(
new TransformOptionValue(false, "1"),
new TransformOptionValue(true, "2"),
new TransformOptionGroup(false, Set.of(
new TransformOptionValue(false, "3.1"),
new TransformOptionValue(false, "3.2"),
new TransformOptionValue(false, "3.3"))),
new TransformOptionGroup(false, Set.of( // OPTIONAL
new TransformOptionValue(false, "4.1"),
new TransformOptionValue(true, "4.2"),
new TransformOptionValue(false, "4.3")))));
assertAddToPossibleOptions(transformOptionGroup, "", "1, 2", "2");
assertAddToPossibleOptions(transformOptionGroup, "1", "1, 2", "2");
assertAddToPossibleOptions(transformOptionGroup, "2", "1, 2", "2");
assertAddToPossibleOptions(transformOptionGroup, "2, 3.2", "1, 2, 3.1, 3.2, 3.3", "2");
assertAddToPossibleOptions(transformOptionGroup, "2, 4.1", "1, 2, 4.1, 4.2, 4.3", "2, 4.2");
assertAddToPossibleOptions(transformOptionGroup, "2, 4.2", "1, 2, 4.1, 4.2, 4.3", "2, 4.2");
}
@Test
public void testRequiredGroup()
{
TransformOptionGroup transformOptionGroup =
new TransformOptionGroup(true, Set.of(
new TransformOptionValue(false, "1"),
new TransformOptionValue(true, "2"),
new TransformOptionGroup(false, Set.of(
new TransformOptionValue(false, "3.1"),
new TransformOptionValue(false, "3.2"),
new TransformOptionValue(false, "3.3"))),
new TransformOptionGroup(true, Set.of( // REQUIRED
new TransformOptionValue(false, "4.1"),
new TransformOptionValue(true, "4.2"),
new TransformOptionValue(false, "4.3")))));
assertAddToPossibleOptions(transformOptionGroup, "", "1, 2, 4.1, 4.2, 4.3", "2, 4.2");
assertAddToPossibleOptions(transformOptionGroup, "1", "1, 2, 4.1, 4.2, 4.3", "2, 4.2");
assertAddToPossibleOptions(transformOptionGroup, "2, 3.2", "1, 2, 3.1, 3.2, 3.3, 4.1, 4.2, 4.3", "2, 4.2");
assertAddToPossibleOptions(transformOptionGroup, "2, 4.1", "1, 2, 4.1, 4.2, 4.3", "2, 4.2");
assertAddToPossibleOptions(transformOptionGroup, "2, 4.2", "1, 2, 4.1, 4.2, 4.3", "2, 4.2");
}
@Test
public void testNesstedGrpups()
{
TransformOptionGroup transformOptionGroup =
new TransformOptionGroup(false, Set.of(
new TransformOptionGroup(false, Set.of(
new TransformOptionValue(false, "1"),
new TransformOptionGroup(false, Set.of(
new TransformOptionValue(false, "1.2"),
new TransformOptionGroup(false, Set.of(
new TransformOptionValue(false, "1.2.3"))))))),
new TransformOptionGroup(false, Set.of(
new TransformOptionValue(false, "2"),
new TransformOptionGroup(false, Set.of(
new TransformOptionValue(false, "2.2"),
new TransformOptionGroup(false, Set.of(
new TransformOptionGroup(false, Set.of(
new TransformOptionValue(false, "2.2.1.2"))))))))),
new TransformOptionGroup(false, Set.of(
new TransformOptionValue(true, "3"), // REQUIRED
new TransformOptionGroup(false, Set.of(
new TransformOptionGroup(false, Set.of(
new TransformOptionGroup(false, Set.of(
new TransformOptionValue(false, "3.1.1.2"))))))))),
new TransformOptionGroup(false, Set.of(
new TransformOptionValue(false, "4"),
new TransformOptionGroup(true, Set.of( // REQUIRED
new TransformOptionGroup(false, Set.of(
new TransformOptionGroup(false, Set.of(
new TransformOptionValue(false, "4.1.1.2"))))))))),
new TransformOptionGroup(false, Set.of(
new TransformOptionValue(false, "5"),
new TransformOptionGroup(false, Set.of(
new TransformOptionGroup(true, Set.of( // REQUIRED
new TransformOptionGroup(false, Set.of(
new TransformOptionValue(false, "5.1.1.2"))))))))),
new TransformOptionGroup(false, Set.of(
new TransformOptionValue(false, "6"),
new TransformOptionGroup(false, Set.of(
new TransformOptionGroup(false, Set.of(
new TransformOptionGroup(true, Set.of( // REQUIRED
new TransformOptionValue(false, "6.1.1.2"))))))))),
new TransformOptionGroup(false, Set.of(
new TransformOptionValue(false, "7"),
new TransformOptionGroup(false, Set.of(
new TransformOptionGroup(false, Set.of(
new TransformOptionGroup(false, Set.of(
new TransformOptionValue(true, "7.1.1.2"))))))))) // REQUIRED
));
assertAddToPossibleOptions(transformOptionGroup, "", "", "");
assertAddToPossibleOptions(transformOptionGroup, "1", "1", "");
assertAddToPossibleOptions(transformOptionGroup, "1, 7", "1, 7", "");
assertAddToPossibleOptions(transformOptionGroup, "1, 7.1.1.2", "1, 7, 7.1.1.2", "7.1.1.2");
assertAddToPossibleOptions(transformOptionGroup, "1, 6", "1, 6", "");
assertAddToPossibleOptions(transformOptionGroup, "1, 6.1.1.2", "1, 6, 6.1.1.2", "");
assertAddToPossibleOptions(transformOptionGroup, "1, 5", "1, 5", "");
assertAddToPossibleOptions(transformOptionGroup, "1, 5.1.1.2", "1, 5, 5.1.1.2", "");
assertAddToPossibleOptions(transformOptionGroup, "1, 4", "1, 4", "");
assertAddToPossibleOptions(transformOptionGroup, "1, 4.1.1.2", "1, 4, 4.1.1.2", "");
assertAddToPossibleOptions(transformOptionGroup, "1, 3", "1, 3", "3");
assertAddToPossibleOptions(transformOptionGroup, "1, 3.1.1.2", "1, 3, 3.1.1.2", "3");
assertAddToPossibleOptions(transformOptionGroup, "2", "2", "");
assertAddToPossibleOptions(transformOptionGroup, "2, 2.2", "2, 2.2", "");
assertAddToPossibleOptions(transformOptionGroup, "3", "3", "3");
assertAddToPossibleOptions(transformOptionGroup, "3.1.1.2", "3, 3.1.1.2", "3");
}
@Test
public void testSupportedOptions()
{
assertIsSupported("a", "a, B, c", "required option B is missing");
assertIsSupported("", "a, B, c", "required option B is missing");
assertIsSupported("B", "a, B, c", null);
assertIsSupported("B, c", "a, B, c", null);
assertIsSupported("B, a, c", "a, B, c", null);
assertIsSupported("B, d", "a, B, c", "there is an extra option d");
assertIsSupported("B, c, d", "a, B, c", "there is an extra option d");
assertIsSupported("d", "a, B, c", "required option B is missing and there is an extra option d");
assertIsSupported("a", "a, b, c", null);
assertIsSupported("", "a, b, c", null);
assertIsSupported("a, b, c", "a, b, c", null);
}
@Test
public void testNoActualOptions() throws Exception
{
assertTransformOptions(Set.of(
new TransformOptionValue(false, "option1"),
new TransformOptionValue(false, "option2")));
}
@Test
public void testNoTrasformOptions() throws Exception
{
assertTransformOptions(Collections.emptySet());
assertTransformOptions(null);
}
@Test
public void testSupported() throws Exception
{
transformer = new InlineTransformer("name",
Set.of(
new TransformOptionValue(false, "page"),
new TransformOptionValue(false, "width"),
new TransformOptionValue(false, "height")),
Set.of(
new SupportedSourceAndTarget(DOC, GIF, 102400),
new SupportedSourceAndTarget(DOC, JPEG, -1),
new SupportedSourceAndTarget(MSG, GIF, -1)));
assertSupported(DOC, 1024, GIF, null, null);
assertSupported(DOC, 102400, GIF, null, null);
assertSupported(DOC, 102401, GIF, null, "source is too large");
assertSupported(DOC, 1024, JPEG, null, null);
assertSupported(GIF, 1024, DOC, null, GIF+" is not a source of this transformer");
assertSupported(MSG, 1024, GIF, null, null);
assertSupported(MSG, 1024, JPEG, null, MSG+" to "+JPEG+" is not supported by this transformer");
assertSupported(DOC, 1024, GIF, buildActualOptions("page, width"), null);
assertSupported(DOC, 1024, GIF, buildActualOptions("page, width, startPage"), "startPage is not an option");
}
@Test
public void testCache()
{
// Note: transformNames are an alias for a set of actualOptions and the target mimetpe. The source mimetype may change.
transformer = new InlineTransformer("name",
Set.of(
new TransformOptionValue(false, "page"),
new TransformOptionValue(false, "width"),
new TransformOptionValue(false, "height")),
Set.of(
new SupportedSourceAndTarget(DOC, GIF, 102400),
new SupportedSourceAndTarget(MSG, GIF, -1)));
registry.register(transformer, getBaseUrl(transformer), getClass().getName());
assertSupported(DOC, 1024, GIF, null, "doclib", "");
assertSupported(MSG, 1024, GIF, null, "doclib", "");
assertEquals(102400L, registry.getMaxSize(DOC, GIF, null, "doclib"));
assertEquals(-1L, registry.getMaxSize(MSG, GIF, null, "doclib"));
// Change the cached value and try and check we are now using the cached value.
List<TransformServiceRegistryImpl.SupportedTransform> supportedTransforms = registry.getData().cachedSupportedTransformList.get("doclib").get(DOC);
supportedTransforms.get(0).maxSourceSizeBytes = 1234L;
assertEquals(1234L, registry.getMaxSize(DOC, GIF, null, "doclib"));
}
@Test
public void testGetTransformerName() throws Exception
{
InlineTransformer t1 = new InlineTransformer("transformer1", null,
Set.of(new SupportedSourceAndTarget(MSG, GIF, 100, 50)));
InlineTransformer t2 = new InlineTransformer("transformer2", null,
Set.of(new SupportedSourceAndTarget(MSG, GIF, 200, 60)));
InlineTransformer t3 = new InlineTransformer("transformer3", null,
Set.of(new SupportedSourceAndTarget(MSG, GIF, 200, 40)));
InlineTransformer t4 = new InlineTransformer("transformer4", null,
Set.of(new SupportedSourceAndTarget(MSG, GIF, -1, 100)));
InlineTransformer t5 = new InlineTransformer("transformer5", null,
Set.of(new SupportedSourceAndTarget(MSG, GIF, -1, 80)));
Map<String, String> actualOptions = null;
// Select on size - priority is ignored
assertTransformerName(MSG, 100, GIF, actualOptions, "transformer1", t1, t2);
assertTransformerName(MSG, 150, GIF, actualOptions, "transformer2", t1, t2);
assertTransformerName(MSG, 250, GIF, actualOptions, 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, actualOptions, "transformer3", t1, t2, t3, t4, t5);
assertTransformerName(MSG, 200, GIF, actualOptions, "transformer3", t1, t2, t3, t4, t5);
// Select on size and priority, t1 and t2 discarded
assertTransformerName(MSG, 200, GIF, actualOptions, "transformer3", t1, t2, t3, t4);
assertTransformerName(MSG, 300, GIF, actualOptions, "transformer4", t1, t2, t3, t4);
assertTransformerName(MSG, 300, GIF, actualOptions, "transformer5", t1, t2, t3, t4, t5);
}
@Test
public void testMultipleTransformers() throws Exception
{
InlineTransformer transformer1 = new InlineTransformer("transformer1",
Set.of(
new TransformOptionValue(false, "page"),
new TransformOptionValue(false, "width"),
new TransformOptionValue(false, "height")),
Set.of(
new SupportedSourceAndTarget(DOC, GIF, 102400),
new SupportedSourceAndTarget(DOC, JPEG, -1),
new SupportedSourceAndTarget(MSG, GIF, -1)));
InlineTransformer transformer2 = new InlineTransformer("transformer2",
Set.of(
new TransformOptionValue(false, "opt1"),
new TransformOptionValue(false, "opt2")),
Set.of(
new SupportedSourceAndTarget(PDF, GIF, -1),
new SupportedSourceAndTarget(PPT, JPEG, -1)));
InlineTransformer transformer3 = new InlineTransformer("transformer3",
Set.of(
new TransformOptionValue(false, "opt1")),
Set.of(
new SupportedSourceAndTarget(DOC, GIF, -1)));
Map<String, String> actualOptions = null;
assertSupported(DOC, 1024, GIF, actualOptions, null, transformer1);
assertSupported(DOC, 1024, GIF, actualOptions, null, transformer1, transformer2);
assertSupported(DOC, 1024, GIF, actualOptions, null, transformer1, transformer2, transformer3);
assertSupported(DOC, 102401, GIF, null, "source is too large", transformer1);
assertSupported(DOC, 102401, GIF, null, null, transformer1, transformer3);
assertSupported(PDF, 1024, GIF, actualOptions, "Only transformer2 supports these mimetypes", transformer1);
assertSupported(PDF, 1024, GIF, actualOptions, null, transformer1, transformer2);
assertSupported(PDF, 1024, GIF, actualOptions, null, transformer1, transformer2, transformer3);
actualOptions = buildActualOptions("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);
}
@Test
public void testPipeline() throws Exception
{
InlineTransformer transformer1 = new InlineTransformer("transformer1",
null, // there are no options
Set.of(
new SupportedSourceAndTarget(DOC, PDF, -1),
new SupportedSourceAndTarget(MSG, PDF, -1)));
InlineTransformer transformer2 = new InlineTransformer("transformer2",
Set.of(
new TransformOptionValue(false, "page"),
new TransformOptionValue(false, "width"),
new TransformOptionValue(false, "height")),
Set.of(
new SupportedSourceAndTarget(PDF, GIF, -1),
new SupportedSourceAndTarget(PDF, JPEG, -1)));
buildPipelineTransformer(transformer1, transformer2);
assertSupported(DOC, 1024, GIF, null, null);
assertSupported(DOC, 1024, JPEG, null, null);
assertSupported(GIF, 1024, DOC, null, GIF+" is not a source of this transformer");
assertSupported(MSG, 1024, GIF, null, null);
assertSupported(MSG, 1024, JPEG, null, MSG+" to "+JPEG+" is not supported by this transformer");
// Now try the options
assertSupported(DOC, 1024, GIF, buildActualOptions("page, width"), null);
assertSupported(DOC, 1024, GIF, buildActualOptions("page, width, startPage"), "startPage is not an option");
// Add options to the first transformer
transformer1.setTransformOptions(Set.of(
new TransformOptionValue(false, "startPage"),
new TransformOptionValue(false, "endPage")));
buildPipelineTransformer(transformer1, transformer2);
assertSupported(DOC, 1024, GIF, buildActualOptions("page, width"), null);
assertSupported(DOC, 1024, GIF, buildActualOptions("page, width, startPage"), null);
}
private void buildPipelineTransformer(InlineTransformer transformer1, InlineTransformer transformer2)
{
transformer = builder.buildPipeLine("transformer1",
Set.of(
new SupportedSourceAndTarget(DOC, GIF, -1),
new SupportedSourceAndTarget(DOC, JPEG, -1),
new SupportedSourceAndTarget(MSG, GIF, -1)),
Arrays.asList(
new ChildTransformer(false, transformer1),
new ChildTransformer(true, transformer2)));
}
}

View File

@@ -23,12 +23,15 @@
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>. * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L% * #L%
*/ */
package org.alfresco.transform.client.model.config; package org.alfresco.transform.client.registry;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import org.alfresco.repo.content.MimetypeMap; import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.content.transform.LocalTransformServiceRegistry; import org.alfresco.repo.content.transform.LocalTransformServiceRegistry;
import org.alfresco.repo.content.transform.TransformerDebug; import org.alfresco.repo.content.transform.TransformerDebug;
import org.alfresco.transform.client.model.config.SupportedSourceAndTarget;
import org.alfresco.transform.client.model.config.TransformOption;
import org.alfresco.transform.client.model.config.Transformer;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.junit.Before; import org.junit.Before;
@@ -43,12 +46,12 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Properties; import java.util.Properties;
import java.util.Set;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
/** /**
* Extends the {@link TransformServiceRegistryConfigTest} (used to test the config received from the Transform Service) * Extends the {@link TransformServiceRegistryConfigTest} (used to test the config received from the Transform Service)
@@ -115,12 +118,7 @@ public class LocalTransformServiceRegistryConfigTest extends TransformServiceReg
} }
} }
protected TestLocalTransformServiceRegistry registry; private static Log log = LogFactory.getLog(LocalTransformServiceRegistry.class);
private Properties properties = new Properties();
@Mock private TransformerDebug transformerDebug;
@Mock private MimetypeMap mimetypeMap;
private static final String LOCAL_TRANSFORM_SERVICE_CONFIG = "alfresco/local-transform-service-config-test.json"; private static final String LOCAL_TRANSFORM_SERVICE_CONFIG = "alfresco/local-transform-service-config-test.json";
private static final String LOCAL_TRANSFORM_SERVICE_CONFIG_PIPELINE = "alfresco/local-transform-service-config-pipeline-test.json"; private static final String LOCAL_TRANSFORM_SERVICE_CONFIG_PIPELINE = "alfresco/local-transform-service-config-pipeline-test.json";
@@ -129,7 +127,15 @@ public class LocalTransformServiceRegistryConfigTest extends TransformServiceReg
private static final String LOCAL_TRANSFORM = "localTransform."; private static final String LOCAL_TRANSFORM = "localTransform.";
private static final String URL = ".url"; private static final String URL = ".url";
private static Log log = LogFactory.getLog(LocalTransformServiceRegistry.class); private Map<String, Set<TransformOption>> mapOfTransformOptions;
private List<CombinedConfig.TransformAndItsOrigin> transformerList;
protected TestLocalTransformServiceRegistry registry;
private Properties properties = new Properties();
@Mock private TransformerDebug transformerDebug;
@Mock private MimetypeMap mimetypeMap;
private Map<String, List<String>> imagemagickSupportedTransformation; private Map<String, List<String>> imagemagickSupportedTransformation;
private Map<String, List<String>> tikaSupportedTransformation; private Map<String, List<String>> tikaSupportedTransformation;
@@ -187,20 +193,14 @@ public class LocalTransformServiceRegistryConfigTest extends TransformServiceReg
} }
/** /**
* Reads and loads localTransforms from LOCAL_TRANSFORM_SERVICE_CONFIG config file. * Loads localTransforms from the LOCAL_TRANSFORM_SERVICE_CONFIG config file.
* @return List<Transformer> list of local transformers.
*/ */
private List<CombinedConfig.TransformAndItsOrigin> retrieveLocalTransformList() private void retrieveLocalTransformList()
{ {
try { CombinedConfig combinedConfig = new CombinedConfig(log);
CombinedConfig combinedConfig = new CombinedConfig(log); combinedConfig.addLocalConfig(LOCAL_TRANSFORM_SERVICE_CONFIG);
combinedConfig.addLocalConfig(LOCAL_TRANSFORM_SERVICE_CONFIG); mapOfTransformOptions = combinedConfig.combinedTransformOptions;
return combinedConfig.getTransforms(); transformerList = combinedConfig.combinedTransformers;
} catch (IOException e) {
log.error("Could not read LocalTransform config file");
fail();
}
return null;
} }
/** /**
@@ -280,11 +280,24 @@ public class LocalTransformServiceRegistryConfigTest extends TransformServiceReg
officeToImageViaPdfSupportedTransformation.put("application/vnd.ms-outlook", targetMimetype); officeToImageViaPdfSupportedTransformation.put("application/vnd.ms-outlook", targetMimetype);
} }
protected String getBaseUrl(InlineTransformer transformer) @Override
protected String getBaseUrl(Transformer transformer)
{ {
return LOCAL_TRANSFORM+transformer.getTransformerName()+".url"; return LOCAL_TRANSFORM+transformer.getTransformerName()+".url";
} }
private int countTopLevelOptions(Set<String> transformOptionNames)
{
int i = 0;
for (String name: transformOptionNames)
{
Set<TransformOption> transformOptions = mapOfTransformOptions.get(name);
i += transformOptions.size();
}
return i;
}
@Test @Test
public void testReadWriteJson() throws IOException public void testReadWriteJson() throws IOException
{ {
@@ -294,7 +307,8 @@ public class LocalTransformServiceRegistryConfigTest extends TransformServiceReg
@Test @Test
public void testReadJsonConfig() public void testReadJsonConfig()
{ {
List<CombinedConfig.TransformAndItsOrigin> transformerList = retrieveLocalTransformList(); retrieveLocalTransformList();
// Assert expected size of the transformers. // Assert expected size of the transformers.
assertNotNull("Transformer list is null.", transformerList); assertNotNull("Transformer list is null.", transformerList);
assertEquals("Unexpected number of transformers retrieved", 5, transformerList.size()); assertEquals("Unexpected number of transformers retrieved", 5, transformerList.size());
@@ -309,18 +323,20 @@ public class LocalTransformServiceRegistryConfigTest extends TransformServiceReg
for (CombinedConfig.TransformAndItsOrigin t : transformerList) for (CombinedConfig.TransformAndItsOrigin t : transformerList)
{ {
assertTrue(t.transform.getTransformerName() + " should be an expected local transformer.", listOfExpectedTransformersName.contains(t.transform.getTransformerName())); assertTrue(t.transformer.getTransformerName() + " should be an expected local transformer.", listOfExpectedTransformersName.contains(t.transformer.getTransformerName()));
listOfExpectedTransformersName.remove(t.transform.getTransformerName()); listOfExpectedTransformersName.remove(t.transformer.getTransformerName());
switch (t.transform.getTransformerName()) switch (t.transformer.getTransformerName())
{ {
case "imagemagick": case "imagemagick":
assertEquals(t.transform.getTransformerName() + " incorrect number of supported transform", 14, t.transform.getSupportedSourceAndTargetList().size()); assertEquals(t.transformer.getTransformerName() + " incorrect number of supported transform", 14, t.transformer.getSupportedSourceAndTargetList().size());
assertEquals( t.transform.getTransformerName() + "incorrect number of transform options", 6, t.transform.getTransformOptions().size()); assertEquals( t.transformer.getTransformerName() + "incorrect number of transform option names", 1, t.transformer.getTransformOptions().size());
assertEquals(t.transform.getTransformerName() + " expected to not be a transformer pipeline", t.transform.getTransformerPipeline().size(), 0); assertEquals( t.transformer.getTransformerName() + "incorrect number of transform options", 6, countTopLevelOptions(t.transformer.getTransformOptions()));
assertEquals(t.transformer.getTransformerName() + " expected to not be a transformer pipeline", t.transformer.getTransformerPipeline().size(), 0);
assertEquals(t.transformer.getTransformerName() + " expected to not be a failover pipeline", t.transformer.getTransformerFailover().size(), 0);
//Test supportedSourceAndTargetList //Test supportedSourceAndTargetList
for ( SupportedSourceAndTarget ssat: t.transform.getSupportedSourceAndTargetList()) for ( SupportedSourceAndTarget ssat: t.transformer.getSupportedSourceAndTargetList())
{ {
assertTrue(ssat.getSourceMediaType() + " not expected to be a supported transform source.", imagemagickSupportedTransformation.containsKey(ssat.getSourceMediaType())); assertTrue(ssat.getSourceMediaType() + " not expected to be a supported transform source.", imagemagickSupportedTransformation.containsKey(ssat.getSourceMediaType()));
assertTrue(ssat.getTargetMediaType() + " not expected to be a supported transform target for " + ssat.getSourceMediaType(), imagemagickSupportedTransformation.get(ssat.getSourceMediaType()).contains(ssat.getTargetMediaType())); assertTrue(ssat.getTargetMediaType() + " not expected to be a supported transform target for " + ssat.getSourceMediaType(), imagemagickSupportedTransformation.get(ssat.getSourceMediaType()).contains(ssat.getTargetMediaType()));
@@ -328,12 +344,14 @@ public class LocalTransformServiceRegistryConfigTest extends TransformServiceReg
break; break;
case "tika": case "tika":
assertEquals(t.transform.getTransformerName() + " incorrect number of supported transform", 8, t.transform.getSupportedSourceAndTargetList().size()); assertEquals(t.transformer.getTransformerName() + " incorrect number of supported transform", 8, t.transformer.getSupportedSourceAndTargetList().size());
assertEquals( t.transform.getTransformerName() + "incorrect number of transform options", 5, t.transform.getTransformOptions().size()); assertEquals( t.transformer.getTransformerName() + "incorrect number of transform option names", 1, t.transformer.getTransformOptions().size());
assertEquals(t.transform.getTransformerName() + " expected to not be a transformer pipeline", t.transform.getTransformerPipeline().size(), 0); assertEquals( t.transformer.getTransformerName() + "incorrect number of transform options", 5, countTopLevelOptions(t.transformer.getTransformOptions()));
assertEquals(t.transformer.getTransformerName() + " expected to not be a transformer pipeline", t.transformer.getTransformerPipeline().size(), 0);
assertEquals(t.transformer.getTransformerName() + " expected to not be a failover pipeline", t.transformer.getTransformerFailover().size(), 0);
//Test supportedSourceAndTargetList //Test supportedSourceAndTargetList
for ( SupportedSourceAndTarget ssat: t.transform.getSupportedSourceAndTargetList()) for ( SupportedSourceAndTarget ssat: t.transformer.getSupportedSourceAndTargetList())
{ {
assertTrue(ssat.getSourceMediaType() + " not expected to be a supported transform source.", tikaSupportedTransformation.containsKey(ssat.getSourceMediaType())); assertTrue(ssat.getSourceMediaType() + " not expected to be a supported transform source.", tikaSupportedTransformation.containsKey(ssat.getSourceMediaType()));
assertTrue(ssat.getTargetMediaType() + " not expected to be a supported transform target for " + ssat.getSourceMediaType(), tikaSupportedTransformation.get(ssat.getSourceMediaType()).contains(ssat.getTargetMediaType())); assertTrue(ssat.getTargetMediaType() + " not expected to be a supported transform target for " + ssat.getSourceMediaType(), tikaSupportedTransformation.get(ssat.getSourceMediaType()).contains(ssat.getTargetMediaType()));
@@ -341,12 +359,14 @@ public class LocalTransformServiceRegistryConfigTest extends TransformServiceReg
break; break;
case "pdfrenderer": case "pdfrenderer":
assertEquals(t.transform.getTransformerName() + " incorrect number of supported transform", 1, t.transform.getSupportedSourceAndTargetList().size()); assertEquals(t.transformer.getTransformerName() + " incorrect number of supported transform", 1, t.transformer.getSupportedSourceAndTargetList().size());
assertEquals( t.transform.getTransformerName() + "incorrect number of transform options", 5, t.transform.getTransformOptions().size()); assertEquals( t.transformer.getTransformerName() + "incorrect number of transform option names", 1, t.transformer.getTransformOptions().size());
assertEquals(t.transform.getTransformerName() + " expected to not be a transformer pipeline", t.transform.getTransformerPipeline().size(), 0); assertEquals( t.transformer.getTransformerName() + "incorrect number of transform options", 5, countTopLevelOptions(t.transformer.getTransformOptions()));
assertEquals(t.transformer.getTransformerName() + " expected to not be a transformer pipeline", t.transformer.getTransformerPipeline().size(), 0);
assertEquals(t.transformer.getTransformerName() + " expected to not be a failover pipeline", t.transformer.getTransformerFailover().size(), 0);
//Test supportedSourceAndTargetList //Test supportedSourceAndTargetList
for ( SupportedSourceAndTarget ssat: t.transform.getSupportedSourceAndTargetList()) for ( SupportedSourceAndTarget ssat: t.transformer.getSupportedSourceAndTargetList())
{ {
assertTrue(ssat.getSourceMediaType() + " not expected to be a supported transform source.", pdfRendererSupportedTransformation.containsKey(ssat.getSourceMediaType())); assertTrue(ssat.getSourceMediaType() + " not expected to be a supported transform source.", pdfRendererSupportedTransformation.containsKey(ssat.getSourceMediaType()));
assertTrue(ssat.getTargetMediaType() + " not expected to be a supported transform target for " + ssat.getSourceMediaType(), pdfRendererSupportedTransformation.get(ssat.getSourceMediaType()).contains(ssat.getTargetMediaType())); assertTrue(ssat.getTargetMediaType() + " not expected to be a supported transform target for " + ssat.getSourceMediaType(), pdfRendererSupportedTransformation.get(ssat.getSourceMediaType()).contains(ssat.getTargetMediaType()));
@@ -354,12 +374,14 @@ public class LocalTransformServiceRegistryConfigTest extends TransformServiceReg
break; break;
case "libreoffice": case "libreoffice":
assertEquals(t.transform.getTransformerName() + " incorrect number of supported transform", 9, t.transform.getSupportedSourceAndTargetList().size()); assertEquals(t.transformer.getTransformerName() + " incorrect number of supported transform", 9, t.transformer.getSupportedSourceAndTargetList().size());
assertEquals( t.transform.getTransformerName() + "incorrect number of transform options", t.transform.getTransformOptions().size(), 0); assertEquals( t.transformer.getTransformerName() + "incorrect number of transform option names", 0, t.transformer.getTransformOptions().size());
assertEquals(t.transform.getTransformerName() + " expected to not be a transformer pipeline", t.transform.getTransformerPipeline().size(), 0); assertEquals( t.transformer.getTransformerName() + "incorrect number of transform options", 0, countTopLevelOptions(t.transformer.getTransformOptions()));
assertEquals(t.transformer.getTransformerName() + " expected to not be a transformer pipeline", t.transformer.getTransformerPipeline().size(), 0);
assertEquals(t.transformer.getTransformerName() + " expected to not be a failover pipeline", t.transformer.getTransformerFailover().size(), 0);
//Test supportedSourceAndTargetList //Test supportedSourceAndTargetList
for ( SupportedSourceAndTarget ssat: t.transform.getSupportedSourceAndTargetList()) for ( SupportedSourceAndTarget ssat: t.transformer.getSupportedSourceAndTargetList())
{ {
assertTrue(ssat.getSourceMediaType() + " not expected to be a supported transform source.", libreofficeSupportedTransformation.containsKey(ssat.getSourceMediaType())); assertTrue(ssat.getSourceMediaType() + " not expected to be a supported transform source.", libreofficeSupportedTransformation.containsKey(ssat.getSourceMediaType()));
assertTrue(ssat.getTargetMediaType() + " not expected to be a supported transform target for " + ssat.getSourceMediaType(), libreofficeSupportedTransformation.get(ssat.getSourceMediaType()).contains(ssat.getTargetMediaType())); assertTrue(ssat.getTargetMediaType() + " not expected to be a supported transform target for " + ssat.getSourceMediaType(), libreofficeSupportedTransformation.get(ssat.getSourceMediaType()).contains(ssat.getTargetMediaType()));
@@ -367,12 +389,13 @@ public class LocalTransformServiceRegistryConfigTest extends TransformServiceReg
break; break;
case "officeToImageViaPdf": case "officeToImageViaPdf":
assertEquals(t.transform.getTransformerName() + " incorrect number of supported transform", 28, t.transform.getSupportedSourceAndTargetList().size()); assertEquals(t.transformer.getTransformerName() + " incorrect number of supported transform", 28, t.transformer.getSupportedSourceAndTargetList().size());
assertEquals( t.transform.getTransformerName() + "incorrect number of transform options", 2, t.transform.getTransformOptions().size()); assertEquals( t.transformer.getTransformerName() + "incorrect number of transform option names", 2, t.transformer.getTransformOptions().size());
assertEquals(t.transform.getTransformerName() + " expected to be a transformer pipeline", t.transform.getTransformerPipeline().size(), 3); assertEquals( t.transformer.getTransformerName() + "incorrect number of transform options", 11, countTopLevelOptions(t.transformer.getTransformOptions()));
assertEquals(t.transformer.getTransformerName() + " expected to be a transformer pipeline", t.transformer.getTransformerPipeline().size(), 3);
//Test supportedSourceAndTargetList //Test supportedSourceAndTargetList
for ( SupportedSourceAndTarget ssat: t.transform.getSupportedSourceAndTargetList()) for ( SupportedSourceAndTarget ssat: t.transformer.getSupportedSourceAndTargetList())
{ {
assertTrue(ssat.getSourceMediaType() + " not expected to be a supported transform source.", officeToImageViaPdfSupportedTransformation.containsKey(ssat.getSourceMediaType())); assertTrue(ssat.getSourceMediaType() + " not expected to be a supported transform source.", officeToImageViaPdfSupportedTransformation.containsKey(ssat.getSourceMediaType()));
assertTrue(ssat.getTargetMediaType() + " not expected to be a supported transform target for " + ssat.getSourceMediaType(), officeToImageViaPdfSupportedTransformation.get(ssat.getSourceMediaType()).contains(ssat.getTargetMediaType())); assertTrue(ssat.getTargetMediaType() + " not expected to be a supported transform target for " + ssat.getSourceMediaType(), officeToImageViaPdfSupportedTransformation.get(ssat.getSourceMediaType()).contains(ssat.getTargetMediaType()));
@@ -386,13 +409,14 @@ public class LocalTransformServiceRegistryConfigTest extends TransformServiceReg
@Test @Test
public void testReadTransformProperties() public void testReadTransformProperties()
{ {
List<CombinedConfig.TransformAndItsOrigin> transformerList = retrieveLocalTransformList(); retrieveLocalTransformList();
assertNotNull("Transformer list is null.", transformerList); assertNotNull("Transformer list is null.", transformerList);
for (CombinedConfig.TransformAndItsOrigin t : transformerList) for (CombinedConfig.TransformAndItsOrigin t : transformerList)
{ {
if(t.transform.getTransformerPipeline() == null) if(t.transformer.getTransformerPipeline() == null)
{ {
assertNotNull(t.transform.getTransformerName()+ " JVM property not set.", System.getProperty(LOCAL_TRANSFORM + t.transform.getTransformerName() + URL)); assertNotNull(t.transformer.getTransformerName()+ " JVM property not set.", System.getProperty(LOCAL_TRANSFORM + t.transformer.getTransformerName() + URL));
} }
} }
assertEquals("Unexpected pdfrenderer JVM property value", "http://localhost:8090/", System.getProperty(LOCAL_TRANSFORM + "pdfrenderer" + URL)); assertEquals("Unexpected pdfrenderer JVM property value", "http://localhost:8090/", System.getProperty(LOCAL_TRANSFORM + "pdfrenderer" + URL));
@@ -402,9 +426,9 @@ public class LocalTransformServiceRegistryConfigTest extends TransformServiceReg
for (CombinedConfig.TransformAndItsOrigin t : transformerList) for (CombinedConfig.TransformAndItsOrigin t : transformerList)
{ {
if(t.transform.getTransformerPipeline() == null) if(t.transformer.getTransformerPipeline() == null)
{ {
assertNotNull(t.transform.getTransformerName()+ " alfresco-global property not set.", properties.getProperty(LOCAL_TRANSFORM + t.transform.getTransformerName() + URL)); assertNotNull(t.transformer.getTransformerName()+ " alfresco-global property not set.", properties.getProperty(LOCAL_TRANSFORM + t.transformer.getTransformerName() + URL));
} }
} }
assertEquals("Unexpected pdfrenderer alfresco-global property value", "http://localhost:8090/", properties.getProperty(LOCAL_TRANSFORM + "pdfrenderer" + URL)); assertEquals("Unexpected pdfrenderer alfresco-global property value", "http://localhost:8090/", properties.getProperty(LOCAL_TRANSFORM + "pdfrenderer" + URL));

View File

@@ -0,0 +1,287 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2019 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 static java.util.Collections.emptyMap;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
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.registry.SupportedTransform;
import org.alfresco.transform.client.registry.TransformRegistryTest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.log4j.Level;
import org.apache.log4j.LogManager;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import com.fasterxml.jackson.databind.ObjectMapper;
/**
* Test the config received from the Transform Service about what it supports.
*
* @author adavis
*/
public class TransformServiceRegistryConfigTest extends TransformRegistryTest
{
private static Log log = LogFactory.getLog(TransformServiceRegistryConfigTest.class);
public static final String PNG = "image/png";
public static final String TIFF = "image/tiff";
private static final String TRANSFORM_SERVICE_CONFIG = "alfresco/transform-service-config-test.json";
private static final String TRANSFORM_SERVICE_CONFIG_PIPELINE = "alfresco/transform-service-config-pipeline-test.json";
public static final ObjectMapper JSON_OBJECT_MAPPER = new ObjectMapper();
@Before
@Override
public void setUp() throws Exception
{
super.setUp();
LogManager.getLogger(TransformServiceRegistryConfigTest.class).setLevel(Level.DEBUG);
}
@Override
protected TransformServiceRegistryImpl buildTransformServiceRegistryImpl() throws Exception
{
TransformServiceRegistryImpl registry = new TransformServiceRegistryImpl()
{
@Override
public boolean readConfig() throws IOException
{
return true;
}
@Override
protected Log getLog()
{
return log;
}
};
registry.setJsonObjectMapper(JSON_OBJECT_MAPPER);
registry.setCronExpression(null); // just read once
registry.afterPropertiesSet();
return registry;
}
@After
public void tearDown()
{
// shut down
}
protected String getTransformServiceConfig()
{
return TRANSFORM_SERVICE_CONFIG;
}
protected String getTransformServiceConfigPipeline()
{
return TRANSFORM_SERVICE_CONFIG_PIPELINE;
}
private void register(String path) throws IOException
{
CombinedConfig combinedConfig = new CombinedConfig(log);
combinedConfig.addLocalConfig(path);
combinedConfig.register((TransformServiceRegistryImpl)registry);
}
@Test
public void testJsonConfig() throws IOException
{
register(getTransformServiceConfig());
// Check the count of transforms supported
assertEquals("The number of UNIQUE source to target mimetypes transforms has changed. Config change?",
60, countSupportedTransforms(true));
assertEquals("The number of source to target mimetypes transforms has changed. " +
"There may be multiple transformers for the same combination. Config change?",
60, countSupportedTransforms(false));
// Check a supported transform for each transformer.
assertSupported(DOC, 1234, PDF, emptyMap(), null, ""); // libreoffice
assertSupported(DOC, 1234, PDF, emptyMap(), null, ""); // libreoffice
assertSupported(PDF, 1234, PNG, emptyMap(), null, ""); // pdfrenderer
assertSupported(JPEG,1234, GIF, emptyMap(), null, ""); // imagemagick
assertSupported(MSG, 1234, TXT, emptyMap(), null, ""); // tika
assertSupported(MSG, 1234, GIF, emptyMap(), null, ""); // officeToImageViaPdf
Map<String, String> invalidPdfOptions = new HashMap<>();
invalidPdfOptions.put("allowEnlargement", "false");
assertSupported(DOC, 1234, PDF, invalidPdfOptions, null, "Invalid as there is a extra option");
}
@Test
public void testJsonPipeline() throws IOException
{
register(getTransformServiceConfigPipeline());
// Check the count of transforms supported
int expectedTransforms = getExpectedTransformsForTestJsonPipeline();
assertEquals("The number of UNIQUE source to target mimetypes transforms has changed. Config change?",
expectedTransforms, countSupportedTransforms(true));
assertEquals("The number of source to target mimetypes transforms has changed. " +
"There may be multiple transformers for the same combination. Config change?",
expectedTransforms, countSupportedTransforms(false));
// Check required and optional default correctly
Map<String, List<SupportedTransform>> transformsToWord =
registry.getData().getTransforms().get(DOC);
List<SupportedTransform> supportedTransforms = transformsToWord.get(GIF);
SupportedTransform supportedTransform = supportedTransforms.get(0);
Set<TransformOption> transformOptionsSet = supportedTransform.getTransformOptions().getTransformOptions();
System.out.println("Nothing");
Iterator<TransformOption> iterator = transformOptionsSet.iterator();
assertTrue("Expected transform values", iterator.hasNext());
// Because Set is unordered we don't know which TransformOptionGroup we retrieve
TransformOptionGroup transformOptions1 = (TransformOptionGroup)iterator.next();
assertTrue("Expected transform values", iterator.hasNext());
TransformOptionGroup transformOptions2 = (TransformOptionGroup)iterator.next();
TransformOptionGroup imagemagick;
TransformOptionGroup pdf;
if(containsTransformOptionValueName(transformOptions1, "alphaRemove"))
{
imagemagick = transformOptions1;
pdf = transformOptions2;
}
else
{
imagemagick = transformOptions2;
pdf = transformOptions1;
}
TransformOptionValue alphaRemove = (TransformOptionValue)retrieveTransformOptionByPropertyName(imagemagick, "alphaRemove", "TransformOptionValue");
TransformOptionGroup crop = (TransformOptionGroup)retrieveTransformOptionByPropertyName(imagemagick, "crop", "TransformOptionGroup");
TransformOptionValue cropGravity = (TransformOptionValue)retrieveTransformOptionByPropertyName(crop, "cropGravity", "TransformOptionValue");
TransformOptionValue cropWidth = (TransformOptionValue)retrieveTransformOptionByPropertyName(crop, "cropWidth", "TransformOptionValue");
assertTrue("The holding group should be required", supportedTransform.getTransformOptions().isRequired());
assertFalse("imagemagick should be optional as it is not set", imagemagick.isRequired());
assertFalse("pdf should be optional as required is not set", pdf.isRequired());
assertEquals("alphaRemove", alphaRemove.getName());
assertEquals("cropGravity", cropGravity.getName());
assertEquals("cropWidth", cropWidth.getName());
assertFalse("alphaRemove should be optional as required is not set", alphaRemove.isRequired());
assertFalse("crop should be optional as required is not set", crop.isRequired());
assertTrue("cropGravity should be required as it is set", cropGravity.isRequired());
assertFalse("cropWidth should be optional as required is not set", cropWidth.isRequired());
// Check a supported transform for each transformer.
assertSupported(DOC,1234, GIF, emptyMap(), null, "");
assertSupported(DOC,1234, PNG, emptyMap(), null, "");
assertSupported(DOC,1234, JPEG, emptyMap(), null, "");
assertSupported(DOC,1234, TIFF, emptyMap(), null, "");
Map<String, String> actualOptions = new HashMap<>();
actualOptions.put("thumbnail", "true");
actualOptions.put("resizeWidth", "100");
actualOptions.put("resizeHeight", "100");
actualOptions.put("allowEnlargement", "false");
actualOptions.put("maintainAspectRatio", "true");
assertSupported(DOC,1234, PNG, actualOptions, null, "");
}
private TransformOption retrieveTransformOptionByPropertyName (TransformOptionGroup transformOptionGroup, String propertyName, String propertyType)
{
Iterator<TransformOption> iterator = transformOptionGroup.getTransformOptions().iterator();
List<TransformOption> transformOptionsList = new ArrayList<>();
while(iterator.hasNext())
{
transformOptionsList.add(iterator.next());
}
for (TransformOption t : transformOptionsList)
{
if (t instanceof TransformOptionValue)
{
TransformOptionValue value = (TransformOptionValue) t;
if (propertyType.equalsIgnoreCase("TransformOptionValue"))
{
if (value.getName().equalsIgnoreCase(propertyName))
return value;
}
else
{
if (value.getName().contains(propertyName))
return transformOptionGroup;
}
}
else
{
TransformOption result = retrieveTransformOptionByPropertyName((TransformOptionGroup)t, propertyName, propertyType);
if (result != null)
return result;
}
}
return null;
}
private boolean containsTransformOptionValueName (TransformOptionGroup transformOptionGroup, String propertyName)
{
return retrieveTransformOptionByPropertyName(transformOptionGroup, propertyName, "TransformOptionValue") != null;
}
protected int getExpectedTransformsForTestJsonPipeline()
{
return 4;
}
private int countSupportedTransforms(boolean unique)
{
int count = 0;
int uniqueCount = 0;
for (Map<String, List<SupportedTransform>> targetMap : registry.getData().getTransforms().values())
{
for (List<SupportedTransform> supportedTransforms : targetMap.values())
{
uniqueCount++;
count += supportedTransforms.size();
}
}
return unique ? uniqueCount : count;
}
}