Allow T-Router to be a T-Engine

This commit is contained in:
alandavis
2022-08-13 18:38:08 +01:00
parent 29fa2086af
commit 13ba2534ea
48 changed files with 1425 additions and 172 deletions

View File

@@ -88,6 +88,6 @@ public class WebApplicationConfig implements WebMvcConfigurer
@Bean @Bean
public TransformerDebug transformerDebug() public TransformerDebug transformerDebug()
{ {
return new TransformerDebug().setIsTEngine(true); return new TransformerDebug().setIsTRouter(false);
} }
} }

View File

@@ -49,7 +49,7 @@ public class AIOTransformEngine implements TransformEngine
@Override @Override
public String getTransformEngineName() public String getTransformEngineName()
{ {
return "0060-AllInOne"; return "0060 AllInOne";
} }
@Override @Override
@@ -77,7 +77,7 @@ public class AIOTransformEngine implements TransformEngine
@Override @Override
public ProbeTransform getProbeTransform() public ProbeTransform getProbeTransform()
{ {
return new ProbeTransform("quick.pdf", MIMETYPE_PDF, MIMETYPE_TEXT_PLAIN, Collections.emptyMap(), return new ProbeTransform("probe.pdf", MIMETYPE_PDF, MIMETYPE_TEXT_PLAIN, Collections.emptyMap(),
60, 16, 400, 10240, 60 * 30 + 1, 60 * 15 + 20); 60, 16, 400, 10240, 60 * 30 + 1, 60 * 15 + 20);
} }
} }

View File

@@ -41,7 +41,7 @@ package org.alfresco.transform.example;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import org.alfresco.transform.base.TransformEngine; import org.alfresco.transform.base.TransformEngine;
import org.alfresco.transform.base.probes.ProbeTransform; import org.alfresco.transform.base.probes.ProbeTransform;
import org.alfresco.transform.common.TransformConfigResourceReader; import org.alfresco.transform.config.reader.TransformConfigResourceReader;
import org.alfresco.transform.config.TransformConfig; import org.alfresco.transform.config.TransformConfig;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;

View File

@@ -66,10 +66,6 @@
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-activemq</artifactId> <artifactId>spring-boot-starter-activemq</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-client</artifactId>
</dependency>
<dependency> <dependency>
<groupId>com.fasterxml.jackson.core</groupId> <groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId> <artifactId>jackson-annotations</artifactId>
@@ -86,7 +82,6 @@
<dependency> <dependency>
<groupId>ch.qos.logback</groupId> <groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId> <artifactId>logback-classic</artifactId>
<version>1.2.6</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.httpcomponents</groupId> <groupId>org.apache.httpcomponents</groupId>

View File

@@ -162,7 +162,7 @@ public class TransformController
@ResponseBody @ResponseBody
public String version() public String version()
{ {
return transformEngine.getTransformEngineName() + ' ' + coreVersion + " available"; return transformEngine.getTransformEngineName() + ' ' + coreVersion;
} }
/** /**
@@ -211,7 +211,7 @@ public class TransformController
String pathPrefix = ""; String pathPrefix = "";
if (behindIngres) if (behindIngres)
{ {
int i = transformEngineName.lastIndexOf('-'); int i = transformEngineName.indexOf(' ');
if (i != -1) if (i != -1)
{ {
transformEngineName = transformEngineName.substring(i + 1); transformEngineName = transformEngineName.substring(i + 1);

View File

@@ -27,7 +27,7 @@
package org.alfresco.transform.base; package org.alfresco.transform.base;
import org.alfresco.transform.base.probes.ProbeTransform; import org.alfresco.transform.base.probes.ProbeTransform;
import org.alfresco.transform.common.TransformConfigResourceReader; import org.alfresco.transform.config.reader.TransformConfigResourceReader;
import org.alfresco.transform.config.TransformConfig; import org.alfresco.transform.config.TransformConfig;
/** /**

View File

@@ -26,14 +26,10 @@
*/ */
package org.alfresco.transform.base.config; package org.alfresco.transform.base.config;
import org.alfresco.transform.base.clients.AlfrescoSharedFileStoreClient;
import org.alfresco.transform.base.html.TransformInterceptor; import org.alfresco.transform.base.html.TransformInterceptor;
import org.alfresco.transform.base.registry.TransformConfigSource; import org.alfresco.transform.base.registry.TransformConfigSource;
import org.alfresco.transform.base.registry.TransformRegistry;
import org.alfresco.transform.common.TransformerDebug; import org.alfresco.transform.common.TransformerDebug;
import org.alfresco.transform.messages.TransformRequestValidator; import org.alfresco.transform.messages.TransformRequestValidator;
import org.alfresco.transform.registry.TransformServiceRegistry;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.ComponentScan;
@@ -58,6 +54,9 @@ public class WebApplicationConfig implements WebMvcConfigurer
@Value("${transform.core.version}") @Value("${transform.core.version}")
private String coreVersionString; private String coreVersionString;
@Value("${container.isTRouter}")
private boolean isTRouter;
@Override @Override
public void addInterceptors(InterceptorRegistry registry) public void addInterceptors(InterceptorRegistry registry)
{ {
@@ -80,7 +79,7 @@ public class WebApplicationConfig implements WebMvcConfigurer
@Bean @Bean
public TransformerDebug transformerDebug() public TransformerDebug transformerDebug()
{ {
return new TransformerDebug().setIsTEngine(true); return new TransformerDebug().setIsTRouter(isTRouter);
} }
@Bean @Bean

View File

@@ -56,8 +56,6 @@ import org.springframework.transaction.PlatformTransactionManager;
@ConditionalOnProperty(name = "activemq.url") @ConditionalOnProperty(name = "activemq.url")
public class MessagingConfig implements JmsListenerConfigurer public class MessagingConfig implements JmsListenerConfigurer
{ {
private static final Logger logger = LoggerFactory.getLogger(MessagingConfig.class);
@Override @Override
public void configureJmsListeners(@NonNull JmsListenerEndpointRegistrar registrar) public void configureJmsListeners(@NonNull JmsListenerEndpointRegistrar registrar)
{ {
@@ -65,7 +63,6 @@ public class MessagingConfig implements JmsListenerConfigurer
} }
@Bean @Bean
@ConditionalOnProperty(name = "activemq.url")
public DefaultMessageHandlerMethodFactory methodFactory() public DefaultMessageHandlerMethodFactory methodFactory()
{ {
DefaultMessageHandlerMethodFactory factory = new DefaultMessageHandlerMethodFactory(); DefaultMessageHandlerMethodFactory factory = new DefaultMessageHandlerMethodFactory();
@@ -74,21 +71,20 @@ public class MessagingConfig implements JmsListenerConfigurer
} }
@Bean @Bean
@ConditionalOnProperty(name = "activemq.url")
public DefaultJmsListenerContainerFactory jmsListenerContainerFactory( public DefaultJmsListenerContainerFactory jmsListenerContainerFactory(
final ConnectionFactory connectionFactory, final ConnectionFactory connectionFactory,
final TransformMessageConverter transformMessageConverter) final TransformMessageConverter transformMessageConverter,
final MessagingErrorHandler messagingErrorHandler)
{ {
final DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory(); final DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
factory.setConnectionFactory(connectionFactory); factory.setConnectionFactory(connectionFactory);
factory.setMessageConverter(transformMessageConverter); factory.setMessageConverter(transformMessageConverter);
factory.setErrorHandler(t -> logger.error("JMS error: " + t.getMessage(), t)); factory.setErrorHandler(messagingErrorHandler);
factory.setTransactionManager(transactionManager(connectionFactory)); factory.setTransactionManager(transactionManager(connectionFactory));
return factory; return factory;
} }
@Bean @Bean
@ConditionalOnProperty(name = "activemq.url")
public PlatformTransactionManager transactionManager(final ConnectionFactory connectionFactory) public PlatformTransactionManager transactionManager(final ConnectionFactory connectionFactory)
{ {
final JmsTransactionManager transactionManager = new JmsTransactionManager(); final JmsTransactionManager transactionManager = new JmsTransactionManager();
@@ -97,7 +93,6 @@ public class MessagingConfig implements JmsListenerConfigurer
} }
@Bean @Bean
@ConditionalOnProperty(name = "activemq.url")
public Queue engineRequestQueue( public Queue engineRequestQueue(
@Value("${queue.engineRequestQueue}") String engineRequestQueueValue) @Value("${queue.engineRequestQueue}") String engineRequestQueueValue)
{ {

View File

@@ -0,0 +1,31 @@
/*
* Copyright 2015-2018 Alfresco Software, Ltd. All rights reserved.
*
* License rights for this program may be obtained from Alfresco Software, Ltd.
* pursuant to a written agreement and any use of this program without such an
* agreement is prohibited.
*/
package org.alfresco.transform.base.messaging;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.util.ErrorHandler;
/**
* Extensible Error Handler for JMS exceptions
*
* @author Cezar Leahu
*/
@Service
public class MessagingErrorHandler implements ErrorHandler
{
private static final Logger logger = LoggerFactory.getLogger(MessagingErrorHandler.class);
@Override
public void handleError(Throwable t)
{
logger.error("JMS error: " + t.getMessage(), t);
}
}

View File

@@ -36,8 +36,7 @@ import org.springframework.jms.core.JmsTemplate;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
/** /**
* Copied from the t-router. We would need to create a common dependency between t-engine base and t-router that * Copied from the t-router.
* knows about jms to remove this duplication.
* *
* @author Cezar Leahu * @author Cezar Leahu
*/ */

View File

@@ -35,15 +35,20 @@ import java.util.List;
import java.util.Map; import java.util.Map;
@Configuration @Configuration
@ConfigurationProperties(prefix = "transform") @ConfigurationProperties(prefix = "transform.config")
public class TransformConfigFiles public class TransformConfigFiles
{ {
// Populated from Spring Boot properties or such as transform.config.<engineName> or environment variables like // Populated from Spring Boot properties or such as transform.config.file.<engineName> or environment variables like
// TRANSFORM_CONFIG_<engineName>. // TRANSFORM_CONFIG_FILE_<engineName>.
private final Map<String, String> config = new HashMap<>(); private final Map<String, String> files = new HashMap<>();
public Map<String, String> getFile()
{
return files;
}
public List<Resource> retrieveResources() public List<Resource> retrieveResources()
{ {
return TransformConfigFromFiles.retrieveResources(config); return TransformConfigFromFiles.retrieveResources(files);
} }
} }

View File

@@ -26,7 +26,7 @@
*/ */
package org.alfresco.transform.base.registry; package org.alfresco.transform.base.registry;
import org.alfresco.transform.common.TransformConfigResourceReader; import org.alfresco.transform.config.reader.TransformConfigResourceReader;
import org.alfresco.transform.config.TransformConfig; import org.alfresco.transform.config.TransformConfig;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.ClassPathResource;

View File

@@ -26,12 +26,18 @@
package org.alfresco.transform.base.registry; package org.alfresco.transform.base.registry;
import org.alfresco.transform.config.TransformConfig; import org.alfresco.transform.config.TransformConfig;
import org.alfresco.transform.config.TransformOption;
import org.alfresco.transform.config.TransformOptionGroup;
import org.alfresco.transform.config.TransformOptionValue;
import org.alfresco.transform.config.Transformer;
import org.alfresco.transform.registry.AbstractTransformRegistry; import org.alfresco.transform.registry.AbstractTransformRegistry;
import org.alfresco.transform.registry.CombinedTransformConfig; import org.alfresco.transform.registry.CombinedTransformConfig;
import org.alfresco.transform.registry.Origin;
import org.alfresco.transform.registry.TransformCache; import org.alfresco.transform.registry.TransformCache;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.EventListener; import org.springframework.context.event.EventListener;
@@ -44,11 +50,22 @@ import org.springframework.stereotype.Service;
import java.util.Comparator; import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.function.Supplier; import java.util.function.Supplier;
import java.util.stream.Stream;
import static java.util.Collections.emptyMap;
import static java.util.Objects.isNull;
import static java.util.stream.Collectors.toUnmodifiableMap;
import static java.util.stream.Collectors.toUnmodifiableSet;
import static org.alfresco.transform.config.CoreVersionDecorator.setCoreVersionOnSingleStepTransformers; import static org.alfresco.transform.config.CoreVersionDecorator.setCoreVersionOnSingleStepTransformers;
import static org.springframework.util.CollectionUtils.isEmpty;
@Service @Service
public class TransformRegistry extends AbstractTransformRegistry public class TransformRegistry extends AbstractTransformRegistry
@@ -59,30 +76,53 @@ public class TransformRegistry extends AbstractTransformRegistry
private String coreVersion; private String coreVersion;
@Autowired @Autowired
private List<TransformConfigSource> transformConfigSources; private List<TransformConfigSource> transformConfigSources;
@Value("${container.isTRouter}")
private boolean isTRouter;
private static class Data extends TransformCache private static class Data extends TransformCache
{ {
private TransformConfig transformConfigBeforeIncompleteTransformsAreRemoved; private TransformConfig transformConfig;
private TransformConfig uncombinedTransformConfig;
private Map<String,Origin<Transformer>> transformerByNameMap;
public TransformConfig getTransformConfigBeforeIncompleteTransformsAreRemoved() public TransformConfig getTransformConfig()
{ {
return transformConfigBeforeIncompleteTransformsAreRemoved; return transformConfig;
} }
public void setTransformConfigBeforeIncompleteTransformsAreRemoved( public void setTransformConfig(TransformConfig transformConfig)
TransformConfig transformConfigBeforeIncompleteTransformsAreRemoved)
{ {
this.transformConfigBeforeIncompleteTransformsAreRemoved = transformConfigBeforeIncompleteTransformsAreRemoved; this.transformConfig = transformConfig;
}
public TransformConfig getUncombinedTransformConfig()
{
return uncombinedTransformConfig;
}
public void setUncombinedTransformConfig(TransformConfig uncombinedTransformConfig)
{
this.uncombinedTransformConfig = uncombinedTransformConfig;
}
public Map<String, Origin<Transformer>> getTransformerByNameMap()
{
return transformerByNameMap;
}
public void setTransformerByNameMap(Map<String, Origin<Transformer>> transformerByNameMap)
{
this.transformerByNameMap = transformerByNameMap;
} }
} }
private Data data = new Data(); private Data data = new Data();
// Ensures that read operations are blocked while config is being updated // Ensures that read operations are blocked while config is being updated
private ReadWriteLock configRefreshLock = new ReentrantReadWriteLock(); private final ReadWriteLock configRefreshLock = new ReentrantReadWriteLock();
@EventListener(ContextRefreshedEvent.class) @EventListener(ContextRefreshedEvent.class)
void handleContextRefreshedEvent(final ContextRefreshedEvent event) public void handleContextRefreshedEvent(final ContextRefreshedEvent event)
{ {
final ApplicationContext context = event.getApplicationContext(); final ApplicationContext context = event.getApplicationContext();
// the local "initEngineConfigs" method has to be called through the Spring proxy // the local "initEngineConfigs" method has to be called through the Spring proxy
@@ -135,14 +175,27 @@ public class TransformRegistry extends AbstractTransformRegistry
this); this);
}); });
TransformConfig transformConfigBeforeIncompleteTransformsAreRemoved = combinedTransformConfig.buildTransformConfig(); TransformConfig uncombinedTransformConfig = combinedTransformConfig.buildTransformConfig();
combinedTransformConfig.combineTransformerConfig(this); combinedTransformConfig.combineTransformerConfig(this);
concurrentUpdate(combinedTransformConfig, transformConfigBeforeIncompleteTransformsAreRemoved); TransformConfig transformConfig = combinedTransformConfig.buildTransformConfig();
Map<String, Origin<Transformer>> transformerByNameMap = combinedTransformConfig.getTransformerByNameMap();
concurrentUpdate(combinedTransformConfig, uncombinedTransformConfig, transformConfig, transformerByNameMap);
} }
public TransformConfig getTransformConfig() public TransformConfig getTransformConfig()
{ {
return getData().getTransformConfigBeforeIncompleteTransformsAreRemoved(); Data data = getData();
return isTRouter
? data.getTransformConfig()
: data.getUncombinedTransformConfig();
}
/**
* @return Returns true if transform information has been loaded.
*/
public boolean isReadyForTransformRequests()
{
return getData().getTransforms().size() > 0;
} }
@Override @Override
@@ -155,13 +208,16 @@ public class TransformRegistry extends AbstractTransformRegistry
* Lock for reads while updating, use {@link #concurrentRead} to access locked fields * Lock for reads while updating, use {@link #concurrentRead} to access locked fields
*/ */
private void concurrentUpdate(CombinedTransformConfig combinedTransformConfig, private void concurrentUpdate(CombinedTransformConfig combinedTransformConfig,
TransformConfig transformConfigBeforeIncompleteTransformsAreRemoved) TransformConfig uncombinedTransformConfig, TransformConfig transformConfig,
Map<String, Origin<Transformer>> transformerByNameMap)
{ {
configRefreshLock.writeLock().lock(); configRefreshLock.writeLock().lock();
try try
{ {
data = new Data(); // clear data data = new Data(); // clear data
data.setTransformConfigBeforeIncompleteTransformsAreRemoved(transformConfigBeforeIncompleteTransformsAreRemoved); data.setTransformConfig(transformConfig);
data.setUncombinedTransformConfig(uncombinedTransformConfig);
data.setTransformerByNameMap(transformerByNameMap);
combinedTransformConfig.registerCombinedTransformers(this); combinedTransformConfig.registerCombinedTransformers(this);
} }
finally finally
@@ -195,4 +251,86 @@ public class TransformRegistry extends AbstractTransformRegistry
{ {
logger.warn(msg); logger.warn(msg);
} }
public Transformer getTransformer(final String sourceMediaType, final Long fileSizeBytes,
final String targetMediaType, final Map<String, String> transformOptions)
{
return concurrentRead(() ->
{
long fileSize = fileSizeBytes == null ? 0 : fileSizeBytes;
String transformerName = findTransformerName(sourceMediaType, fileSize, targetMediaType, transformOptions, null);
return getTransformer(transformerName);
});
}
public Transformer getTransformer(String transformerName)
{
return getTransformer(getData(), transformerName);
}
private Transformer getTransformer(Data data, String transformerName)
{
return data.getTransformerByNameMap().get(transformerName).get();
}
public boolean checkSourceSize(String transformerName, String sourceMediaType, Long sourceSize, String targetMediaType)
{
return Optional.ofNullable(getTransformer(transformerName)).
map(transformer -> transformer.getSupportedSourceAndTargetList().stream().
filter(supported -> supported.getSourceMediaType().equals(sourceMediaType) &&
supported.getTargetMediaType().equals(targetMediaType)).
findFirst().
map(supported -> supported.getMaxSourceSizeBytes() == -1 ||
supported.getMaxSourceSizeBytes() >= sourceSize).
orElse(false)).
orElse(false);
}
public String getEngineName(String transformerName)
{
return getData().getTransformerByNameMap().get(transformerName).getReadFrom();
}
/**
* Filters the transform options for a given transformer. In a pipeline there may be options for different steps.
*/
public Map<String, String> filterOptions(final String transformerName, final Map<String, String> options)
{
Data data = getData();
final Map<String, Set<TransformOption>> configOptions = data.getTransformConfig().getTransformOptions();
final Transformer transformer = getTransformer(data, transformerName);
if (isNull(transformer) || isEmpty(options) || isEmpty(configOptions))
{
return emptyMap();
}
final Set<String> knownOptions = transformer.getTransformOptions()
.stream()
.flatMap(name -> configOptions.get(name).stream())
.filter(Objects::nonNull)
.flatMap(TransformRegistry::retrieveOptionsStrings)
.collect(toUnmodifiableSet());
if (isEmpty(knownOptions))
{
return emptyMap();
}
return options
.entrySet()
.stream()
.filter(e -> knownOptions.contains(e.getKey()))
.collect(toUnmodifiableMap(Entry::getKey, Entry::getValue));
}
private static Stream<String> retrieveOptionsStrings(final TransformOption option)
{
if (option instanceof TransformOptionGroup)
{
return ((TransformOptionGroup) option)
.getTransformOptions()
.stream()
.flatMap(TransformRegistry::retrieveOptionsStrings);
}
return Stream.of(((TransformOptionValue) option).getName());
}
} }

View File

@@ -184,31 +184,17 @@ abstract class ProcessHandler extends FragmentHandler
private String getTransformerName(final String sourceMimetype, long sourceSizeInBytes, final String targetMimetype, private String getTransformerName(final String sourceMimetype, long sourceSizeInBytes, final String targetMimetype,
final Map<String, String> transformOptions) final Map<String, String> transformOptions)
{ {
// The transformOptions always contains sourceEncoding when sent to a T-Engine, even though it should not be final String transformerName = transformRegistry.findTransformerName(sourceMimetype,
// used to select a transformer. Similar to source and target mimetypes and extensions, but these are not sourceSizeInBytes, targetMimetype, transformOptions, null);
// passed in transformOptions. if (transformerName == null)
String sourceEncoding = transformOptions.remove(SOURCE_ENCODING);
try
{ {
final String transformerName = transformRegistry.findTransformerName(sourceMimetype, throw new TransformException(BAD_REQUEST, "No transforms for: "+
sourceSizeInBytes, targetMimetype, transformOptions, null); sourceMimetype+" -> "+targetMimetype+transformOptions.entrySet().stream()
if (transformerName == null) .map(entry -> entry.getKey()+"="+entry.getValue())
{ .collect(Collectors.joining(", ", " ", "")));
throw new TransformException(BAD_REQUEST, "No transforms for: "+
sourceMimetype+" -> "+targetMimetype+transformOptions.entrySet().stream()
.map(entry -> entry.getKey()+"="+entry.getValue())
.collect(Collectors.joining(", ", " ", "")));
}
return transformerName;
} }
finally return transformerName;
{ }
if (sourceEncoding != null)
{
transformOptions.put(SOURCE_ENCODING, sourceEncoding);
}
}
}
private CustomTransformer getCustomTransformer(String transformName) private CustomTransformer getCustomTransformer(String transformName)
{ {

View File

@@ -22,6 +22,15 @@ server:
error: error:
include-message: ALWAYS include-message: ALWAYS
# Historic values (AVOID) - Exist to help with transition to newer versions
transformer-routes-path: ${TRANSFORMER_ROUTES_FILE_LOCATION:transformer-pipelines.json}
logging:
level:
org.alfresco.transform.common.TransformerDebug: debug
fileStoreUrl: ${FILE_STORE_URL:http://localhost:8099/alfresco/api/-default-/private/sfs/versions/1/file}
transform: transform:
core: core:
version: @project.version@ version: @project.version@
@@ -32,17 +41,6 @@ transform:
attempts: 10 attempts: 10
timeout: 10 # seconds timeout: 10 # seconds
# Historic values (AVOID) - Exist to help with transition to newer versions
transformer-routes-path: ${TRANSFORMER_ROUTES_FILE_LOCATION:transformer-pipelines.json}
logging:
level:
# org.alfresco.util.exec.RuntimeExec: debug
# org.alfresco.transform.base.metadataExtractors: debug
org.alfresco.transform.common.TransformerDebug: debug
fileStoreUrl: ${FILE_STORE_URL:http://localhost:8099/alfresco/api/-default-/private/sfs/versions/1/file}
jms-listener: jms-listener:
concurrency: ${JMS_LISTENER_CONCURRENCY:1-10} concurrency: ${JMS_LISTENER_CONCURRENCY:1-10}
@@ -62,12 +60,5 @@ management:
container: container:
name: ${HOSTNAME:t-engine} name: ${HOSTNAME:t-engine}
isTRouter: false
behind-ingres: false behind-ingres: false
async-task-executor:
core-pool-size: 1
max-pool-size: 2147483647
keep-alive-seconds: 60
queue-capacity: 2147483647
allow-core-thread-time-out: false
prestart-all-core-threads: false

View File

@@ -124,7 +124,7 @@ public class TransformControllerAllInOneTest
{ {
mockMvc.perform(MockMvcRequestBuilders.get(ENDPOINT_VERSION)) mockMvc.perform(MockMvcRequestBuilders.get(ENDPOINT_VERSION))
.andExpect(status().isOk()) .andExpect(status().isOk())
.andExpect(content().string("AllInOne "+coreVersion+" available")); .andExpect(content().string("AllInOne "+coreVersion));
} }
@Test @Test

View File

@@ -206,7 +206,7 @@ public class TransformControllerTest
{ {
mockMvc.perform(MockMvcRequestBuilders.get(ENDPOINT_VERSION)) mockMvc.perform(MockMvcRequestBuilders.get(ENDPOINT_VERSION))
.andExpect(status().isOk()) .andExpect(status().isOk())
.andExpect(content().string("TwoCustomTransformers "+coreVersion+" available")); .andExpect(content().string("TwoCustomTransformers "+coreVersion));
} }
@Test @Test

View File

@@ -47,7 +47,7 @@ public class TransformRegistryRefreshTest
verify(transformRegistry, atLeast(1)).retrieveConfig(); verify(transformRegistry, atLeast(1)).retrieveConfig();
// As we can't change the content of a classpath resource, lets change what is read. // As we can't change the content of a classpath resource, lets change what is read.
ReflectionTestUtils.setField(transformConfigFiles, "config", ImmutableMap.of( ReflectionTestUtils.setField(transformConfigFiles, "files", ImmutableMap.of(
"a", "config/addA2B.json", "a", "config/addA2B.json",
"foo", "config/addB2C.json")); "foo", "config/addB2C.json"));
transformConfigFromFiles.initFileConfig(); transformConfigFromFiles.initFileConfig();

View File

@@ -45,6 +45,8 @@ import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
@AutoConfigureMockMvc @AutoConfigureMockMvc
@SpringBootTest(classes={org.alfresco.transform.base.Application.class}) @SpringBootTest(classes={org.alfresco.transform.base.Application.class})
@@ -68,8 +70,9 @@ public class TransformRegistryTest
{ {
transformConfigSources.clear(); transformConfigSources.clear();
ReflectionTestUtils.setField(transformConfigFromTransformEngines, "transformEngines", Collections.emptyList()); ReflectionTestUtils.setField(transformConfigFromTransformEngines, "transformEngines", Collections.emptyList());
ReflectionTestUtils.setField(transformConfigFiles, "config", Collections.emptyMap()); ReflectionTestUtils.setField(transformConfigFiles, "files", Collections.emptyMap());
ReflectionTestUtils.setField(transformConfigFilesHistoric, "additional", Collections.emptyMap()); ReflectionTestUtils.setField(transformConfigFilesHistoric, "additional", Collections.emptyMap());
ReflectionTestUtils.setField(transformRegistry, "isTRouter", false);
transformRegistry.retrieveConfig(); transformRegistry.retrieveConfig();
} }
@@ -112,12 +115,46 @@ public class TransformRegistryTest
getTransformerNames(transformRegistry.getTransformConfig())); getTransformerNames(transformRegistry.getTransformConfig()));
} }
@Test
public void uncombinedConfigFromEngine()
{
ReflectionTestUtils.setField(transformConfigFromTransformEngines, "transformEngines", ImmutableList.of(
new FakeTransformEngineWithAllInOne(),
new FakeTransformEngineWithTwoCustomTransformers()));
transformConfigFromTransformEngines.initTransformEngineConfig();
transformRegistry.retrieveConfig();
assertEquals("Pdf2Png, TxT2Pdf, Txt2JpgViaPdf, Txt2PngViaPdf",
getTransformerNames(transformRegistry.getTransformConfig()));
ReflectionTestUtils.setField(transformRegistry, "isTRouter", true);
transformConfigFromTransformEngines.initTransformEngineConfig();
transformRegistry.retrieveConfig();
assertEquals("Pdf2Png, TxT2Pdf, Txt2PngViaPdf",
getTransformerNames(transformRegistry.getTransformConfig()));
}
@Test
public void combinedConfigFromRouter()
{
ReflectionTestUtils.setField(transformRegistry, "isTRouter", true);
ReflectionTestUtils.setField(transformConfigFromTransformEngines, "transformEngines", ImmutableList.of(
new FakeTransformEngineWithAllInOne(),
new FakeTransformEngineWithTwoCustomTransformers()));
transformConfigFromTransformEngines.initTransformEngineConfig();
transformRegistry.retrieveConfig();
assertEquals("Pdf2Png, TxT2Pdf, Txt2PngViaPdf",
getTransformerNames(transformRegistry.getTransformConfig()));
}
@Test @Test
public void singleTransformEngineWithAdditionalConfig() public void singleTransformEngineWithAdditionalConfig()
{ {
ReflectionTestUtils.setField(transformConfigFromTransformEngines, "transformEngines", ImmutableList.of( ReflectionTestUtils.setField(transformConfigFromTransformEngines, "transformEngines", ImmutableList.of(
new FakeTransformEngineWithOneCustomTransformer())); new FakeTransformEngineWithOneCustomTransformer()));
ReflectionTestUtils.setField(transformConfigFiles, "config", ImmutableMap.of( ReflectionTestUtils.setField(transformConfigFiles, "files", ImmutableMap.of(
"a", "config/addA2B.json", "a", "config/addA2B.json",
"foo", "config/addB2C.json")); "foo", "config/addB2C.json"));
@@ -175,4 +212,19 @@ public class TransformRegistryTest
assertEquals("A2Z", getTransformerNames(transformRegistry.getTransformConfig())); assertEquals("A2Z", getTransformerNames(transformRegistry.getTransformConfig()));
} }
@Test
public void isReadyForTransformRequests()
{
transformConfigFromTransformEngines.initTransformEngineConfig();
transformRegistry.retrieveConfig();
assertFalse(transformRegistry.isReadyForTransformRequests());
ReflectionTestUtils.setField(transformConfigFromTransformEngines, "transformEngines", ImmutableList.of(
new FakeTransformEngineWithOneCustomTransformer()));
transformConfigFromTransformEngines.initTransformEngineConfig();
transformRegistry.retrieveConfig();
assertTrue(transformRegistry.isReadyForTransformRequests());
}
} }

View File

@@ -29,7 +29,7 @@ package org.alfresco.transform.example;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import org.alfresco.transform.base.TransformEngine; import org.alfresco.transform.base.TransformEngine;
import org.alfresco.transform.base.probes.ProbeTransform; import org.alfresco.transform.base.probes.ProbeTransform;
import org.alfresco.transform.common.TransformConfigResourceReader; import org.alfresco.transform.config.reader.TransformConfigResourceReader;
import org.alfresco.transform.config.TransformConfig; import org.alfresco.transform.config.TransformConfig;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -43,7 +43,7 @@ public class HelloTransformEngine implements TransformEngine
@Override @Override
public String getTransformEngineName() public String getTransformEngineName()
{ {
return "0200_hello"; return "0200 Hello";
} }
@Override @Override

View File

@@ -28,7 +28,7 @@ package org.alfresco.transform.imagemagick;
import org.alfresco.transform.base.TransformEngine; import org.alfresco.transform.base.TransformEngine;
import org.alfresco.transform.base.probes.ProbeTransform; import org.alfresco.transform.base.probes.ProbeTransform;
import org.alfresco.transform.common.TransformConfigResourceReader; import org.alfresco.transform.config.reader.TransformConfigResourceReader;
import org.alfresco.transform.config.TransformConfig; import org.alfresco.transform.config.TransformConfig;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -48,7 +48,7 @@ public class ImageMagickTransformEngine implements TransformEngine
@Override @Override
public String getTransformEngineName() public String getTransformEngineName()
{ {
return "0030-ImageMagick"; return "0030 ImageMagick";
} }
@Override @Override

View File

@@ -28,7 +28,7 @@ package org.alfresco.transform.libreoffice;
import org.alfresco.transform.base.TransformEngine; import org.alfresco.transform.base.TransformEngine;
import org.alfresco.transform.base.probes.ProbeTransform; import org.alfresco.transform.base.probes.ProbeTransform;
import org.alfresco.transform.common.TransformConfigResourceReader; import org.alfresco.transform.config.reader.TransformConfigResourceReader;
import org.alfresco.transform.config.TransformConfig; import org.alfresco.transform.config.TransformConfig;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -48,7 +48,7 @@ public class LibreOfficeTransformEngine implements TransformEngine
@Override @Override
public String getTransformEngineName() public String getTransformEngineName()
{ {
return "0020-LibreOffice"; return "0020 LibreOffice";
} }
@Override @Override

View File

@@ -12,8 +12,8 @@
</parent> </parent>
<properties> <properties>
<image.name>alfresco/alfresco-transform-misc</image.name>
<image.registry>quay.io</image.registry> <image.registry>quay.io</image.registry>
<image.name>alfresco/alfresco-transform-misc</image.name>
<env.project_artifactId>${project.artifactId}</env.project_artifactId> <env.project_artifactId>${project.artifactId}</env.project_artifactId>
</properties> </properties>

View File

@@ -29,7 +29,7 @@ package org.alfresco.transform.misc;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import org.alfresco.transform.base.TransformEngine; import org.alfresco.transform.base.TransformEngine;
import org.alfresco.transform.base.probes.ProbeTransform; import org.alfresco.transform.base.probes.ProbeTransform;
import org.alfresco.transform.common.TransformConfigResourceReader; import org.alfresco.transform.config.reader.TransformConfigResourceReader;
import org.alfresco.transform.config.TransformConfig; import org.alfresco.transform.config.TransformConfig;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -52,7 +52,7 @@ public class MiscTransformEngine implements TransformEngine
@Override @Override
public String getTransformEngineName() public String getTransformEngineName()
{ {
return "0050-Misc"; return "0050 Misc";
} }
@Override @Override

View File

@@ -28,7 +28,7 @@ package org.alfresco.transform.pdfrenderer;
import org.alfresco.transform.base.TransformEngine; import org.alfresco.transform.base.TransformEngine;
import org.alfresco.transform.base.probes.ProbeTransform; import org.alfresco.transform.base.probes.ProbeTransform;
import org.alfresco.transform.common.TransformConfigResourceReader; import org.alfresco.transform.config.reader.TransformConfigResourceReader;
import org.alfresco.transform.config.TransformConfig; import org.alfresco.transform.config.TransformConfig;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -48,7 +48,7 @@ public class PdfRendererTransformEngine implements TransformEngine
@Override @Override
public String getTransformEngineName() public String getTransformEngineName()
{ {
return "0040-PdfRenderer"; return "0040 PdfRenderer";
} }
@Override @Override

View File

@@ -28,7 +28,7 @@ package org.alfresco.transform.tika;
import org.alfresco.transform.base.TransformEngine; import org.alfresco.transform.base.TransformEngine;
import org.alfresco.transform.base.probes.ProbeTransform; import org.alfresco.transform.base.probes.ProbeTransform;
import org.alfresco.transform.common.TransformConfigResourceReader; import org.alfresco.transform.config.reader.TransformConfigResourceReader;
import org.alfresco.transform.config.TransformConfig; import org.alfresco.transform.config.TransformConfig;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -48,7 +48,7 @@ public class TikaTransformEngine implements TransformEngine
@Override @Override
public String getTransformEngineName() public String getTransformEngineName()
{ {
return "0010-Tika"; return "0010 Tika";
} }
@Override @Override

View File

@@ -37,6 +37,10 @@
<artifactId>jackson-annotations</artifactId> <artifactId>jackson-annotations</artifactId>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-yaml</artifactId>
</dependency>
<dependency> <dependency>
<groupId>junit</groupId> <groupId>junit</groupId>
<artifactId>junit</artifactId> <artifactId>junit</artifactId>

View File

@@ -50,7 +50,7 @@ public class TransformerDebug
private static int MAX_OPTION_END_CHARS = 5; private static int MAX_OPTION_END_CHARS = 5;
private static String MAX_OPTION_DOTS = "..."; private static String MAX_OPTION_DOTS = "...";
private boolean isTEngine = false; private boolean isTRouter = false;
public void pushTransform(TransformRequest request) public void pushTransform(TransformRequest request)
{ {
@@ -64,7 +64,7 @@ public class TransformerDebug
String message = getPaddedReference(reference) + String message = getPaddedReference(reference) +
getMimetypeExt(step.getSourceMediaType()) + getMimetypeExt(step.getSourceMediaType()) +
getTargetMimetypeExt(step.getTargetMediaType(), step.getSourceMediaType()) + ' ' + getTargetMimetypeExt(step.getTargetMediaType(), step.getSourceMediaType()) + ' ' +
(isTopLevel || isTEngine() (isTopLevel || !isTRouter()
? fileSize(request.getSourceSize()) + ' ' + ? fileSize(request.getSourceSize()) + ' ' +
getRenditionName(new RepositoryClientData(request.getClientData()).getRenditionName()) getRenditionName(new RepositoryClientData(request.getClientData()).getRenditionName())
: "") + : "") +
@@ -117,7 +117,7 @@ public class TransformerDebug
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
{ {
String message = getPaddedReference(reference) + "Finished in " + ms(elapsedTime); String message = getPaddedReference(reference) + "Finished in " + ms(elapsedTime);
if (isTopLevel(reference) || isTEngine()) if (isTopLevel(reference) || !isTRouter())
{ {
logger.debug(message); logger.debug(message);
} }
@@ -221,9 +221,9 @@ public class TransformerDebug
} }
// T-Engines call this method, as the T-Router will appended the same debug messages // T-Engines call this method, as the T-Router will appended the same debug messages
public TransformerDebug setIsTEngine(boolean isTEngine) public TransformerDebug setIsTRouter(boolean isTRouter)
{ {
this.isTEngine = isTEngine; this.isTRouter = isTRouter;
return this; return this;
} }
@@ -234,12 +234,12 @@ public class TransformerDebug
private boolean isDebugToBeReturned(RepositoryClientData repositoryClientData) private boolean isDebugToBeReturned(RepositoryClientData repositoryClientData)
{ {
return !isTEngine() && repositoryClientData.isDebugRequested(); return isTRouter() && repositoryClientData.isDebugRequested();
} }
private boolean isTEngine() private boolean isTRouter()
{ {
return isTEngine; return isTRouter;
} }
private boolean isTopLevel(String reference) private boolean isTopLevel(String reference)

View File

@@ -56,7 +56,32 @@ public class TransformConfig
public void setTransformOptions(Map<String, Set<TransformOption>> transformOptions) public void setTransformOptions(Map<String, Set<TransformOption>> transformOptions)
{ {
this.transformOptions = new HashMap<>(transformOptions); this.transformOptions = transformOptions == null ? new HashMap<>() : new HashMap<>(transformOptions);
}
public void setRemoveTransformers(Set<String> removeTransformers)
{
this.removeTransformers = removeTransformers == null ? new HashSet<>() : removeTransformers;
}
public void setAddSupported(Set<AddSupported> addSupported)
{
this.addSupported = addSupported == null ? new HashSet<>() : addSupported;
}
public void setRemoveSupported(Set<RemoveSupported> removeSupported)
{
this.removeSupported = removeSupported == null ? new HashSet<>() : removeSupported;
}
public void setOverrideSupported(Set<OverrideSupported> overrideSupported)
{
this.overrideSupported = overrideSupported == null ? new HashSet<>() : overrideSupported;
}
public void setSupportedDefaults(Set<SupportedDefaults> supportedDefaults)
{
this.supportedDefaults = supportedDefaults == null ? new HashSet<>() : supportedDefaults;
} }
public List<Transformer> getTransformers() public List<Transformer> getTransformers()
@@ -91,7 +116,7 @@ public class TransformConfig
public void setTransformers(List<Transformer> transformers) public void setTransformers(List<Transformer> transformers)
{ {
this.transformers = transformers; this.transformers = transformers == null ? new ArrayList<>() : transformers;
} }
@Override @Override

View File

@@ -53,7 +53,7 @@ public class TransformOptionGroup extends AbstractTransformOption
public void setTransformOptions(Set<TransformOption> transformOptions) public void setTransformOptions(Set<TransformOption> transformOptions)
{ {
this.transformOptions = transformOptions; this.transformOptions = transformOptions == null ? new HashSet<>() : transformOptions;
} }
@Override @Override

View File

@@ -119,7 +119,7 @@ public class Transformer
public void setTransformerPipeline(List<TransformStep> transformerPipeline) public void setTransformerPipeline(List<TransformStep> transformerPipeline)
{ {
this.transformerPipeline = transformerPipeline; this.transformerPipeline = transformerPipeline == null ? new ArrayList<>() : transformerPipeline;
} }
public List<String> getTransformerFailover() public List<String> getTransformerFailover()
@@ -129,7 +129,7 @@ public class Transformer
public void setTransformerFailover(List<String> transformerFailover) public void setTransformerFailover(List<String> transformerFailover)
{ {
this.transformerFailover = transformerFailover; this.transformerFailover = transformerFailover == null ? new ArrayList<>() : transformerFailover;
} }
public Set<String> getTransformOptions() public Set<String> getTransformOptions()
@@ -139,7 +139,7 @@ public class Transformer
public void setTransformOptions(Set<String> transformOptions) public void setTransformOptions(Set<String> transformOptions)
{ {
this.transformOptions = transformOptions; this.transformOptions = transformOptions == null ? new HashSet<>() : transformOptions;
} }
public Set<SupportedSourceAndTarget> getSupportedSourceAndTargetList() public Set<SupportedSourceAndTarget> getSupportedSourceAndTargetList()
@@ -150,7 +150,7 @@ public class Transformer
public void setSupportedSourceAndTargetList( public void setSupportedSourceAndTargetList(
Set<SupportedSourceAndTarget> supportedSourceAndTargetList) Set<SupportedSourceAndTarget> supportedSourceAndTargetList)
{ {
this.supportedSourceAndTargetList = supportedSourceAndTargetList; this.supportedSourceAndTargetList = supportedSourceAndTargetList == null ? new HashSet<>() : supportedSourceAndTargetList;
} }
@Override @Override

View File

@@ -0,0 +1,31 @@
/*
* #%L
* Alfresco Transform Model
* %%
* Copyright (C) 2015 - 2022 Alfresco Software Limited
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
* #L%
*/
package org.alfresco.transform.config.reader;
import org.alfresco.transform.config.TransformConfig;
import java.io.IOException;
public interface TransformConfigReader
{
TransformConfig load() throws IOException;
}

View File

@@ -0,0 +1,53 @@
/*
* #%L
* Alfresco Transform Model
* %%
* Copyright (C) 2015 - 2022 Alfresco Software Limited
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
* #L%
*/
package org.alfresco.transform.config.reader;
import static java.util.Objects.isNull;
import org.springframework.core.io.Resource;
public class TransformConfigReaderFactory
{
public static TransformConfigReader create(final Resource resource)
{
final String fileName = resource.getFilename();
if (isNull(fileName) || !fileName.contains("."))
{
throw new RuntimeException("Invalid configuration file: " + fileName);
}
final String extension = fileName.substring(fileName.lastIndexOf('.') + 1);
switch (extension)
{
case "properties":
throw new UnsupportedOperationException(".properties configuration files are no longer " +
"supported: " + fileName);
case "yaml":
case "yml":
return new TransformConfigReaderYaml(resource);
case "json":
return new TransformConfigReaderJson(resource);
default:
throw new RuntimeException("Unknown configuration file type: " + fileName);
}
}
}

View File

@@ -0,0 +1,47 @@
/*
* #%L
* Alfresco Transform Model
* %%
* Copyright (C) 2015 - 2022 Alfresco Software Limited
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
* #L%
*/
package org.alfresco.transform.config.reader;
import java.io.IOException;
import org.alfresco.transform.config.TransformConfig;
import org.springframework.core.io.Resource;
import com.fasterxml.jackson.databind.ObjectMapper;
public class TransformConfigReaderJson implements TransformConfigReader
{
private static final ObjectMapper MAPPER= new ObjectMapper();
private final Resource resource;
TransformConfigReaderJson(final Resource resource)
{
this.resource = resource;
}
@Override
public TransformConfig load() throws IOException
{
return MAPPER.readValue(resource.getInputStream(), TransformConfig.class);
}
}

View File

@@ -0,0 +1,48 @@
/*
* #%L
* Alfresco Transform Model
* %%
* Copyright (C) 2015 - 2022 Alfresco Software Limited
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
* #L%
*/
package org.alfresco.transform.config.reader;
import java.io.IOException;
import org.alfresco.transform.config.TransformConfig;
import org.springframework.core.io.Resource;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
public class TransformConfigReaderYaml implements TransformConfigReader
{
private static final ObjectMapper MAPPER = new ObjectMapper(new YAMLFactory());
private final Resource resource;
TransformConfigReaderYaml(final Resource resource)
{
this.resource = resource;
}
@Override
public TransformConfig load() throws IOException
{
return MAPPER.readValue(resource.getInputStream(), TransformConfig.class);
}
}

View File

@@ -2,7 +2,7 @@
* #%L * #%L
* Alfresco Transform Core * Alfresco Transform Core
* %% * %%
* Copyright (C) 2005 - 2022 Alfresco Software Limited * Copyright (C) 2022 - 2022 Alfresco Software Limited
* %% * %%
* This file is part of the Alfresco software. * This file is part of the Alfresco software.
* - * -
@@ -24,9 +24,9 @@
* 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.common; package org.alfresco.transform.config.reader;
import com.fasterxml.jackson.databind.ObjectMapper; import org.alfresco.transform.common.TransformException;
import org.alfresco.transform.config.TransformConfig; import org.alfresco.transform.config.TransformConfig;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
@@ -41,7 +41,7 @@ import static java.nio.charset.StandardCharsets.UTF_8;
import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR; import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR;
/** /**
* Reads {@link TransformConfig} from a {@json} file. Typically used by {@code TransformEngine.getTransformConfig()}. * Reads {@link TransformConfig} from json or yaml files. Typically used by {@code TransformEngine.getTransformConfig()}.
* <pre> * <pre>
* transformConfigResourceReader.read("classpath:pdfrenderer_engine_config.json"); * transformConfigResourceReader.read("classpath:pdfrenderer_engine_config.json");
* </pre> * </pre>
@@ -51,20 +51,16 @@ public class TransformConfigResourceReader
{ {
@Autowired ResourceLoader resourceLoader; @Autowired ResourceLoader resourceLoader;
private ObjectMapper jsonObjectMapper = new ObjectMapper(); public TransformConfig read(String resourcePath)
public TransformConfig read(String engineConfigLocation)
{ {
Resource engineConfig = resourceLoader.getResource(engineConfigLocation); return read(resourceLoader.getResource(resourcePath));
return read(engineConfig);
} }
public TransformConfig read(Resource resource) public TransformConfig read(Resource resource)
{ {
try (Reader reader = new InputStreamReader(resource.getInputStream(), UTF_8)) try
{ {
TransformConfig transformConfig = jsonObjectMapper.readValue(reader, TransformConfig.class); return TransformConfigReaderFactory.create(resource).load();
return transformConfig;
} }
catch (IOException e) catch (IOException e)
{ {

View File

@@ -32,6 +32,7 @@ import org.alfresco.transform.config.TransformStep;
import org.alfresco.transform.config.Transformer; import org.alfresco.transform.config.Transformer;
import org.alfresco.transform.config.TransformerAndTypes; import org.alfresco.transform.config.TransformerAndTypes;
import org.alfresco.transform.config.Types; import org.alfresco.transform.config.Types;
import org.apache.commons.lang3.tuple.Triple;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
@@ -827,4 +828,9 @@ public class CombinedTransformConfig
{ {
return combinedTransformers.size(); return combinedTransformers.size();
} }
public Map<String,Origin<Transformer>> getTransformerByNameMap()
{
return combinedTransformers.stream().collect(Collectors.toMap(origin -> origin.get().getTransformerName(), origin -> origin));
}
} }

View File

@@ -39,6 +39,7 @@ import static java.util.Collections.emptyMap;
import static java.util.Collections.emptySet; import static java.util.Collections.emptySet;
import static java.util.Map.Entry; import static java.util.Map.Entry;
import static java.util.stream.Collectors.toMap; import static java.util.stream.Collectors.toMap;
import static org.alfresco.transform.common.RequestParamMap.SOURCE_ENCODING;
import static org.springframework.http.HttpStatus.BAD_REQUEST; import static org.springframework.http.HttpStatus.BAD_REQUEST;
class TransformRegistryHelper class TransformRegistryHelper
@@ -95,17 +96,36 @@ class TransformRegistryHelper
return cachedTransformList; return cachedTransformList;
} }
final List<SupportedTransform> builtTransformList = buildTransformList(data, // The transformOptions always contains sourceEncoding and possibly timeout when sent to a T-Engine, even though
sourceMimetype, // they should not be used to select a transformer. Would like to change this, but cannot as we need to support
targetMimetype, // older ACS repo versions.
filterTimeout(actualOptions)); String sourceEncoding = actualOptions.remove(SOURCE_ENCODING);
String timeout = actualOptions.remove(TIMEOUT);
if (renditionName != null) try
{ {
data.cache(renditionName, sourceMimetype, builtTransformList); final List<SupportedTransform> builtTransformList = buildTransformList(data,
} sourceMimetype,
targetMimetype,
actualOptions);
return builtTransformList; if (renditionName != null)
{
data.cache(renditionName, sourceMimetype, builtTransformList);
}
return builtTransformList;
}
finally
{
if (sourceEncoding != null)
{
actualOptions.put(SOURCE_ENCODING, sourceEncoding);
}
if (timeout != null)
{
actualOptions.put(TIMEOUT, timeout);
}
}
} }
private static List<SupportedTransform> buildTransformList( private static List<SupportedTransform> buildTransformList(
@@ -349,18 +369,4 @@ class TransformRegistryHelper
.stream() .stream()
.allMatch(transformOptions::containsKey); .allMatch(transformOptions::containsKey);
} }
private static Map<String, String> filterTimeout(final Map<String, String> options)
{
// Remove the "timeout" property from the actualOptions as it is not used to select a transformer.
if (!options.containsKey(TIMEOUT))
{
return options;
}
return options
.entrySet()
.stream()
.filter(e -> !TIMEOUT.equals(e.getKey()))
.collect(toMap(Entry::getKey, Entry::getValue));
}
} }

View File

@@ -63,10 +63,10 @@ class TransformerDebugTest
.replaceAll(" [\\d,]+ ms", " -- ms"); .replaceAll(" [\\d,]+ ms", " -- ms");
} }
private void twoStepTransform(boolean isTEngine, boolean fail, Level logLevel, String renditionName, private void twoStepTransform(boolean isTRouter, boolean fail, Level logLevel, String renditionName,
long sourceSize) long sourceSize)
{ {
transformerDebug.setIsTEngine(isTEngine); transformerDebug.setIsTRouter(isTRouter);
monitorLogs(logLevel); monitorLogs(logLevel);
TransformRequest request = TransformRequest.builder() TransformRequest request = TransformRequest.builder()
@@ -144,7 +144,7 @@ class TransformerDebugTest
@Test @Test
void testRouterTwoStepTransform() void testRouterTwoStepTransform()
{ {
twoStepTransform(false, false, Level.DEBUG, "", 1234L); twoStepTransform(true, false, Level.DEBUG, "", 1234L);
Assertions.assertEquals("" + Assertions.assertEquals("" +
"1 txt pdf 1.2 KB wrapper\n" + "1 txt pdf 1.2 KB wrapper\n" +
@@ -159,7 +159,7 @@ class TransformerDebugTest
@Test @Test
void testRouterTwoStepTransformWithTrace() void testRouterTwoStepTransformWithTrace()
{ {
twoStepTransform(false, false, Level.TRACE, "", 1234L); twoStepTransform(true, false, Level.TRACE, "", 1234L);
// With trace there are "Finished" lines for nested transforms, like a T-Engine's debug but still without // With trace there are "Finished" lines for nested transforms, like a T-Engine's debug but still without
// the size and rendition name // the size and rendition name
@@ -178,7 +178,7 @@ class TransformerDebugTest
@Test @Test
void testEngineTwoStepTransform() void testEngineTwoStepTransform()
{ {
twoStepTransform(true, false, Level.DEBUG, "", 1234L); twoStepTransform(false, false, Level.DEBUG, "", 1234L);
// Note the first and last lines would only ever be logged on the router, but the expected data includes // Note the first and last lines would only ever be logged on the router, but the expected data includes
// the extra "Finished" lines, sizes and renditions (if set in client data). // the extra "Finished" lines, sizes and renditions (if set in client data).
@@ -197,7 +197,7 @@ class TransformerDebugTest
@Test @Test
void testRouterTwoStepTransformWithFailure() void testRouterTwoStepTransformWithFailure()
{ {
twoStepTransform(false, true, Level.DEBUG, "", 1234L); twoStepTransform(true, true, Level.DEBUG, "", 1234L);
Assertions.assertEquals("" + Assertions.assertEquals("" +
"1 txt pdf 1.2 KB wrapper\n" + "1 txt pdf 1.2 KB wrapper\n" +
@@ -212,7 +212,7 @@ class TransformerDebugTest
@Test @Test
void testRenditionName() void testRenditionName()
{ {
twoStepTransform(false, false, Level.DEBUG, "renditionName", 1234L); twoStepTransform(true, false, Level.DEBUG, "renditionName", 1234L);
Assertions.assertEquals("" + Assertions.assertEquals("" +
"1 txt pdf 1.2 KB -- renditionName -- wrapper\n" + "1 txt pdf 1.2 KB -- renditionName -- wrapper\n" +
@@ -227,7 +227,7 @@ class TransformerDebugTest
@Test @Test
void testMetadataExtract() void testMetadataExtract()
{ {
twoStepTransform(false, false, Level.DEBUG, "transform:alfresco-metadata-extract", 1234L); twoStepTransform(true, false, Level.DEBUG, "transform:alfresco-metadata-extract", 1234L);
Assertions.assertEquals("" + Assertions.assertEquals("" +
"1 txt pdf 1.2 KB -- metadataExtract -- wrapper\n" + "1 txt pdf 1.2 KB -- metadataExtract -- wrapper\n" +
@@ -242,7 +242,7 @@ class TransformerDebugTest
@Test @Test
void testMetadataEmbed() void testMetadataEmbed()
{ {
twoStepTransform(false, false, Level.DEBUG, "transform:alfresco-metadata-embed", 1234L); twoStepTransform(true, false, Level.DEBUG, "transform:alfresco-metadata-embed", 1234L);
Assertions.assertEquals("" + Assertions.assertEquals("" +
"1 txt pdf 1.2 KB -- metadataEmbed -- wrapper\n" + "1 txt pdf 1.2 KB -- metadataEmbed -- wrapper\n" +
@@ -257,7 +257,7 @@ class TransformerDebugTest
@Test @Test
void testSourceSize1Byte() void testSourceSize1Byte()
{ {
twoStepTransform(false, false, Level.DEBUG, "", 1); twoStepTransform(true, false, Level.DEBUG, "", 1);
Assertions.assertEquals("" + Assertions.assertEquals("" +
"1 txt pdf 1 byte wrapper\n" + "1 txt pdf 1 byte wrapper\n" +
@@ -272,7 +272,7 @@ class TransformerDebugTest
@Test @Test
void testSourceSize23TB() void testSourceSize23TB()
{ {
twoStepTransform(false, false, Level.DEBUG, "", 23L*1024*1024*1024*1024); twoStepTransform(true, false, Level.DEBUG, "", 23L*1024*1024*1024*1024);
Assertions.assertEquals("" + Assertions.assertEquals("" +
"1 txt pdf 23 TB wrapper\n" + "1 txt pdf 23 TB wrapper\n" +
@@ -285,7 +285,7 @@ class TransformerDebugTest
} }
@Test @Test
void testLogFailure() void testLogFailureOnTEngine()
{ {
monitorLogs(Level.TRACE); monitorLogs(Level.TRACE);
@@ -296,11 +296,33 @@ class TransformerDebugTest
.withClientData(origClientData) .withClientData(origClientData)
.build(); .build();
transformerDebug.setIsTRouter(false);
transformerDebug.logFailure(reply); transformerDebug.logFailure(reply);
String expectedDebug = " T-Request was null - a major error"; String expectedDebug = " T-Request was null - a major error";
Assertions.assertEquals(expectedDebug, getTransformerDebugOutput()); Assertions.assertEquals(expectedDebug, getTransformerDebugOutput());
assertEquals(origClientData+DEBUG_SEPARATOR+expectedDebug, reply.getClientData()); assertEquals(origClientData, reply.getClientData());
}
@Test
void testLogFailureOnTRouter()
{
monitorLogs(Level.TRACE);
String origClientData = clientDataWithDebugRequest("");
TransformReply reply = TransformReply.builder()
.withInternalContext(InternalContext.initialise(null))
.withErrorDetails("T-Request was null - a major error")
.withClientData(origClientData)
.build();
transformerDebug.setIsTRouter(true);
transformerDebug.logFailure(reply);
String expectedDebug = " T-Request was null - a major error";
String expectedClientData = origClientData+DEBUG_SEPARATOR+expectedDebug;
Assertions.assertEquals(expectedDebug, getTransformerDebugOutput());
assertEquals(expectedClientData, reply.getClientData());
} }
@Test @Test

View File

@@ -0,0 +1,300 @@
/*
* #%L
* Alfresco Transform Model
* %%
* Copyright (C) 2015 - 2022 Alfresco Software Limited
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
* #L%
*/
package org.alfresco.transform.config.reader;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.google.common.collect.ImmutableMap;
import org.alfresco.transform.config.TransformConfig;
import org.alfresco.transform.config.TransformOption;
import org.alfresco.transform.config.TransformOptionGroup;
import org.alfresco.transform.config.TransformOptionValue;
import org.alfresco.transform.config.Transformer;
import org.alfresco.transform.config.SupportedSourceAndTarget;
import org.alfresco.transform.config.TransformStep;
import org.junit.jupiter.api.Test;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
public class TransformConfigReaderJsonTest
{
@Test
public void testEmptyRoutesFile() throws Exception
{
final Resource resource = new ClassPathResource("config/sample1.json");
final TransformConfigReader loader = TransformConfigReaderFactory.create(resource);
TransformConfig transformConfig = loader.load();
final List<Transformer> transformers = transformConfig.getTransformers();
assertNotNull(transformers);
assertEquals(Collections.emptyList(), transformers);
}
@Test
public void testMixedRoutesFile() throws Exception
{
final List<Transformer> expected = prepareSample2();
final Resource resource = new ClassPathResource("config/sample2.json");
final TransformConfigReader loader = TransformConfigReaderFactory.create(resource);
TransformConfig transformConfig = loader.load();
final List<Transformer> transformers = transformConfig.getTransformers();
assertNotNull(transformers);
assertEquals(expected.size(), transformers.size());
assertTrue(expected.containsAll(transformers));
}
private List<Transformer> prepareSample2()
{
return List.of(
Transformer.builder()
.withTransformerName("CORE_AIO")
.withSupportedSourceAndTargetList(ImmutableSet.of(
SupportedSourceAndTarget.builder()
.withSourceMediaType("image/gif")
.withTargetMediaType("image/gif")
.build()
))
.withTransformOptions(ImmutableSet.of("imageMagickOptions"))
.build(),
Transformer.builder()
.withTransformerName("IMAGEMAGICK")
.withSupportedSourceAndTargetList(ImmutableSet.of(
SupportedSourceAndTarget.builder()
.withSourceMediaType("image/gif")
.withTargetMediaType("image/gif")
.build()
))
.withTransformOptions(ImmutableSet.of("imageMagickOptions"))
.build(),
Transformer.builder()
.withTransformerName("CORE_AIO")
.withSupportedSourceAndTargetList(ImmutableSet.of(
SupportedSourceAndTarget.builder()
.withSourceMediaType("application/msword")
.withTargetMediaType("application/pdf")
.withMaxSourceSizeBytes(18874368L)
.build()
))
.build(),
Transformer.builder()
.withTransformerName("PDF_RENDERER")
.withSupportedSourceAndTargetList(ImmutableSet.of(
SupportedSourceAndTarget.builder()
.withSourceMediaType("application/vnd.ms-powerpoint")
.withTargetMediaType("application/pdf")
.withPriority(55)
.withMaxSourceSizeBytes(50331648L)
.build()
))
.build(),
Transformer.builder()
.withTransformerName("CORE_AIO")
.withSupportedSourceAndTargetList(ImmutableSet.of(
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/plain")
.withTargetMediaType("text/plain")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/mediawiki")
.withTargetMediaType("text/plain")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/css")
.withTargetMediaType("text/plain")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/csv")
.withTargetMediaType("text/plain")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/xml")
.withTargetMediaType("text/plain")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/html")
.withTargetMediaType("text/plain")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("application/x-javascript")
.withTargetMediaType("text/plain")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("application/dita+xml")
.withTargetMediaType("text/plain")
.build()
))
.withTransformOptions(ImmutableSet.of("stringOptions"))
.build(),
Transformer.builder()
.withTransformerName("officeToImageViaPdf")
.withTransformerPipeline(ImmutableList.of(
new TransformStep("libreoffice", "application/pdf"),
new TransformStep("pdfToImageViaPng", null)
))
.withTransformOptions(ImmutableSet.of(
"pdfRendererOptions",
"imageMagickOptions"
))
.build(),
Transformer.builder()
.withTransformerName("textToImageViaPdf")
.withTransformerPipeline(ImmutableList.of(
new TransformStep("libreoffice", "application/pdf"),
new TransformStep("pdfToImageViaPng", null)
))
.withTransformOptions(ImmutableSet.of(
"pdfRendererOptions",
"imageMagickOptions"
))
.withSupportedSourceAndTargetList(ImmutableSet.of(
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/plain")
.withTargetMediaType("image/gif")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/plain")
.withTargetMediaType("image/jpeg")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/plain")
.withTargetMediaType("image/tiff")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/plain")
.withTargetMediaType("image/png")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/csv")
.withTargetMediaType("image/gif")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/csv")
.withTargetMediaType("image/jpeg")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/csv")
.withTargetMediaType("image/tiff")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/csv")
.withTargetMediaType("image/png")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/xml")
.withTargetMediaType("image/gif")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/xml")
.withTargetMediaType("image/jpeg")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/xml")
.withTargetMediaType("image/tiff")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/xml")
.withTargetMediaType("image/png")
.build()
))
.withTransformOptions(ImmutableSet.of(
"pdfRendererOptions",
"imageMagickOptions"
))
.build()
);
}
@Test
public void testRouteFileWithTransformOptions() throws Exception
{
final List<Transformer> expected = prepareSample5Transformers();
Map<String, Set<TransformOption>> expectedOptions = prepareSample5Options();
final Resource resource = new ClassPathResource("config/sample5.json");
final TransformConfigReader loader = TransformConfigReaderFactory.create(resource);
TransformConfig transformConfig = loader.load();
final List<Transformer> transformers = transformConfig.getTransformers();
Map<String, Set<TransformOption>> transformOptions = transformConfig.getTransformOptions();
assertNotNull(transformers);
assertEquals(expected.size(), transformers.size());
assertTrue(expected.containsAll(transformers));
assertEquals(expectedOptions, transformOptions);
}
private List<Transformer> prepareSample5Transformers()
{
return List.of(
Transformer.builder()
.withTransformerName("CORE_AIO")
.withSupportedSourceAndTargetList(ImmutableSet.of(
SupportedSourceAndTarget.builder()
.withSourceMediaType("image/gif")
.withTargetMediaType("image/gif")
.build()
))
.withTransformOptions(ImmutableSet.of("imageMagickOptions"))
.build()
);
}
public static Map<String, Set<TransformOption>> prepareSample5Options()
{
return ImmutableMap.of(
"imageMagickOptions", ImmutableSet.of(
new TransformOptionValue(false, "alphaRemove"),
new TransformOptionValue(false, "autoOrient"),
new TransformOptionValue(false, "startPage"),
new TransformOptionValue(false, "endPage"),
new TransformOptionGroup(false, ImmutableSet.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, ImmutableSet.of(
new TransformOptionValue(false, "thumbnail"),
new TransformOptionValue(false, "resizeHeight"),
new TransformOptionValue(false, "resizeWidth"),
new TransformOptionValue(false, "resizePercentage"),
new TransformOptionValue(false, "allowEnlargement"),
new TransformOptionValue(false, "maintainAspectRatio")
)))
);
}
}

View File

@@ -0,0 +1,245 @@
/*
* #%L
* Alfresco Transform Model
* %%
* Copyright (C) 2015 - 2022 Alfresco Software Limited
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
* #L%
*/
package org.alfresco.transform.config.reader;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.alfresco.transform.config.TransformConfig;
import org.alfresco.transform.config.TransformOption;
import org.alfresco.transform.config.Transformer;
import org.alfresco.transform.config.SupportedSourceAndTarget;
import org.alfresco.transform.config.TransformStep;
import org.junit.jupiter.api.Test;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
public class TransformConfigReaderYamlTest
{
@Test
public void testEmptyRoutesFile() throws Exception
{
final Resource resource = new ClassPathResource("config/sample3.yaml");
final TransformConfigReader loader = TransformConfigReaderFactory.create(resource);
TransformConfig transformConfig = loader.load();
final List<Transformer> transformers = transformConfig.getTransformers();
assertNotNull(transformers);
assertEquals(Collections.emptyList(), transformers);
}
@Test
public void testMixedRoutesFile() throws Exception
{
final List<Transformer> expected = prepareSample4();
Map<String, Set<TransformOption>> expectedOptions = TransformConfigReaderJsonTest.prepareSample5Options();
final Resource resource = new ClassPathResource("config/sample4.yaml");
final TransformConfigReader loader = TransformConfigReaderFactory.create(resource);
TransformConfig transformConfig = loader.load();
final List<Transformer> transformers = transformConfig.getTransformers();
Map<String, Set<TransformOption>> transformOptions = transformConfig.getTransformOptions();
assertNotNull(transformers);
assertEquals(expected.size(), transformers.size());
assertTrue(expected.containsAll(transformers));
assertEquals(expectedOptions, transformOptions);
}
private List<Transformer> prepareSample4()
{
var result = new ArrayList<Transformer>();
result.add(Transformer.builder()
.withTransformerName("CORE_AIO")
.withSupportedSourceAndTargetList(ImmutableSet.of(
SupportedSourceAndTarget.builder()
.withSourceMediaType("image/gif")
.withTargetMediaType("image/gif")
.build()
))
.withTransformOptions(ImmutableSet.of("imageMagickOptions"))
.build());
result.add(Transformer.builder()
.withTransformerName("IMAGEMAGICK")
.withSupportedSourceAndTargetList(ImmutableSet.of(
SupportedSourceAndTarget.builder()
.withSourceMediaType("image/gif")
.withTargetMediaType("image/gif")
.build()
))
.withTransformOptions(ImmutableSet.of("imageMagickOptions"))
.build());
result.add(Transformer.builder()
.withTransformerName("CORE_AIO")
.withSupportedSourceAndTargetList(ImmutableSet.of(
SupportedSourceAndTarget.builder()
.withSourceMediaType("application/msword")
.withTargetMediaType("application/pdf")
.withMaxSourceSizeBytes(18874368L)
.build()
))
.build());
result.add(Transformer.builder()
.withTransformerName("PDF_RENDERER")
.withSupportedSourceAndTargetList(ImmutableSet.of(
SupportedSourceAndTarget.builder()
.withSourceMediaType("application/vnd.ms-powerpoint")
.withTargetMediaType("application/pdf")
.withPriority(55)
.withMaxSourceSizeBytes(50331648L)
.build()
))
.build());
result.add(Transformer.builder()
.withTransformerName("CORE_AIO")
.withSupportedSourceAndTargetList(ImmutableSet.of(
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/plain")
.withTargetMediaType("text/plain")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/mediawiki")
.withTargetMediaType("text/plain")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/css")
.withTargetMediaType("text/plain")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/csv")
.withTargetMediaType("text/plain")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/xml")
.withTargetMediaType("text/plain")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/html")
.withTargetMediaType("text/plain")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("application/x-javascript")
.withTargetMediaType("text/plain")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("application/dita+xml")
.withTargetMediaType("text/plain")
.build()
))
.withTransformOptions(ImmutableSet.of("stringOptions"))
.build());
result.add(Transformer.builder()
.withTransformerName("officeToImageViaPdf")
.withTransformerPipeline(ImmutableList.of(
new TransformStep("libreoffice", "application/pdf"),
new TransformStep("pdfToImageViaPng", null)
))
.withTransformOptions(ImmutableSet.of(
"pdfRendererOptions",
"imageMagickOptions"
))
.build());
result.add(Transformer.builder()
.withTransformerName("textToImageViaPdf")
.withTransformerPipeline(ImmutableList.of(
new TransformStep("libreoffice", "application/pdf"),
new TransformStep("pdfToImageViaPng", null)
))
.withTransformOptions(ImmutableSet.of(
"pdfRendererOptions",
"imageMagickOptions"
))
.withSupportedSourceAndTargetList(ImmutableSet.of(
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/plain")
.withTargetMediaType("image/gif")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/plain")
.withTargetMediaType("image/jpeg")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/plain")
.withTargetMediaType("image/tiff")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/plain")
.withTargetMediaType("image/png")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/csv")
.withTargetMediaType("image/gif")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/csv")
.withTargetMediaType("image/jpeg")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/csv")
.withTargetMediaType("image/tiff")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/csv")
.withTargetMediaType("image/png")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/xml")
.withTargetMediaType("image/gif")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/xml")
.withTargetMediaType("image/jpeg")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/xml")
.withTargetMediaType("image/tiff")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/xml")
.withTargetMediaType("image/png")
.build()
))
.withTransformOptions(ImmutableSet.of(
"pdfRendererOptions",
"imageMagickOptions"
))
.build());
return result;
}
}

View File

@@ -30,11 +30,13 @@ import com.google.common.collect.ImmutableMap;
import org.alfresco.transform.common.TransformException; import org.alfresco.transform.common.TransformException;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import static java.util.Arrays.asList; import static java.util.Arrays.asList;
import static java.util.Collections.emptySet; import static java.util.Collections.emptySet;
import static org.alfresco.transform.common.RequestParamMap.SOURCE_ENCODING;
import static org.alfresco.transform.common.RequestParamMap.TIMEOUT; import static org.alfresco.transform.common.RequestParamMap.TIMEOUT;
import static org.alfresco.transform.registry.TransformRegistryHelper.retrieveTransformListBySize; import static org.alfresco.transform.registry.TransformRegistryHelper.retrieveTransformListBySize;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -192,7 +194,21 @@ public class TransformRegistryHelperTest
assertThrows(TransformException.class, () -> assertThrows(TransformException.class, () ->
{ {
retrieveTransformListBySize(data, "text/plain", null, ImmutableMap.of(TIMEOUT, "1234"), null); retrieveTransformListBySize(data, "text/plain", null,
new HashMap<>(ImmutableMap.of(TIMEOUT, "1234")), null);
});
}
@Test
public void filterSourceEncodingTest()
{
// Almost identical to buildTransformListTargetMimeTypeNullErrorTest
TransformCache data = new TransformCache();
assertThrows(TransformException.class, () ->
{
retrieveTransformListBySize(data, "text/plain", null,
new HashMap<>(ImmutableMap.of(SOURCE_ENCODING, "UTF-8")), null);
}); });
} }
} }

View File

@@ -0,0 +1,3 @@
{
"transformers":[]
}

View File

@@ -0,0 +1,92 @@
{
"transformers": [
{
"transformerName": "CORE_AIO",
"supportedSourceAndTargetList": [
{"sourceMediaType": "image/gif", "targetMediaType": "image/gif" }
],
"transformOptions": [
"imageMagickOptions"
]
},
{
"transformerName": "IMAGEMAGICK",
"supportedSourceAndTargetList": [
{"sourceMediaType": "image/gif", "targetMediaType": "image/gif" }
],
"transformOptions": [
"imageMagickOptions"
]
},
{
"transformerName": "CORE_AIO",
"supportedSourceAndTargetList": [
{"sourceMediaType": "application/msword", "maxSourceSizeBytes": 18874368, "targetMediaType": "application/pdf" }
]
},
{
"transformerName": "PDF_RENDERER",
"supportedSourceAndTargetList": [
{"sourceMediaType": "application/vnd.ms-powerpoint", "maxSourceSizeBytes": 50331648, "priority": 55, "targetMediaType": "application/pdf" }
],
"transformOptions": [
]
},
{
"transformerName": "CORE_AIO",
"supportedSourceAndTargetList": [
{"sourceMediaType": "text/plain", "targetMediaType": "text/plain" },
{"sourceMediaType": "text/mediawiki", "targetMediaType": "text/plain" },
{"sourceMediaType": "text/css", "targetMediaType": "text/plain" },
{"sourceMediaType": "text/csv", "targetMediaType": "text/plain" },
{"sourceMediaType": "text/xml", "targetMediaType": "text/plain" },
{"sourceMediaType": "text/html", "targetMediaType": "text/plain" },
{"sourceMediaType": "application/x-javascript", "targetMediaType": "text/plain" },
{"sourceMediaType": "application/dita+xml", "targetMediaType": "text/plain" }
],
"transformOptions": [
"stringOptions"
]
},
{
"transformerName": "officeToImageViaPdf",
"transformerPipeline" : [
{"transformerName": "libreoffice", "targetMediaType": "application/pdf"},
{"transformerName": "pdfToImageViaPng"}
],
"supportedSourceAndTargetList": [
],
"transformOptions": [
"pdfRendererOptions",
"imageMagickOptions"
]
},
{
"transformerName": "textToImageViaPdf",
"transformerPipeline" : [
{"transformerName": "libreoffice", "targetMediaType": "application/pdf"},
{"transformerName": "pdfToImageViaPng"}
],
"supportedSourceAndTargetList": [
{"sourceMediaType": "text/plain", "targetMediaType": "image/gif" },
{"sourceMediaType": "text/plain", "targetMediaType": "image/jpeg"},
{"sourceMediaType": "text/plain", "targetMediaType": "image/tiff"},
{"sourceMediaType": "text/plain", "targetMediaType": "image/png" },
{"sourceMediaType": "text/csv", "targetMediaType": "image/gif" },
{"sourceMediaType": "text/csv", "targetMediaType": "image/jpeg"},
{"sourceMediaType": "text/csv", "targetMediaType": "image/tiff"},
{"sourceMediaType": "text/csv", "targetMediaType": "image/png" },
{"sourceMediaType": "text/xml", "targetMediaType": "image/gif" },
{"sourceMediaType": "text/xml", "targetMediaType": "image/jpeg"},
{"sourceMediaType": "text/xml", "targetMediaType": "image/tiff"},
{"sourceMediaType": "text/xml", "targetMediaType": "image/png" }
],
"transformOptions": [
"pdfRendererOptions",
"imageMagickOptions"
]
}
]
}

View File

@@ -0,0 +1,2 @@
---
transformers:

View File

@@ -0,0 +1,130 @@
---
transformOptions:
imageMagickOptions:
- value:
name: alphaRemove
- value:
name: autoOrient
- value:
name: startPage
- value:
name: endPage
- group:
transformOptions:
- value:
name: cropGravity
- value:
name: cropWidth
- value:
name: cropHeight
- value:
name: cropPercentage
- value:
name: cropXOffset
- value:
name: cropYOffset
- group:
transformOptions:
- value:
name: thumbnail
- value:
name: resizeHeight
- value:
name: resizeWidth
- value:
name: resizePercentage
- value:
name: allowEnlargement
- value:
name: maintainAspectRatio
transformers:
- transformerName: CORE_AIO
supportedSourceAndTargetList:
- sourceMediaType: image/gif
targetMediaType: image/gif
transformOptions:
- imageMagickOptions
- transformerName: IMAGEMAGICK
supportedSourceAndTargetList:
- sourceMediaType: image/gif
targetMediaType: image/gif
transformOptions:
- imageMagickOptions
- transformerName: PDF_RENDERER
supportedSourceAndTargetList:
- sourceMediaType: application/vnd.ms-powerpoint
targetMediaType: application/pdf
priority: 55
maxSourceSizeBytes: 50331648
transformOptions: []
- transformerName: CORE_AIO
supportedSourceAndTargetList:
- sourceMediaType: application/msword
targetMediaType: application/pdf
maxSourceSizeBytes: 18874368
- transformerName: CORE_AIO
supportedSourceAndTargetList:
- sourceMediaType: text/plain
targetMediaType: text/plain
- sourceMediaType: text/mediawiki
targetMediaType: text/plain
- sourceMediaType: text/css
targetMediaType: text/plain
- sourceMediaType: text/csv
targetMediaType: text/plain
- sourceMediaType: text/xml
targetMediaType: text/plain
- sourceMediaType: text/html
targetMediaType: text/plain
- sourceMediaType: application/x-javascript
targetMediaType: text/plain
- sourceMediaType: application/dita+xml
targetMediaType: text/plain
transformOptions:
- stringOptions
- transformerName: officeToImageViaPdf
transformerPipeline:
- transformerName: libreoffice
targetMediaType: application/pdf
- transformerName: pdfToImageViaPng
transformOptions:
- pdfRendererOptions
- imageMagickOptions
- transformerName: textToImageViaPdf
transformerPipeline:
- transformerName: libreoffice
targetMediaType: application/pdf
- transformerName: pdfToImageViaPng
supportedSourceAndTargetList:
- sourceMediaType: text/plain
targetMediaType: image/gif
- sourceMediaType: text/plain
targetMediaType: image/jpeg
- sourceMediaType: text/plain
targetMediaType: image/tiff
- sourceMediaType: text/plain
targetMediaType: image/png
- sourceMediaType: text/csv
targetMediaType: image/gif
- sourceMediaType: text/csv
targetMediaType: image/jpeg
- sourceMediaType: text/csv
targetMediaType: image/tiff
- sourceMediaType: text/csv
targetMediaType: image/png
- sourceMediaType: text/xml
targetMediaType: image/gif
- sourceMediaType: text/xml
targetMediaType: image/jpeg
- sourceMediaType: text/xml
targetMediaType: image/tiff
- sourceMediaType: text/xml
targetMediaType: image/png
transformOptions:
- pdfRendererOptions
- imageMagickOptions

View File

@@ -0,0 +1,37 @@
{
"transformOptions": {
"imageMagickOptions": [
{"value": {"name": "alphaRemove"}},
{"value": {"name": "autoOrient"}},
{"value": {"name": "startPage"}},
{"value": {"name": "endPage"}},
{"group": {"transformOptions": [
{"value": {"name": "cropGravity"}},
{"value": {"name": "cropWidth"}},
{"value": {"name": "cropHeight"}},
{"value": {"name": "cropPercentage"}},
{"value": {"name": "cropXOffset"}},
{"value": {"name": "cropYOffset"}}
]}},
{"group": {"transformOptions": [
{"value": {"name": "thumbnail"}},
{"value": {"name": "resizeHeight"}},
{"value": {"name": "resizeWidth"}},
{"value": {"name": "resizePercentage"}},
{"value": {"name": "allowEnlargement"}},
{"value": {"name": "maintainAspectRatio"}}
]}}
]
},
"transformers": [
{
"transformerName": "CORE_AIO",
"supportedSourceAndTargetList": [
{"sourceMediaType": "image/gif", "targetMediaType": "image/gif" }
],
"transformOptions": [
"imageMagickOptions"
]
}
]
}

View File

@@ -11,7 +11,6 @@
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId> <artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.2</version> <version>2.7.2</version>
<relativePath />
</parent> </parent>
<properties> <properties>