mirror of
https://github.com/Alfresco/alfresco-transform-core.git
synced 2025-08-07 17:48:35 +00:00
ACS-9835-Improve code quality in alfresco-transform-core (#1116)
This commit is contained in:
@@ -27,8 +27,6 @@
|
||||
package org.alfresco.transform.base;
|
||||
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.MeterRegistryCustomizer;
|
||||
|
@@ -26,16 +26,14 @@
|
||||
*/
|
||||
package org.alfresco.transform.base;
|
||||
|
||||
import org.alfresco.transform.config.TransformConfig;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.transform.config.TransformConfig;
|
||||
|
||||
/**
|
||||
* Interface to be implemented by transform specific code. The {@code transformerName} should match the transformerName
|
||||
* in the {@link TransformConfig} returned by the {@link TransformEngine}. So that it is automatically picked up, it
|
||||
* must exist in a package under {@code org.alfresco.transform} and have the Spring {@code @Component} annotation.
|
||||
* Interface to be implemented by transform specific code. The {@code transformerName} should match the transformerName in the {@link TransformConfig} returned by the {@link TransformEngine}. So that it is automatically picked up, it must exist in a package under {@code org.alfresco.transform} and have the Spring {@code @Component} annotation.
|
||||
*
|
||||
* Implementations may also use the {@link TransformManager} if they wish to interact with the base t-engine.
|
||||
*/
|
||||
@@ -44,6 +42,6 @@ public interface CustomTransformer
|
||||
String getTransformerName();
|
||||
|
||||
void transform(String sourceMimetype, InputStream inputStream,
|
||||
String targetMimetype, OutputStream outputStream,
|
||||
Map<String, String> transformOptions, TransformManager transformManager) throws Exception;
|
||||
String targetMimetype, OutputStream outputStream,
|
||||
Map<String, String> transformOptions, TransformManager transformManager) throws Exception;
|
||||
}
|
||||
|
@@ -26,15 +26,42 @@
|
||||
*/
|
||||
package org.alfresco.transform.base;
|
||||
|
||||
import org.alfresco.transform.base.logging.LogEntry;
|
||||
import org.alfresco.transform.base.probes.ProbeTransform;
|
||||
import org.alfresco.transform.base.registry.TransformRegistry;
|
||||
import org.alfresco.transform.base.transform.TransformHandler;
|
||||
import org.alfresco.transform.client.model.TransformReply;
|
||||
import org.alfresco.transform.client.model.TransformRequest;
|
||||
import org.alfresco.transform.exceptions.TransformException;
|
||||
import org.alfresco.transform.config.TransformConfig;
|
||||
import org.alfresco.transform.registry.TransformServiceRegistry;
|
||||
import static java.text.MessageFormat.format;
|
||||
|
||||
import static org.springframework.http.HttpStatus.BAD_REQUEST;
|
||||
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
|
||||
import static org.springframework.http.MediaType.MULTIPART_FORM_DATA_VALUE;
|
||||
|
||||
import static org.alfresco.transform.base.html.OptionsHelper.getOptionNames;
|
||||
import static org.alfresco.transform.common.RequestParamMap.CONFIG_VERSION;
|
||||
import static org.alfresco.transform.common.RequestParamMap.CONFIG_VERSION_DEFAULT;
|
||||
import static org.alfresco.transform.common.RequestParamMap.ENDPOINT_ERROR;
|
||||
import static org.alfresco.transform.common.RequestParamMap.ENDPOINT_LIVE;
|
||||
import static org.alfresco.transform.common.RequestParamMap.ENDPOINT_LOG;
|
||||
import static org.alfresco.transform.common.RequestParamMap.ENDPOINT_READY;
|
||||
import static org.alfresco.transform.common.RequestParamMap.ENDPOINT_ROOT;
|
||||
import static org.alfresco.transform.common.RequestParamMap.ENDPOINT_TEST;
|
||||
import static org.alfresco.transform.common.RequestParamMap.ENDPOINT_TRANSFORM;
|
||||
import static org.alfresco.transform.common.RequestParamMap.ENDPOINT_TRANSFORM_CONFIG;
|
||||
import static org.alfresco.transform.common.RequestParamMap.ENDPOINT_VERSION;
|
||||
import static org.alfresco.transform.common.RequestParamMap.FILE;
|
||||
import static org.alfresco.transform.common.RequestParamMap.SOURCE_MIMETYPE;
|
||||
import static org.alfresco.transform.common.RequestParamMap.TARGET_MIMETYPE;
|
||||
import static org.alfresco.transform.config.CoreVersionDecorator.setOrClearCoreVersion;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.jms.Destination;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -57,39 +84,14 @@ import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.jms.Destination;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import static java.text.MessageFormat.format;
|
||||
import static org.alfresco.transform.base.html.OptionsHelper.getOptionNames;
|
||||
import static org.alfresco.transform.common.RequestParamMap.CONFIG_VERSION;
|
||||
import static org.alfresco.transform.common.RequestParamMap.CONFIG_VERSION_DEFAULT;
|
||||
import static org.alfresco.transform.common.RequestParamMap.ENDPOINT_ERROR;
|
||||
import static org.alfresco.transform.common.RequestParamMap.ENDPOINT_LIVE;
|
||||
import static org.alfresco.transform.common.RequestParamMap.ENDPOINT_LOG;
|
||||
import static org.alfresco.transform.common.RequestParamMap.ENDPOINT_READY;
|
||||
import static org.alfresco.transform.common.RequestParamMap.ENDPOINT_ROOT;
|
||||
import static org.alfresco.transform.common.RequestParamMap.ENDPOINT_TEST;
|
||||
import static org.alfresco.transform.common.RequestParamMap.ENDPOINT_TRANSFORM;
|
||||
import static org.alfresco.transform.common.RequestParamMap.ENDPOINT_TRANSFORM_CONFIG;
|
||||
import static org.alfresco.transform.common.RequestParamMap.ENDPOINT_VERSION;
|
||||
import static org.alfresco.transform.common.RequestParamMap.FILE;
|
||||
import static org.alfresco.transform.common.RequestParamMap.SOURCE_MIMETYPE;
|
||||
import static org.alfresco.transform.common.RequestParamMap.TARGET_MIMETYPE;
|
||||
import static org.alfresco.transform.config.CoreVersionDecorator.setOrClearCoreVersion;
|
||||
import static org.springframework.http.HttpStatus.BAD_REQUEST;
|
||||
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
|
||||
import static org.springframework.http.MediaType.MULTIPART_FORM_DATA_VALUE;
|
||||
import org.alfresco.transform.base.logging.LogEntry;
|
||||
import org.alfresco.transform.base.probes.ProbeTransform;
|
||||
import org.alfresco.transform.base.registry.TransformRegistry;
|
||||
import org.alfresco.transform.base.transform.TransformHandler;
|
||||
import org.alfresco.transform.client.model.TransformReply;
|
||||
import org.alfresco.transform.client.model.TransformRequest;
|
||||
import org.alfresco.transform.config.TransformConfig;
|
||||
import org.alfresco.transform.exceptions.TransformException;
|
||||
|
||||
/**
|
||||
* Provides the main endpoints into the t-engine.
|
||||
@@ -126,9 +128,9 @@ public class TransformController
|
||||
transformEngine = getTransformEngine();
|
||||
logger.info("TransformEngine: {}", transformEngine.getTransformEngineName());
|
||||
transformEngines.stream()
|
||||
.filter(transformEngineFromStream -> transformEngineFromStream != transformEngine)
|
||||
.sorted(Comparator.comparing(TransformEngine::getTransformEngineName))
|
||||
.map(sortedTransformEngine -> " "+sortedTransformEngine.getTransformEngineName()).forEach(logger::info);
|
||||
.filter(transformEngineFromStream -> transformEngineFromStream != transformEngine)
|
||||
.sorted(Comparator.comparing(TransformEngine::getTransformEngineName))
|
||||
.map(sortedTransformEngine -> " " + sortedTransformEngine.getTransformEngineName()).forEach(logger::info);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,9 +140,9 @@ public class TransformController
|
||||
// CustomTransform code from many t-engines into a single t-engine. In this case, there should be a wrapper
|
||||
// TransformEngine (it has no TransformConfig of its own).
|
||||
return transformEngines.stream()
|
||||
.filter(transformEngineFromStream -> transformEngineFromStream.getTransformConfig() == null)
|
||||
.findFirst()
|
||||
.orElse(transformEngines.get(0));
|
||||
.filter(transformEngineFromStream -> transformEngineFromStream.getTransformConfig() == null)
|
||||
.findFirst()
|
||||
.orElse(transformEngines.get(0));
|
||||
}
|
||||
|
||||
@EventListener(ApplicationReadyEvent.class)
|
||||
@@ -285,8 +287,8 @@ public class TransformController
|
||||
@PostMapping(value = ENDPOINT_TRANSFORM, produces = APPLICATION_JSON_VALUE)
|
||||
@ResponseBody
|
||||
public ResponseEntity<TransformReply> transform(@RequestBody TransformRequest request,
|
||||
@RequestParam(value = "timeout", required = false) Long timeout,
|
||||
@RequestParam(value = "replyToQueue", required = false) Destination replyToQueue)
|
||||
@RequestParam(value = "timeout", required = false) Long timeout,
|
||||
@RequestParam(value = "replyToQueue", required = false) Destination replyToQueue)
|
||||
{
|
||||
TransformReply reply = transformHandler.handleMessageRequest(request, timeout, replyToQueue, getProbeTransform());
|
||||
return new ResponseEntity<>(reply, HttpStatus.valueOf(reply.getStatus()));
|
||||
@@ -317,8 +319,7 @@ public class TransformController
|
||||
Map<String, String> requestParameters = new HashMap<>();
|
||||
sourceMimetype = overrideMimetypeFromExtension(origRequestParameters, SOURCE_MIMETYPE, sourceMimetype);
|
||||
targetMimetype = overrideMimetypeFromExtension(origRequestParameters, TARGET_MIMETYPE, targetMimetype);
|
||||
origRequestParameters.forEach((name, value) ->
|
||||
{
|
||||
origRequestParameters.forEach((name, value) -> {
|
||||
if (!name.startsWith("value"))
|
||||
{
|
||||
if (name.startsWith("name"))
|
||||
@@ -338,7 +339,7 @@ public class TransformController
|
||||
|
||||
private String overrideMimetypeFromExtension(Map<String, String> origRequestParameters, String name, String value)
|
||||
{
|
||||
String override = origRequestParameters.remove("_"+ name);
|
||||
String override = origRequestParameters.remove("_" + name);
|
||||
if (override != null && !override.isBlank())
|
||||
{
|
||||
value = override;
|
||||
@@ -349,7 +350,7 @@ public class TransformController
|
||||
|
||||
@ExceptionHandler(MissingServletRequestParameterException.class)
|
||||
public void handleMissingParams(HttpServletResponse response, MissingServletRequestParameterException e)
|
||||
throws IOException
|
||||
throws IOException
|
||||
{
|
||||
final String message = format("Request parameter ''{0}'' is missing", e.getParameterName());
|
||||
logger.error(message, e);
|
||||
|
@@ -27,14 +27,11 @@
|
||||
package org.alfresco.transform.base;
|
||||
|
||||
import org.alfresco.transform.base.probes.ProbeTransform;
|
||||
import org.alfresco.transform.config.reader.TransformConfigResourceReader;
|
||||
import org.alfresco.transform.config.TransformConfig;
|
||||
import org.alfresco.transform.config.reader.TransformConfigResourceReader;
|
||||
|
||||
/**
|
||||
* Interface to be implemented by transform specific code. Provides information about the t-engine as a whole.
|
||||
* Also see {@link CustomTransformer} which provides the code that performs transformation. There may be several
|
||||
* in a single t-engine. So that it is automatically picked up, it must exist in a package under
|
||||
* {@code org.alfresco.transform} and have the Spring {@code @Component} annotation.
|
||||
* Interface to be implemented by transform specific code. Provides information about the t-engine as a whole. Also see {@link CustomTransformer} which provides the code that performs transformation. There may be several in a single t-engine. So that it is automatically picked up, it must exist in a package under {@code org.alfresco.transform} and have the Spring {@code @Component} annotation.
|
||||
*/
|
||||
public interface TransformEngine
|
||||
{
|
||||
@@ -49,10 +46,7 @@ public interface TransformEngine
|
||||
String getStartupMessage();
|
||||
|
||||
/**
|
||||
* @return a definition of what the t-engine supports. Normally read from a json Resource on the classpath using a
|
||||
* {@link TransformConfigResourceReader}. To combine to code from multiple t-engine into a single t-engine
|
||||
* include all the TransformEngines and CustomTransform implementations, plus a wrapper TransformEngine for the
|
||||
* others. The wrapper should return {@code null} from this method.
|
||||
* @return a definition of what the t-engine supports. Normally read from a json Resource on the classpath using a {@link TransformConfigResourceReader}. To combine to code from multiple t-engine into a single t-engine include all the TransformEngines and CustomTransform implementations, plus a wrapper TransformEngine for the others. The wrapper should return {@code null} from this method.
|
||||
*/
|
||||
TransformConfig getTransformConfig();
|
||||
|
||||
|
@@ -26,14 +26,14 @@
|
||||
*/
|
||||
package org.alfresco.transform.base;
|
||||
|
||||
import org.alfresco.transform.exceptions.TransformException;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.transform.exceptions.TransformException;
|
||||
|
||||
/**
|
||||
* Allows {@link CustomTransformer} implementations to interact with the base t-engine.
|
||||
*/
|
||||
@@ -45,42 +45,33 @@ public interface TransformManager
|
||||
String getRequestId();
|
||||
|
||||
/**
|
||||
* Allows a {@link CustomTransformer} to use a local source {@code File} rather than the supplied {@code InputStream}.
|
||||
* The file will be deleted once the request is completed. To avoid creating extra files, if a File has already
|
||||
* been created by the base t-engine, it is returned.
|
||||
* If possible this method should be avoided as it is better not to leave content on disk.
|
||||
* @throws IllegalStateException if this method has already been called.
|
||||
* Allows a {@link CustomTransformer} to use a local source {@code File} rather than the supplied {@code InputStream}. The file will be deleted once the request is completed. To avoid creating extra files, if a File has already been created by the base t-engine, it is returned. If possible this method should be avoided as it is better not to leave content on disk.
|
||||
*
|
||||
* @throws IllegalStateException
|
||||
* if this method has already been called.
|
||||
*/
|
||||
File createSourceFile() throws IllegalStateException;
|
||||
|
||||
/**
|
||||
* Allows a {@link CustomTransformer} to use a local target {@code File} rather than the supplied {@code OutputStream}.
|
||||
* The file will be deleted once the request is completed. To avoid creating extra files, if a File has already
|
||||
* been created by the base t-engine, it is returned.
|
||||
* If possible this method should be avoided as it is better not to leave content on disk.
|
||||
* @throws IllegalStateException if this method has already been called. A call to {@link #respondWithFragment(Integer, boolean)}
|
||||
* allows the method to be called again.
|
||||
* Allows a {@link CustomTransformer} to use a local target {@code File} rather than the supplied {@code OutputStream}. The file will be deleted once the request is completed. To avoid creating extra files, if a File has already been created by the base t-engine, it is returned. If possible this method should be avoided as it is better not to leave content on disk.
|
||||
*
|
||||
* @throws IllegalStateException
|
||||
* if this method has already been called. A call to {@link #respondWithFragment(Integer, boolean)} allows the method to be called again.
|
||||
*/
|
||||
File createTargetFile() throws IllegalStateException;
|
||||
|
||||
/**
|
||||
* Allows a single transform request to have multiple transform responses. For example, images from a video at
|
||||
* different time offsets or different pages of a document. Following a call to this method a transform response is
|
||||
* made with the data sent to the current {@code OutputStream}. If this method has been called, there will not be
|
||||
* another response when {@link CustomTransformer#transform(String, InputStream, String, OutputStream, Map,
|
||||
* TransformManager)} returns and any data written to the final {@code OutputStream} will be ignored.
|
||||
* @param index returned with the response, so that the fragment may be distinguished from other responses.
|
||||
* Renditions use the index as an offset into elements. A {@code null} value indicates that there
|
||||
* is no more output and any data sent to the current {@code outputStream} will be ignored.
|
||||
* @param finished indicates this is the final fragment. {@code False} indicates that it is expected there will be
|
||||
* more fragments. There need not be a call with this parameter set to {@code true}.
|
||||
* @return a new {@code OutputStream} for the next fragment. A {@code null} will be returned if {@code index} was
|
||||
* {@code null} or {@code finished} was {@code true}.
|
||||
* @throws TransformException if a synchronous (http) request has been made as this only works with requests
|
||||
* on queues, or the first call to this method indicated there was no output, or
|
||||
* another call is made after it has been indicated that there should be no more
|
||||
* fragments.
|
||||
* @throws IOException if there was a problem sending the response.
|
||||
* Allows a single transform request to have multiple transform responses. For example, images from a video at different time offsets or different pages of a document. Following a call to this method a transform response is made with the data sent to the current {@code OutputStream}. If this method has been called, there will not be another response when {@link CustomTransformer#transform(String, InputStream, String, OutputStream, Map, TransformManager)} returns and any data written to the final {@code OutputStream} will be ignored.
|
||||
*
|
||||
* @param index
|
||||
* returned with the response, so that the fragment may be distinguished from other responses. Renditions use the index as an offset into elements. A {@code null} value indicates that there is no more output and any data sent to the current {@code outputStream} will be ignored.
|
||||
* @param finished
|
||||
* indicates this is the final fragment. {@code False} indicates that it is expected there will be more fragments. There need not be a call with this parameter set to {@code true}.
|
||||
* @return a new {@code OutputStream} for the next fragment. A {@code null} will be returned if {@code index} was {@code null} or {@code finished} was {@code true}.
|
||||
* @throws TransformException
|
||||
* if a synchronous (http) request has been made as this only works with requests on queues, or the first call to this method indicated there was no output, or another call is made after it has been indicated that there should be no more fragments.
|
||||
* @throws IOException
|
||||
* if there was a problem sending the response.
|
||||
*/
|
||||
// This works because all the state is in the TransformResponse and the t-router will just see each response as
|
||||
// something to either return to the client or pass to the next stage in a pipeline. We might be able to enhance
|
||||
|
@@ -26,7 +26,15 @@
|
||||
*/
|
||||
package org.alfresco.transform.base.config;
|
||||
|
||||
import org.alfresco.transform.base.WebClientBuilderAdjuster;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.KeyStore;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.UnrecoverableKeyException;
|
||||
import java.security.cert.CertificateException;
|
||||
|
||||
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
|
||||
import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
|
||||
import org.apache.hc.client5.http.impl.classic.HttpClients;
|
||||
@@ -52,17 +60,11 @@ import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
|
||||
import org.springframework.http.client.reactive.JettyClientHttpConnector;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.KeyStore;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.UnrecoverableKeyException;
|
||||
import java.security.cert.CertificateException;
|
||||
import org.alfresco.transform.base.WebClientBuilderAdjuster;
|
||||
|
||||
@Configuration
|
||||
public class MTLSConfig {
|
||||
public class MTLSConfig
|
||||
{
|
||||
|
||||
@Value("${client.ssl.key-store:#{null}}")
|
||||
private Resource keyStoreResource;
|
||||
@@ -89,7 +91,7 @@ public class MTLSConfig {
|
||||
public WebClientBuilderAdjuster webClientBuilderAdjuster(SslContextFactory.Client sslContextFactory)
|
||||
{
|
||||
return builder -> {
|
||||
if(isTlsOrMtlsConfigured())
|
||||
if (isTlsOrMtlsConfigured())
|
||||
{
|
||||
ClientConnector clientConnector = new ClientConnector();
|
||||
clientConnector.setSslContextFactory(sslContextFactory);
|
||||
@@ -103,23 +105,26 @@ public class MTLSConfig {
|
||||
@Bean
|
||||
public RestTemplate restTemplate(SSLContextBuilder sslContextBuilder) throws NoSuchAlgorithmException, KeyManagementException
|
||||
{
|
||||
if(isTlsOrMtlsConfigured())
|
||||
if (isTlsOrMtlsConfigured())
|
||||
{
|
||||
return createRestTemplateWithSslContext(sslContextBuilder);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
return new RestTemplate();
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SSLContextBuilder sslContextBuilder() throws CertificateException, KeyStoreException, IOException, NoSuchAlgorithmException, UnrecoverableKeyException {
|
||||
public SSLContextBuilder sslContextBuilder() throws CertificateException, KeyStoreException, IOException, NoSuchAlgorithmException, UnrecoverableKeyException
|
||||
{
|
||||
SSLContextBuilder sslContextBuilder = new SSLContextBuilder();
|
||||
if(isKeystoreConfigured())
|
||||
if (isKeystoreConfigured())
|
||||
{
|
||||
KeyStore keyStore = getKeyStore(keyStoreType, keyStoreResource, keyStorePassword);
|
||||
sslContextBuilder.loadKeyMaterial(keyStore, keyStorePassword);
|
||||
}
|
||||
if(isTruststoreConfigured())
|
||||
if (isTruststoreConfigured())
|
||||
{
|
||||
sslContextBuilder
|
||||
.setKeyStoreType(trustStoreType)
|
||||
@@ -156,20 +161,20 @@ public class MTLSConfig {
|
||||
return keyStoreResource != null;
|
||||
}
|
||||
|
||||
private RestTemplate createRestTemplateWithSslContext(SSLContextBuilder sslContextBuilder) throws NoSuchAlgorithmException, KeyManagementException {
|
||||
final SSLConnectionSocketFactoryBuilder sslConnectionSocketFactoryBuilder =
|
||||
SSLConnectionSocketFactoryBuilder.create()
|
||||
.setSslContext(sslContextBuilder.build())
|
||||
.setTlsVersions(TLS.V_1_2, TLS.V_1_3);
|
||||
if (hostNameVerificationDisabled) {
|
||||
private RestTemplate createRestTemplateWithSslContext(SSLContextBuilder sslContextBuilder) throws NoSuchAlgorithmException, KeyManagementException
|
||||
{
|
||||
final SSLConnectionSocketFactoryBuilder sslConnectionSocketFactoryBuilder = SSLConnectionSocketFactoryBuilder.create()
|
||||
.setSslContext(sslContextBuilder.build())
|
||||
.setTlsVersions(TLS.V_1_2, TLS.V_1_3);
|
||||
if (hostNameVerificationDisabled)
|
||||
{
|
||||
sslConnectionSocketFactoryBuilder.setHostnameVerifier(NoopHostnameVerifier.INSTANCE);
|
||||
}
|
||||
final SSLConnectionSocketFactory sslConnectionSocketFactory = sslConnectionSocketFactoryBuilder.build();
|
||||
|
||||
final Registry<ConnectionSocketFactory> sslSocketFactoryRegistry =
|
||||
RegistryBuilder.<ConnectionSocketFactory> create()
|
||||
.register("https", sslConnectionSocketFactory)
|
||||
.build();
|
||||
final Registry<ConnectionSocketFactory> sslSocketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory> create()
|
||||
.register("https", sslConnectionSocketFactory)
|
||||
.build();
|
||||
|
||||
final PoolingHttpClientConnectionManager sslConnectionManager = new PoolingHttpClientConnectionManager(sslSocketFactoryRegistry);
|
||||
|
||||
|
@@ -26,10 +26,12 @@
|
||||
*/
|
||||
package org.alfresco.transform.base.config;
|
||||
|
||||
import org.alfresco.transform.base.html.TransformInterceptor;
|
||||
import org.alfresco.transform.base.registry.TransformConfigSource;
|
||||
import org.alfresco.transform.common.TransformerDebug;
|
||||
import org.alfresco.transform.messages.TransformRequestValidator;
|
||||
import static org.alfresco.transform.common.RequestParamMap.ENDPOINT_TRANSFORM;
|
||||
import static org.alfresco.transform.config.CoreFunction.standardizeCoreVersion;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
@@ -38,11 +40,10 @@ import org.springframework.context.annotation.FilterType;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.alfresco.transform.common.RequestParamMap.ENDPOINT_TRANSFORM;
|
||||
import static org.alfresco.transform.config.CoreFunction.standardizeCoreVersion;
|
||||
import org.alfresco.transform.base.html.TransformInterceptor;
|
||||
import org.alfresco.transform.base.registry.TransformConfigSource;
|
||||
import org.alfresco.transform.common.TransformerDebug;
|
||||
import org.alfresco.transform.messages.TransformRequestValidator;
|
||||
|
||||
@Configuration
|
||||
@ComponentScan(
|
||||
|
@@ -26,10 +26,11 @@
|
||||
*/
|
||||
package org.alfresco.transform.base.executors;
|
||||
|
||||
import static org.alfresco.transform.base.executors.RuntimeExec.ExecutionResult;
|
||||
import static org.springframework.http.HttpStatus.BAD_REQUEST;
|
||||
import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR;
|
||||
|
||||
import static org.alfresco.transform.base.executors.RuntimeExec.ExecutionResult;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Map;
|
||||
|
||||
|
@@ -26,12 +26,12 @@
|
||||
*/
|
||||
package org.alfresco.transform.base.executors;
|
||||
|
||||
import org.alfresco.transform.base.logging.LogEntry;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.transform.base.logging.LogEntry;
|
||||
|
||||
/**
|
||||
* Basic interface for executing transformations via Shell commands
|
||||
*
|
||||
|
@@ -35,24 +35,17 @@ import java.util.Objects;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
/**
|
||||
* This class is used to tokenize strings used as parameters for {@link RuntimeExec} objects.
|
||||
* Examples of such strings are as follows (ImageMagick-like parameters):
|
||||
* This class is used to tokenize strings used as parameters for {@link RuntimeExec} objects. Examples of such strings are as follows (ImageMagick-like parameters):
|
||||
* <ul>
|
||||
* <li><tt>-font Helvetica -pointsize 50</tt></li>
|
||||
* <li><tt>-font Helvetica -pointsize 50 -draw "circle 100,100 150,150"</tt></li>
|
||||
* <li><tt>-font Helvetica -pointsize 50 -draw "gravity south fill black text 0,12 'CopyRight'"</tt></li>
|
||||
* </ul>
|
||||
* The first is the simple case which would be parsed into Strings as follows:
|
||||
* <tt>"-font", "Helvetica", "-pointsize", "50"</tt>
|
||||
* The first is the simple case which would be parsed into Strings as follows: <tt>"-font", "Helvetica", "-pointsize", "50"</tt>
|
||||
* <p/>
|
||||
* The second is more complex in that it includes a quoted parameter, which would be parsed as a single String:
|
||||
* <tt>"-font", "Helvetica", "-pointsize", "50", "circle 100,100 150,150"</tt>
|
||||
* Note however that the quotation characters will be stripped from the token.
|
||||
* The second is more complex in that it includes a quoted parameter, which would be parsed as a single String: <tt>"-font", "Helvetica", "-pointsize", "50", "circle 100,100 150,150"</tt> Note however that the quotation characters will be stripped from the token.
|
||||
* <p/>
|
||||
* The third shows an example with embedded quotation marks, which would parse to:
|
||||
* <tt>"-font", "Helvetica", "-pointsize", "50", "gravity south fill black text 0,12 'CopyRight'"</tt>
|
||||
* In this case, the embedded quotation marks (which must be different from those surrounding the parameter)
|
||||
* are preserved in the extracted token.
|
||||
* The third shows an example with embedded quotation marks, which would parse to: <tt>"-font", "Helvetica", "-pointsize", "50", "gravity south fill black text 0,12 'CopyRight'"</tt> In this case, the embedded quotation marks (which must be different from those surrounding the parameter) are preserved in the extracted token.
|
||||
* <p/>
|
||||
* The class does not understand escaped quotes such as <tt>p1 p2 "a b c \"hello\" d" p4</tt>
|
||||
*
|
||||
@@ -77,15 +70,12 @@ public class ExecParameterTokenizer
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the tokens in a parameter string.
|
||||
* Any tokens not contained within single or double quotes will be tokenized in the normal
|
||||
* way i.e. by using whitespace separators and the standard StringTokenizer algorithm.
|
||||
* Any tokens which are contained within single or double quotes will be returned as single
|
||||
* String instances and will have their quote marks removed.
|
||||
* This method returns the tokens in a parameter string. Any tokens not contained within single or double quotes will be tokenized in the normal way i.e. by using whitespace separators and the standard StringTokenizer algorithm. Any tokens which are contained within single or double quotes will be returned as single String instances and will have their quote marks removed.
|
||||
* <p/>
|
||||
* See above for examples.
|
||||
*
|
||||
* @throws NullPointerException if the string to be tokenized was null.
|
||||
* @throws NullPointerException
|
||||
* if the string to be tokenized was null.
|
||||
*/
|
||||
public List<String> getAllTokens()
|
||||
{
|
||||
@@ -103,7 +93,7 @@ public class ExecParameterTokenizer
|
||||
{
|
||||
// Contains no quotes.
|
||||
for (StringTokenizer standardTokenizer = new StringTokenizer(
|
||||
str); standardTokenizer.hasMoreTokens(); )
|
||||
str); standardTokenizer.hasMoreTokens();)
|
||||
{
|
||||
tokens.add(standardTokenizer.nextToken());
|
||||
}
|
||||
@@ -114,7 +104,7 @@ public class ExecParameterTokenizer
|
||||
// So we need to identify the quoted regions within the string.
|
||||
List<Pair<Integer, Integer>> quotedRegions = new ArrayList<>();
|
||||
|
||||
for (Pair<Integer, Integer> next = identifyNextQuotedRegion(str, 0); next != null; )
|
||||
for (Pair<Integer, Integer> next = identifyNextQuotedRegion(str, 0); next != null;)
|
||||
{
|
||||
quotedRegions.add(next);
|
||||
next = identifyNextQuotedRegion(str, next.getSecond() + 1);
|
||||
@@ -135,12 +125,10 @@ public class ExecParameterTokenizer
|
||||
}
|
||||
|
||||
/**
|
||||
* The substrings will be a list of quoted and unquoted substrings.
|
||||
* The unquoted ones need to be further tokenized in the normal way.
|
||||
* The quoted ones must not be tokenized, but need their quotes stripped off.
|
||||
* The substrings will be a list of quoted and unquoted substrings. The unquoted ones need to be further tokenized in the normal way. The quoted ones must not be tokenized, but need their quotes stripped off.
|
||||
*/
|
||||
private List<Substring> getSubstrings(String str,
|
||||
List<Pair<Integer, Integer>> quotedRegionIndices)
|
||||
List<Pair<Integer, Integer>> quotedRegionIndices)
|
||||
{
|
||||
List<Substring> result = new ArrayList<>();
|
||||
|
||||
@@ -151,10 +139,10 @@ public class ExecParameterTokenizer
|
||||
{
|
||||
int startIndexOfNextQuotedRegion = nextQuotedRegionIndices.getFirst() - 1;
|
||||
result.add(new UnquotedSubstring(
|
||||
str.substring(cursorPosition, startIndexOfNextQuotedRegion)));
|
||||
str.substring(cursorPosition, startIndexOfNextQuotedRegion)));
|
||||
}
|
||||
result.add(new QuotedSubstring(str.substring(nextQuotedRegionIndices.getFirst(),
|
||||
nextQuotedRegionIndices.getSecond())));
|
||||
nextQuotedRegionIndices.getSecond())));
|
||||
cursorPosition = nextQuotedRegionIndices.getSecond();
|
||||
}
|
||||
|
||||
@@ -198,12 +186,12 @@ public class ExecParameterTokenizer
|
||||
}
|
||||
|
||||
private Pair<Integer, Integer> findIndexOfClosingQuote(String str, int indexOfStartingQuote,
|
||||
char quoteChar)
|
||||
char quoteChar)
|
||||
{
|
||||
// So we know which type of quote char we're dealing with. Either ' or ".
|
||||
// Now we need to find the closing quote.
|
||||
int indexAfterClosingQuote = str.indexOf(quoteChar,
|
||||
indexOfStartingQuote + 1) + 1; // + 1 to search after opening quote. + 1 to give result including closing quote.
|
||||
indexOfStartingQuote + 1) + 1; // + 1 to search after opening quote. + 1 to give result including closing quote.
|
||||
|
||||
if (indexAfterClosingQuote == 0) // -1 + 1
|
||||
{
|
||||
@@ -295,8 +283,10 @@ public class ExecParameterTokenizer
|
||||
/**
|
||||
* Make a new one.
|
||||
*
|
||||
* @param first The first member.
|
||||
* @param second The second member.
|
||||
* @param first
|
||||
* The first member.
|
||||
* @param second
|
||||
* The second member.
|
||||
*/
|
||||
public Pair(F first, S second)
|
||||
{
|
||||
@@ -334,16 +324,20 @@ public class ExecParameterTokenizer
|
||||
this.second = second;
|
||||
}
|
||||
|
||||
@Override public boolean equals(Object o)
|
||||
@Override
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
if (this == o)
|
||||
return true;
|
||||
if (o == null || getClass() != o.getClass())
|
||||
return false;
|
||||
Pair<?, ?> pair = (Pair<?, ?>) o;
|
||||
return Objects.equals(first, pair.first) &&
|
||||
Objects.equals(second, pair.second);
|
||||
Objects.equals(second, pair.second);
|
||||
}
|
||||
|
||||
@Override public int hashCode()
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return Objects.hash(first, second);
|
||||
}
|
||||
@@ -355,4 +349,3 @@ public class ExecParameterTokenizer
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -50,51 +50,50 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* This acts as a session similar to the <code>java.lang.Process</code>, but
|
||||
* logs the system standard and error streams.
|
||||
* This acts as a session similar to the <code>java.lang.Process</code>, but logs the system standard and error streams.
|
||||
* <p>
|
||||
* The bean can be configured to execute a command directly, or be given a map
|
||||
* of commands keyed by the <i>os.name</i> Java system property. In this map,
|
||||
* the default key that is used when no match is found is the
|
||||
* <b>{@link #KEY_OS_DEFAULT *}</b> key.
|
||||
* The bean can be configured to execute a command directly, or be given a map of commands keyed by the <i>os.name</i> Java system property. In this map, the default key that is used when no match is found is the <b>{@link #KEY_OS_DEFAULT *}</b> key.
|
||||
* <p>
|
||||
* Use the {@link #setProcessDirectory(String) processDirectory} property to change the default location
|
||||
* from which the command executes. The process's environment can be configured using the
|
||||
* {@link #setProcessProperties(Map) processProperties} property.
|
||||
* Use the {@link #setProcessDirectory(String) processDirectory} property to change the default location from which the command executes. The process's environment can be configured using the {@link #setProcessProperties(Map) processProperties} property.
|
||||
* <p>
|
||||
* Commands may use placeholders, e.g.
|
||||
* <pre><code>
|
||||
*
|
||||
* <pre>
|
||||
* <code>
|
||||
* find
|
||||
* -name
|
||||
* ${filename}
|
||||
* </code></pre>
|
||||
* The <b>filename</b> property will be substituted for any supplied value prior to
|
||||
* each execution of the command. Currently, no checks are made to get or check the
|
||||
* properties contained within the command string. It is up to the client code to
|
||||
* dynamically extract the properties required if the required properties are not
|
||||
* known up front.
|
||||
* </code>
|
||||
* </pre>
|
||||
*
|
||||
* The <b>filename</b> property will be substituted for any supplied value prior to each execution of the command. Currently, no checks are made to get or check the properties contained within the command string. It is up to the client code to dynamically extract the properties required if the required properties are not known up front.
|
||||
* <p>
|
||||
* Sometimes, a variable may contain several arguments. . In this case, the arguments
|
||||
* need to be tokenized using a standard <tt>StringTokenizer</tt>. To force tokenization
|
||||
* of a value, use:
|
||||
* <pre><code>
|
||||
* Sometimes, a variable may contain several arguments. . In this case, the arguments need to be tokenized using a standard <tt>StringTokenizer</tt>. To force tokenization of a value, use:
|
||||
*
|
||||
* <pre>
|
||||
* <code>
|
||||
* SPLIT:${userArgs}
|
||||
* </code></pre>
|
||||
* You should not use this just to split up arguments that are known to require tokenization
|
||||
* up front. The <b>SPLIT:</b> directive works for the entire argument and will not do anything
|
||||
* if it is not at the beginning of the argument. Do not use <b>SPLIT:</b> to break up arguments
|
||||
* that are fixed, so avoid doing this:
|
||||
* <pre><code>
|
||||
* </code>
|
||||
* </pre>
|
||||
*
|
||||
* You should not use this just to split up arguments that are known to require tokenization up front. The <b>SPLIT:</b> directive works for the entire argument and will not do anything if it is not at the beginning of the argument. Do not use <b>SPLIT:</b> to break up arguments that are fixed, so avoid doing this:
|
||||
*
|
||||
* <pre>
|
||||
* <code>
|
||||
* SPLIT:ls -lih
|
||||
* </code></pre>
|
||||
* </code>
|
||||
* </pre>
|
||||
*
|
||||
* Instead, break the command up explicitly:
|
||||
* <pre><code>
|
||||
*
|
||||
* <pre>
|
||||
* <code>
|
||||
* ls
|
||||
* -lih
|
||||
* </code></pre>
|
||||
* </code>
|
||||
* </pre>
|
||||
*
|
||||
* Tokenization of quoted parameter values is handled by ExecParameterTokenizer, which
|
||||
* describes the support in more detail.
|
||||
* Tokenization of quoted parameter values is handled by ExecParameterTokenizer, which describes the support in more detail.
|
||||
*
|
||||
* @author Derek Hulley
|
||||
*/
|
||||
@@ -123,7 +122,7 @@ public class RuntimeExec
|
||||
private final Timer timer = new Timer(true);
|
||||
|
||||
/**
|
||||
* Default constructor. Initialize this instance by setting individual properties.
|
||||
* Default constructor. Initialize this instance by setting individual properties.
|
||||
*/
|
||||
public RuntimeExec()
|
||||
{
|
||||
@@ -151,15 +150,16 @@ public class RuntimeExec
|
||||
sb.append("\n");
|
||||
}
|
||||
sb.append(" env props: ").append(Arrays.toString(processProperties)).append("\n")
|
||||
.append(" dir: ").append(processDirectory).append("\n")
|
||||
.append(" os: ").append(System.getProperty(KEY_OS_NAME)).append("\n");
|
||||
.append(" dir: ").append(processDirectory).append("\n")
|
||||
.append(" os: ").append(System.getProperty(KEY_OS_NAME)).append("\n");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the command to execute regardless of operating system
|
||||
*
|
||||
* @param command an array of strings representing the command (first entry) and arguments
|
||||
* @param command
|
||||
* an array of strings representing the command (first entry) and arguments
|
||||
* @since 3.0
|
||||
*/
|
||||
public void setCommand(String[] command)
|
||||
@@ -168,11 +168,12 @@ public class RuntimeExec
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the assumed charset of OUT and ERR streams generated by the executed command.
|
||||
* This defaults to the system default charset: {@link Charset#defaultCharset()}.
|
||||
* Sets the assumed charset of OUT and ERR streams generated by the executed command. This defaults to the system default charset: {@link Charset#defaultCharset()}.
|
||||
*
|
||||
* @param charsetCode a supported character set code
|
||||
* @throws UnsupportedCharsetException if the characterset code is not recognised by Java
|
||||
* @param charsetCode
|
||||
* a supported character set code
|
||||
* @throws UnsupportedCharsetException
|
||||
* if the characterset code is not recognised by Java
|
||||
*/
|
||||
public void setCharset(String charsetCode)
|
||||
{
|
||||
@@ -180,14 +181,10 @@ public class RuntimeExec
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to wait for completion of the command or not. If there is no wait for completion,
|
||||
* then the return value of <i>out</i> and <i>err</i> buffers cannot be relied upon as the
|
||||
* command may still be in progress. Failure is therefore not possible unless the calling thread
|
||||
* waits for execution.
|
||||
* Set whether to wait for completion of the command or not. If there is no wait for completion, then the return value of <i>out</i> and <i>err</i> buffers cannot be relied upon as the command may still be in progress. Failure is therefore not possible unless the calling thread waits for execution.
|
||||
*
|
||||
* @param waitForCompletion <tt>true</tt> (default) is to wait for the command to exit,
|
||||
* or <tt>false</tt> to just return an exit code of 0 and whatever
|
||||
* output is available at that point.
|
||||
* @param waitForCompletion
|
||||
* <tt>true</tt> (default) is to wait for the command to exit, or <tt>false</tt> to just return an exit code of 0 and whatever output is available at that point.
|
||||
* @since 2.1
|
||||
*/
|
||||
public void setWaitForCompletion(boolean waitForCompletion)
|
||||
@@ -196,26 +193,17 @@ public class RuntimeExec
|
||||
}
|
||||
|
||||
/**
|
||||
* Supply a choice of commands to execute based on a mapping from the <i>os.name</i> system
|
||||
* property to the command to execute. The {@link #KEY_OS_DEFAULT *} key can be used
|
||||
* to get a command where there is not direct match to the operating system key.
|
||||
* Supply a choice of commands to execute based on a mapping from the <i>os.name</i> system property to the command to execute. The {@link #KEY_OS_DEFAULT *} key can be used to get a command where there is not direct match to the operating system key.
|
||||
* <p>
|
||||
* Each command is an array of strings, the first of which represents the command and all subsequent
|
||||
* entries in the array represent the arguments. All elements of the array will be checked for
|
||||
* the presence of any substitution parameters (e.g. '{dir}'). The parameters can be set using the
|
||||
* {@link #setDefaultProperties(Map) defaults} or by passing the substitution values into the
|
||||
* {@link #execute(Map)} command.
|
||||
* Each command is an array of strings, the first of which represents the command and all subsequent entries in the array represent the arguments. All elements of the array will be checked for the presence of any substitution parameters (e.g. '{dir}'). The parameters can be set using the {@link #setDefaultProperties(Map) defaults} or by passing the substitution values into the {@link #execute(Map)} command.
|
||||
* <p>
|
||||
* If parameters passed may be multiple arguments, or if the values provided in the map are themselves
|
||||
* collections of arguments (not recommended), then prefix the value with <b>SPLIT:</b> to ensure that
|
||||
* the value is tokenized before being passed to the command. Any values that are not split, will be
|
||||
* passed to the command as single arguments. For example:<br>
|
||||
* If parameters passed may be multiple arguments, or if the values provided in the map are themselves collections of arguments (not recommended), then prefix the value with <b>SPLIT:</b> to ensure that the value is tokenized before being passed to the command. Any values that are not split, will be passed to the command as single arguments. For example:<br>
|
||||
* '<b>SPLIT: dir . ..</b>' becomes '<b>dir</b>', '<b>.</b>' and '<b>..</b>'.<br>
|
||||
* '<b>SPLIT: dir ${path}</b>' (if path is '<b>. ..</b>') becomes '<b>dir</b>', '<b>.</b>' and '<b>..</b>'.<br>
|
||||
* The splitting occurs post-subtitution. Where the arguments are known, it is advisable to avoid
|
||||
* <b>SPLIT:</b>.
|
||||
* The splitting occurs post-subtitution. Where the arguments are known, it is advisable to avoid <b>SPLIT:</b>.
|
||||
*
|
||||
* @param commandsByOS a map of command string arrays, keyed by operating system names
|
||||
* @param commandsByOS
|
||||
* a map of command string arrays, keyed by operating system names
|
||||
* @see #setDefaultProperties(Map)
|
||||
* @since 3.0
|
||||
*/
|
||||
@@ -230,7 +218,7 @@ public class RuntimeExec
|
||||
// go through the commands keys, looking for one that matches by regular expression matching
|
||||
for (String osName : commandsByOS.keySet())
|
||||
{
|
||||
// Ignore * options. It is dealt with later.
|
||||
// Ignore * options. It is dealt with later.
|
||||
if (osName.equals(KEY_OS_DEFAULT))
|
||||
{
|
||||
continue;
|
||||
@@ -252,26 +240,25 @@ public class RuntimeExec
|
||||
if (command == null)
|
||||
{
|
||||
throw new RuntimeException(
|
||||
"No command found for OS " + serverOs + " or '" + KEY_OS_DEFAULT + "': \n" +
|
||||
" commands: " + commandsByOS);
|
||||
"No command found for OS " + serverOs + " or '" + KEY_OS_DEFAULT + "': \n" +
|
||||
" commands: " + commandsByOS);
|
||||
}
|
||||
this.command = command;
|
||||
}
|
||||
|
||||
/**
|
||||
* Supply a choice of commands to execute based on a mapping from the <i>os.name</i> system
|
||||
* property to the command to execute. The {@link #KEY_OS_DEFAULT *} key can be used
|
||||
* to get a command where there is not direct match to the operating system key.
|
||||
* Supply a choice of commands to execute based on a mapping from the <i>os.name</i> system property to the command to execute. The {@link #KEY_OS_DEFAULT *} key can be used to get a command where there is not direct match to the operating system key.
|
||||
*
|
||||
* @param commandsByOS a map of command string keyed by operating system names
|
||||
* @param commandsByOS
|
||||
* a map of command string keyed by operating system names
|
||||
* @deprecated Use {@link #setCommandsAndArguments(Map)}
|
||||
*/
|
||||
public void setCommandMap(Map<String, String> commandsByOS)
|
||||
{
|
||||
// This is deprecated, so issue a warning
|
||||
logger.warn(
|
||||
"The bean RuntimeExec property 'commandMap' has been deprecated;" +
|
||||
" use 'commandsAndArguments' instead. See https://issues.alfresco.com/jira/browse/ETHREEOH-579.");
|
||||
"The bean RuntimeExec property 'commandMap' has been deprecated;" +
|
||||
" use 'commandsAndArguments' instead. See https://issues.alfresco.com/jira/browse/ETHREEOH-579.");
|
||||
Map<String, String[]> fixed = new LinkedHashMap<>();
|
||||
for (Map.Entry<String, String> entry : commandsByOS.entrySet())
|
||||
{
|
||||
@@ -289,14 +276,12 @@ public class RuntimeExec
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default command-line properties to use when executing the command.
|
||||
* These are properties that substitute variables defined in the command string itself.
|
||||
* Properties supplied during execution will overwrite the default properties.
|
||||
* Set the default command-line properties to use when executing the command. These are properties that substitute variables defined in the command string itself. Properties supplied during execution will overwrite the default properties.
|
||||
* <p>
|
||||
* <code>null</code> properties will be treated as an empty string for substitution
|
||||
* purposes.
|
||||
* <code>null</code> properties will be treated as an empty string for substitution purposes.
|
||||
*
|
||||
* @param defaultProperties property values
|
||||
* @param defaultProperties
|
||||
* property values
|
||||
*/
|
||||
public void setDefaultProperties(Map<String, String> defaultProperties)
|
||||
{
|
||||
@@ -304,14 +289,12 @@ public class RuntimeExec
|
||||
}
|
||||
|
||||
/**
|
||||
* Set additional runtime properties (environment properties) that will used
|
||||
* by the executing process.
|
||||
* Set additional runtime properties (environment properties) that will used by the executing process.
|
||||
* <p>
|
||||
* Any keys or properties that start and end with <b>${...}</b> will be removed on the assumption
|
||||
* that these are unset properties. <tt>null</tt> values are translated to empty strings.
|
||||
* All keys and values are trimmed of leading and trailing whitespace.
|
||||
* Any keys or properties that start and end with <b>${...}</b> will be removed on the assumption that these are unset properties. <tt>null</tt> values are translated to empty strings. All keys and values are trimmed of leading and trailing whitespace.
|
||||
*
|
||||
* @param processProperties Runtime process properties
|
||||
* @param processProperties
|
||||
* Runtime process properties
|
||||
* @see Runtime#exec(String, String[], java.io.File)
|
||||
*/
|
||||
public void setProcessProperties(Map<String, String> processProperties)
|
||||
@@ -368,13 +351,12 @@ public class RuntimeExec
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a property to existed processProperties.
|
||||
* Property should not be null or empty.
|
||||
* If property with the same value already exists then no change is made.
|
||||
* If property exists with a different value then old value is replaced with the new one.
|
||||
* Adds a property to existed processProperties. Property should not be null or empty. If property with the same value already exists then no change is made. If property exists with a different value then old value is replaced with the new one.
|
||||
*
|
||||
* @param name - property name
|
||||
* @param value - property value
|
||||
* @param name
|
||||
* - property name
|
||||
* @param value
|
||||
* - property value
|
||||
*/
|
||||
public void setProcessProperty(String name, String value)
|
||||
{
|
||||
@@ -424,10 +406,10 @@ public class RuntimeExec
|
||||
/**
|
||||
* Set the runtime location from which the command is executed.
|
||||
* <p>
|
||||
* If the value is an unsubsititued variable (<b>${...}</b>) then it is ignored.
|
||||
* If the location is not visible at the time of setting, a warning is issued only.
|
||||
* If the value is an unsubsititued variable (<b>${...}</b>) then it is ignored. If the location is not visible at the time of setting, a warning is issued only.
|
||||
*
|
||||
* @param processDirectory the runtime location from which to execute the command
|
||||
* @param processDirectory
|
||||
* the runtime location from which to execute the command
|
||||
*/
|
||||
public void setProcessDirectory(String processDirectory)
|
||||
{
|
||||
@@ -441,17 +423,18 @@ public class RuntimeExec
|
||||
if (!this.processDirectory.exists())
|
||||
{
|
||||
logger.warn(
|
||||
"The runtime process directory is not visible when setting property " +
|
||||
"'processDirectory': \n{}", this);
|
||||
"The runtime process directory is not visible when setting property " +
|
||||
"'processDirectory': \n{}",
|
||||
this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A comma or space separated list of values that, if returned by the executed command,
|
||||
* indicate an error value. This defaults to <b>"1, 2"</b>.
|
||||
* A comma or space separated list of values that, if returned by the executed command, indicate an error value. This defaults to <b>"1, 2"</b>.
|
||||
*
|
||||
* @param errCodesStr the error codes for the execution
|
||||
* @param errCodesStr
|
||||
* the error codes for the execution
|
||||
*/
|
||||
public void setErrorCodes(String errCodesStr)
|
||||
{
|
||||
@@ -469,7 +452,7 @@ public class RuntimeExec
|
||||
catch (NumberFormatException e)
|
||||
{
|
||||
throw new RuntimeException(
|
||||
"Property 'errorCodes' must be comma-separated list of integers: " + errCodesStr);
|
||||
"Property 'errorCodes' must be comma-separated list of integers: " + errCodesStr);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -487,9 +470,8 @@ public class RuntimeExec
|
||||
/**
|
||||
* Executes the statement that this instance was constructed with.
|
||||
*
|
||||
* @param properties the properties that the command might be executed with.
|
||||
* <code>null</code> properties will be treated as an empty string for substitution
|
||||
* purposes.
|
||||
* @param properties
|
||||
* the properties that the command might be executed with. <code>null</code> properties will be treated as an empty string for substitution purposes.
|
||||
* @return Returns the full execution results
|
||||
*/
|
||||
public ExecutionResult execute(Map<String, String> properties)
|
||||
@@ -498,15 +480,12 @@ public class RuntimeExec
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the statement that this instance was constructed with an optional
|
||||
* timeout after which the command is asked to
|
||||
* Executes the statement that this instance was constructed with an optional timeout after which the command is asked to
|
||||
*
|
||||
* @param properties the properties that the command might be executed with.
|
||||
* <code>null</code> properties will be treated as an empty string for substitution
|
||||
* purposes.
|
||||
* @param timeoutMs a timeout after which {@link Process#destroy()} is called.
|
||||
* ignored if less than or equal to zero. Note this method does not guarantee
|
||||
* to terminate the process (it is not a kill -9).
|
||||
* @param properties
|
||||
* the properties that the command might be executed with. <code>null</code> properties will be treated as an empty string for substitution purposes.
|
||||
* @param timeoutMs
|
||||
* a timeout after which {@link Process#destroy()} is called. ignored if less than or equal to zero. Note this method does not guarantee to terminate the process (it is not a kill -9).
|
||||
* @return Returns the full execution results
|
||||
*/
|
||||
public ExecutionResult execute(Map<String, String> properties, final long timeoutMs)
|
||||
@@ -528,13 +507,12 @@ public class RuntimeExec
|
||||
// execute the command with full property replacement
|
||||
commandToExecute = getCommand(properties);
|
||||
final Process thisProcess = runtime.exec(commandToExecute, processProperties,
|
||||
processDirectory);
|
||||
processDirectory);
|
||||
process = thisProcess;
|
||||
if (timeoutMs > 0)
|
||||
{
|
||||
final String[] command = commandToExecute;
|
||||
timer.schedule(new TimerTask()
|
||||
{
|
||||
timer.schedule(new TimerTask() {
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
@@ -546,8 +524,8 @@ public class RuntimeExec
|
||||
catch (IllegalThreadStateException stillRunning)
|
||||
{
|
||||
logger.debug(
|
||||
"Process has taken too long ({} seconds). Killing process {}",
|
||||
timeoutMs / 1000, Arrays.deepToString(command));
|
||||
"Process has taken too long ({} seconds). Killing process {}",
|
||||
timeoutMs / 1000, Arrays.deepToString(command));
|
||||
}
|
||||
}
|
||||
}, timeoutMs);
|
||||
@@ -559,16 +537,16 @@ public class RuntimeExec
|
||||
String execOut = "";
|
||||
String execErr = e.getMessage();
|
||||
ExecutionResult result = new ExecutionResult(null, commandToExecute, errCodes,
|
||||
defaultFailureExitValue, execOut, execErr);
|
||||
defaultFailureExitValue, execOut, execErr);
|
||||
logFullEnvironmentDump(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
// create the stream gobblers
|
||||
InputStreamReaderThread stdOutGobbler = new InputStreamReaderThread(
|
||||
process.getInputStream(), charset);
|
||||
process.getInputStream(), charset);
|
||||
InputStreamReaderThread stdErrGobbler = new InputStreamReaderThread(
|
||||
process.getErrorStream(), charset);
|
||||
process.getErrorStream(), charset);
|
||||
|
||||
// start gobbling
|
||||
stdOutGobbler.start();
|
||||
@@ -603,7 +581,7 @@ public class RuntimeExec
|
||||
|
||||
// construct the return value
|
||||
ExecutionResult result = new ExecutionResult(process, commandToExecute, errCodes, exitValue,
|
||||
execOut, execErr);
|
||||
execOut, execErr);
|
||||
|
||||
// done
|
||||
logFullEnvironmentDump(result);
|
||||
@@ -646,12 +624,11 @@ public class RuntimeExec
|
||||
}
|
||||
logger.debug("Result: " + result.toString());
|
||||
|
||||
// close output stream (connected to input stream of native subprocess)
|
||||
// close output stream (connected to input stream of native subprocess)
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the command that will be executed if no additional properties
|
||||
* were to be supplied
|
||||
* @return Returns the command that will be executed if no additional properties were to be supplied
|
||||
*/
|
||||
public String[] getCommand()
|
||||
{
|
||||
@@ -661,12 +638,11 @@ public class RuntimeExec
|
||||
/**
|
||||
* Get the command that will be executed post substitution.
|
||||
* <p>
|
||||
* <code>null</code> properties will be treated as an empty string for substitution
|
||||
* purposes.
|
||||
* <code>null</code> properties will be treated as an empty string for substitution purposes.
|
||||
*
|
||||
* @param properties the properties that the command might be executed with
|
||||
* @return Returns the command that will be executed should the additional properties
|
||||
* be supplied
|
||||
* @param properties
|
||||
* the properties that the command might be executed with
|
||||
* @return Returns the command that will be executed should the additional properties be supplied
|
||||
*/
|
||||
public String[] getCommand(Map<String, String> properties)
|
||||
{
|
||||
@@ -715,7 +691,7 @@ public class RuntimeExec
|
||||
|
||||
// There may be quoted arguments here (see ALF-7482)
|
||||
ExecParameterTokenizer quoteAwareTokenizer = new ExecParameterTokenizer(
|
||||
unsplitAdjustedValue);
|
||||
unsplitAdjustedValue);
|
||||
List<String> tokens = quoteAwareTokenizer.getAllTokens();
|
||||
adjustedCommandElements.addAll(tokens);
|
||||
}
|
||||
@@ -743,15 +719,16 @@ public class RuntimeExec
|
||||
private final String stdErr;
|
||||
|
||||
/**
|
||||
* @param process the process attached to Java - <tt>null</tt> is allowed
|
||||
* @param process
|
||||
* the process attached to Java - <tt>null</tt> is allowed
|
||||
*/
|
||||
private ExecutionResult(
|
||||
final Process process,
|
||||
final String[] command,
|
||||
final Set<Integer> errCodes,
|
||||
final int exitValue,
|
||||
final String stdOut,
|
||||
final String stdErr)
|
||||
final Process process,
|
||||
final String[] command,
|
||||
final Set<Integer> errCodes,
|
||||
final int exitValue,
|
||||
final String stdOut,
|
||||
final String stdErr)
|
||||
{
|
||||
this.process = process;
|
||||
this.command = command;
|
||||
@@ -769,20 +746,18 @@ public class RuntimeExec
|
||||
|
||||
StringBuilder sb = new StringBuilder(128);
|
||||
sb.append("Execution result: \n")
|
||||
.append(" os: ").append(System.getProperty(KEY_OS_NAME)).append("\n")
|
||||
.append(" command: ");
|
||||
.append(" os: ").append(System.getProperty(KEY_OS_NAME)).append("\n")
|
||||
.append(" command: ");
|
||||
appendCommand(sb, command).append("\n")
|
||||
.append(" succeeded: ").append(getSuccess()).append("\n")
|
||||
.append(" exit code: ").append(exitValue).append("\n")
|
||||
.append(" out: ").append(out).append("\n")
|
||||
.append(" err: ").append(err);
|
||||
.append(" succeeded: ").append(getSuccess()).append("\n")
|
||||
.append(" exit code: ").append(exitValue).append("\n")
|
||||
.append(" out: ").append(out).append("\n")
|
||||
.append(" err: ").append(err);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the command in a form that make running from the command line simpler.
|
||||
* It is not a real attempt at making a command given all the operating system
|
||||
* and shell options, but makes copy, paste and edit a bit simpler.
|
||||
* Appends the command in a form that make running from the command line simpler. It is not a real attempt at making a command given all the operating system and shell options, but makes copy, paste and edit a bit simpler.
|
||||
*/
|
||||
private StringBuilder appendCommand(StringBuilder sb, String[] command)
|
||||
{
|
||||
@@ -818,10 +793,7 @@ public class RuntimeExec
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper method to force a kill of the process that generated this result. This is
|
||||
* useful in cases where the process started is not expected to exit, or doesn't exit
|
||||
* quickly. If the {@linkplain RuntimeExec#setWaitForCompletion(boolean) "wait for completion"}
|
||||
* flag is <tt>false</tt> then the process may still be running when this result is returned.
|
||||
* A helper method to force a kill of the process that generated this result. This is useful in cases where the process started is not expected to exit, or doesn't exit quickly. If the {@linkplain RuntimeExec#setWaitForCompletion(boolean) "wait for completion"} flag is <tt>false</tt> then the process may still be running when this result is returned.
|
||||
*
|
||||
* @return <tt>true</tt> if the process was killed, otherwise <tt>false</tt>
|
||||
*/
|
||||
@@ -844,7 +816,8 @@ public class RuntimeExec
|
||||
}
|
||||
|
||||
/**
|
||||
* @param exitValue the command exit value
|
||||
* @param exitValue
|
||||
* the command exit value
|
||||
* @return Returns true if the code is a listed failure code
|
||||
* @see #setErrorCodes(String)
|
||||
*/
|
||||
@@ -854,8 +827,7 @@ public class RuntimeExec
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns true if the command was deemed to be successful according to the
|
||||
* failure codes returned by the execution.
|
||||
* @return Returns true if the command was deemed to be successful according to the failure codes returned by the execution.
|
||||
*/
|
||||
public boolean getSuccess()
|
||||
{
|
||||
@@ -879,8 +851,7 @@ public class RuntimeExec
|
||||
}
|
||||
|
||||
/**
|
||||
* Gobbles an <code>InputStream</code> and writes it into a
|
||||
* <code>StringBuffer</code>
|
||||
* Gobbles an <code>InputStream</code> and writes it into a <code>StringBuffer</code>
|
||||
* <p>
|
||||
* The reading of the input stream is buffered.
|
||||
*/
|
||||
@@ -888,12 +859,12 @@ public class RuntimeExec
|
||||
{
|
||||
private final InputStream is;
|
||||
private final Charset charset;
|
||||
private final StringBuffer buffer; // we require the synchronization
|
||||
private final StringBuffer buffer; // we require the synchronization
|
||||
private boolean completed;
|
||||
|
||||
/**
|
||||
* @param is an input stream to read - it will be wrapped in a buffer
|
||||
* for reading
|
||||
* @param is
|
||||
* an input stream to read - it will be wrapped in a buffer for reading
|
||||
*/
|
||||
public InputStreamReaderThread(InputStream is, Charset charset)
|
||||
{
|
||||
@@ -935,7 +906,7 @@ public class RuntimeExec
|
||||
// The thread has finished consuming the stream
|
||||
completed = true;
|
||||
// Notify waiters
|
||||
this.notifyAll(); // Note: Method is synchronized
|
||||
this.notifyAll(); // Note: Method is synchronized
|
||||
}
|
||||
}
|
||||
|
||||
@@ -954,13 +925,13 @@ public class RuntimeExec
|
||||
this.wait(1000L); // 200 ms
|
||||
}
|
||||
catch (InterruptedException ignore)
|
||||
{
|
||||
}
|
||||
{}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param msg the message to add to the buffer
|
||||
* @param msg
|
||||
* the message to add to the buffer
|
||||
*/
|
||||
public void addToBuffer(String msg)
|
||||
{
|
||||
@@ -981,4 +952,3 @@ public class RuntimeExec
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -26,15 +26,16 @@
|
||||
*/
|
||||
package org.alfresco.transform.base.html;
|
||||
|
||||
import org.alfresco.transform.config.TransformOption;
|
||||
import org.alfresco.transform.config.TransformOptionGroup;
|
||||
import org.alfresco.transform.config.TransformOptionValue;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import org.alfresco.transform.config.TransformOption;
|
||||
import org.alfresco.transform.config.TransformOptionGroup;
|
||||
import org.alfresco.transform.config.TransformOptionValue;
|
||||
|
||||
/**
|
||||
* Used in the html test page, which provides a list of known transform option names.
|
||||
*/
|
||||
@@ -42,14 +43,12 @@ import java.util.TreeSet;
|
||||
public class OptionsHelper
|
||||
{
|
||||
private OptionsHelper()
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
public static Set<String> getOptionNames(Map<String, Set<TransformOption>> transformOptionsByName)
|
||||
{
|
||||
Set<String> set = new TreeSet<>();
|
||||
transformOptionsByName.forEach(((optionName, optionSet) ->
|
||||
optionSet.stream().forEach(option -> addOption(set, option))));
|
||||
transformOptionsByName.forEach(((optionName, optionSet) -> optionSet.stream().forEach(option -> addOption(set, option))));
|
||||
return set;
|
||||
}
|
||||
|
||||
@@ -57,11 +56,11 @@ public class OptionsHelper
|
||||
{
|
||||
if (option instanceof TransformOptionGroup)
|
||||
{
|
||||
addGroup(set, (TransformOptionGroup)option);
|
||||
addGroup(set, (TransformOptionGroup) option);
|
||||
}
|
||||
else
|
||||
{
|
||||
addValue(set, (TransformOptionValue)option);
|
||||
addValue(set, (TransformOptionValue) option);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -42,7 +42,7 @@ public class TransformInterceptor implements AsyncHandlerInterceptor
|
||||
{
|
||||
@Override
|
||||
public void afterCompletion(HttpServletRequest request,
|
||||
HttpServletResponse response, Object handler, Exception ex)
|
||||
HttpServletResponse response, Object handler, Exception ex)
|
||||
{
|
||||
deleteFile(request, SOURCE_FILE);
|
||||
deleteFile(request, TARGET_FILE);
|
||||
|
@@ -26,10 +26,9 @@
|
||||
*/
|
||||
package org.alfresco.transform.base.logging;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import static java.lang.Math.max;
|
||||
|
||||
import static org.springframework.http.HttpStatus.OK;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Collection;
|
||||
@@ -38,14 +37,13 @@ import java.util.Deque;
|
||||
import java.util.concurrent.ConcurrentLinkedDeque;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import static java.lang.Math.max;
|
||||
import static org.springframework.http.HttpStatus.OK;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
/**
|
||||
* Provides setter and getter methods to allow the current Thread to set various log properties and for these
|
||||
* values to be retrieved. The {@link #complete()} method should be called at the end of a request to flush the
|
||||
* current entry to an internal log Collection of the latest entries. The {@link #getLog()} method is used to obtain
|
||||
* access to this collection.
|
||||
* Provides setter and getter methods to allow the current Thread to set various log properties and for these values to be retrieved. The {@link #complete()} method should be called at the end of a request to flush the current entry to an internal log Collection of the latest entries. The {@link #getLog()} method is used to obtain access to this collection.
|
||||
*/
|
||||
public final class LogEntry
|
||||
{
|
||||
@@ -166,7 +164,7 @@ public final class LogEntry
|
||||
if (logEntry.statusCode == OK.value())
|
||||
{
|
||||
logEntry.durationStreamOut = System.currentTimeMillis() - logEntry.start -
|
||||
logEntry.durationStreamIn - max(logEntry.durationTransform, 0);
|
||||
logEntry.durationStreamIn - max(logEntry.durationTransform, 0);
|
||||
}
|
||||
currentLogEntry.remove();
|
||||
|
||||
@@ -195,13 +193,14 @@ public final class LogEntry
|
||||
{
|
||||
long duration = durationStreamIn + max(durationTransform, 0) + max(durationStreamOut, 0);
|
||||
return duration <= 5
|
||||
? ""
|
||||
: time(duration) +
|
||||
" (" +
|
||||
(time(durationStreamIn) + ' ' +
|
||||
time(durationTransform) + ' ' +
|
||||
time(durationStreamOut)).trim() +
|
||||
")";
|
||||
? ""
|
||||
: time(duration) +
|
||||
" (" +
|
||||
(time(durationStreamIn) + ' ' +
|
||||
time(durationTransform) + ' ' +
|
||||
time(durationStreamOut)).trim()
|
||||
+
|
||||
")";
|
||||
}
|
||||
|
||||
public String getSource()
|
||||
@@ -236,16 +235,18 @@ public final class LogEntry
|
||||
|
||||
private String time(long ms)
|
||||
{
|
||||
return ms == -1 ? "" : size(ms, "1ms",
|
||||
new String[]{"ms", "s", "min", "hr"},
|
||||
new long[]{1000, 60 * 1000, 60 * 60 * 1000, Long.MAX_VALUE});
|
||||
return ms == -1 ? ""
|
||||
: size(ms, "1ms",
|
||||
new String[]{"ms", "s", "min", "hr"},
|
||||
new long[]{1000, 60 * 1000, 60 * 60 * 1000, Long.MAX_VALUE});
|
||||
}
|
||||
|
||||
private String size(long size)
|
||||
{
|
||||
return size == -1 ? "" : size(size, "1 byte",
|
||||
new String[]{"bytes", " KB", " MB", " GB", " TB"},
|
||||
new long[]{1024, 1024 * 1024, 1024 * 1024 * 1024, 1024L * 1024 * 1024 * 1024, Long.MAX_VALUE});
|
||||
return size == -1 ? ""
|
||||
: size(size, "1 byte",
|
||||
new String[]{"bytes", " KB", " MB", " GB", " TB"},
|
||||
new long[]{1024, 1024 * 1024, 1024 * 1024 * 1024, 1024L * 1024 * 1024 * 1024, Long.MAX_VALUE});
|
||||
}
|
||||
|
||||
private String size(long size, String singleValue, String[] units, long[] dividers)
|
||||
|
@@ -29,19 +29,16 @@ package org.alfresco.transform.base.logging;
|
||||
public final class StandardMessages
|
||||
{
|
||||
private StandardMessages()
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
public static String COMMUNITY_LICENCE =
|
||||
"If the Alfresco software was purchased under a paid Alfresco license, the terms of the paid license agreement \n" +
|
||||
"will prevail. Otherwise, the software is provided under terms of the GNU LGPL v3 license. \n" +
|
||||
"See the license at http://www.gnu.org/licenses/lgpl-3.0.txt. or in /LICENSE.txt \n\n";
|
||||
public static String COMMUNITY_LICENCE = "If the Alfresco software was purchased under a paid Alfresco license, the terms of the paid license agreement \n" +
|
||||
"will prevail. Otherwise, the software is provided under terms of the GNU LGPL v3 license. \n" +
|
||||
"See the license at http://www.gnu.org/licenses/lgpl-3.0.txt. or in /LICENSE.txt \n\n";
|
||||
|
||||
public static String ENTERPRISE_LICENCE =
|
||||
"This image is only intended to be used with the Alfresco Enterprise Content Repository which is covered by\n" +
|
||||
"https://www.alfresco.com/legal/agreements and https://www.alfresco.com/terms-use\n" +
|
||||
"\n" +
|
||||
"License rights for this program may be obtained from Alfresco Software, Ltd. pursuant to a written agreement\n" +
|
||||
"and any use of this program without such an agreement is prohibited.\n" +
|
||||
"\n";
|
||||
public static String ENTERPRISE_LICENCE = "This image is only intended to be used with the Alfresco Enterprise Content Repository which is covered by\n" +
|
||||
"https://www.alfresco.com/legal/agreements and https://www.alfresco.com/terms-use\n" +
|
||||
"\n" +
|
||||
"License rights for this program may be obtained from Alfresco Software, Ltd. pursuant to a written agreement\n" +
|
||||
"and any use of this program without such an agreement is prohibited.\n" +
|
||||
"\n";
|
||||
}
|
||||
|
@@ -26,7 +26,9 @@
|
||||
*/
|
||||
package org.alfresco.transform.base.messaging;
|
||||
|
||||
import org.alfresco.transform.messages.TransformRequestValidator;
|
||||
import jakarta.jms.ConnectionFactory;
|
||||
import jakarta.jms.Queue;
|
||||
|
||||
import org.apache.activemq.command.ActiveMQQueue;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
@@ -40,15 +42,12 @@ import org.springframework.lang.NonNull;
|
||||
import org.springframework.messaging.handler.annotation.support.DefaultMessageHandlerMethodFactory;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
|
||||
import jakarta.jms.ConnectionFactory;
|
||||
import jakarta.jms.Queue;
|
||||
import org.alfresco.transform.messages.TransformRequestValidator;
|
||||
|
||||
/**
|
||||
* JMS and messaging configuration for the T-Engines. Contains the basic config in order to have the
|
||||
* T-Engine able to read from queues and send a reply back.
|
||||
* JMS and messaging configuration for the T-Engines. Contains the basic config in order to have the T-Engine able to read from queues and send a reply back.
|
||||
*
|
||||
* @author Lucian Tuca
|
||||
* created on 18/12/2018
|
||||
* @author Lucian Tuca created on 18/12/2018
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnProperty(name = "activemq.url")
|
||||
@@ -70,9 +69,9 @@ public class MessagingConfig implements JmsListenerConfigurer
|
||||
|
||||
@Bean
|
||||
public DefaultJmsListenerContainerFactory jmsListenerContainerFactory(
|
||||
final ConnectionFactory connectionFactory,
|
||||
final TransformMessageConverter transformMessageConverter,
|
||||
final MessagingErrorHandler messagingErrorHandler)
|
||||
final ConnectionFactory connectionFactory,
|
||||
final TransformMessageConverter transformMessageConverter,
|
||||
final MessagingErrorHandler messagingErrorHandler)
|
||||
{
|
||||
final DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
|
||||
factory.setConnectionFactory(connectionFactory);
|
||||
@@ -92,10 +91,8 @@ public class MessagingConfig implements JmsListenerConfigurer
|
||||
|
||||
@Bean
|
||||
public Queue engineRequestQueue(
|
||||
@Value("${queue.engineRequestQueue}") String engineRequestQueueValue)
|
||||
@Value("${queue.engineRequestQueue}") String engineRequestQueueValue)
|
||||
{
|
||||
return new ActiveMQQueue(engineRequestQueueValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@@ -55,7 +55,7 @@ public class MessagingInfo
|
||||
// Note: as per application.yaml the broker url is appended with "?jms.watchTopicAdvisories=false". If this needs to be fully
|
||||
// overridden then it would require explicitly setting both "spring.activemq.broker-url" *and* "activemq.url" (latter to non-false value).
|
||||
|
||||
if ((activemqUrl != null) && (! activemqUrl.equals("false")))
|
||||
if ((activemqUrl != null) && (!activemqUrl.equals("false")))
|
||||
{
|
||||
logger.info("JMS client is ENABLED - ACTIVEMQ_URL ='{}'", activemqUrl);
|
||||
}
|
||||
|
@@ -26,10 +26,14 @@
|
||||
*/
|
||||
package org.alfresco.transform.base.messaging;
|
||||
|
||||
import org.alfresco.transform.base.TransformController;
|
||||
import org.alfresco.transform.client.model.TransformReply;
|
||||
import org.alfresco.transform.client.model.TransformRequest;
|
||||
import org.alfresco.transform.exceptions.TransformException;
|
||||
import static org.springframework.http.HttpStatus.BAD_REQUEST;
|
||||
import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR;
|
||||
|
||||
import java.util.Optional;
|
||||
import jakarta.jms.Destination;
|
||||
import jakarta.jms.JMSException;
|
||||
import jakarta.jms.Message;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -39,22 +43,15 @@ import org.springframework.jms.annotation.JmsListener;
|
||||
import org.springframework.jms.support.converter.MessageConversionException;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import jakarta.jms.Destination;
|
||||
import jakarta.jms.JMSException;
|
||||
import jakarta.jms.Message;
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.springframework.http.HttpStatus.BAD_REQUEST;
|
||||
import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR;
|
||||
import org.alfresco.transform.base.TransformController;
|
||||
import org.alfresco.transform.client.model.TransformReply;
|
||||
import org.alfresco.transform.client.model.TransformRequest;
|
||||
import org.alfresco.transform.exceptions.TransformException;
|
||||
|
||||
/**
|
||||
* Queue Transformer service.
|
||||
* This service reads all the requests for the particular engine, forwards them to the worker
|
||||
* component (at this time the injected controller - to be refactored) and sends back the reply
|
||||
* to the {@link Message#getJMSReplyTo()} value. If this value is missing we've got to a dead end.
|
||||
* Queue Transformer service. This service reads all the requests for the particular engine, forwards them to the worker component (at this time the injected controller - to be refactored) and sends back the reply to the {@link Message#getJMSReplyTo()} value. If this value is missing we've got to a dead end.
|
||||
*
|
||||
* @author Lucian Tuca
|
||||
* created on 18/12/2018
|
||||
* @author Lucian Tuca created on 18/12/2018
|
||||
*/
|
||||
@Component
|
||||
@ConditionalOnProperty(name = "activemq.url")
|
||||
@@ -87,16 +84,16 @@ public class QueueTransformService
|
||||
if (replyToQueue == null)
|
||||
{
|
||||
logger.error(
|
||||
"Cannot find 'replyTo' destination queue for message with correlationID {}. Stopping. ",
|
||||
correlationId);
|
||||
"Cannot find 'replyTo' destination queue for message with correlationID {}. Stopping. ",
|
||||
correlationId);
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (JMSException e)
|
||||
{
|
||||
logger.error(
|
||||
"Cannot find 'replyTo' destination queue for message with correlationID {}. Stopping. ",
|
||||
correlationId);
|
||||
"Cannot find 'replyTo' destination queue for message with correlationID {}. Stopping. ",
|
||||
correlationId);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -111,7 +108,7 @@ public class QueueTransformService
|
||||
{
|
||||
logger.error(e.getMessage(), e);
|
||||
replyWithError(replyToQueue, HttpStatus.valueOf(e.getStatus().value()),
|
||||
e.getMessage(), correlationId);
|
||||
e.getMessage(), correlationId);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -119,7 +116,7 @@ public class QueueTransformService
|
||||
{
|
||||
logger.error("T-Request from message with correlationID {} is null!", correlationId);
|
||||
replyWithInternalSvErr(replyToQueue,
|
||||
"JMS exception during T-Request deserialization: ", correlationId);
|
||||
"JMS exception during T-Request deserialization: ", correlationId);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -127,10 +124,10 @@ public class QueueTransformService
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to convert the JMS {@link Message} to a {@link TransformRequest}
|
||||
* If any error occurs, a {@link TransformException} is thrown
|
||||
* Tries to convert the JMS {@link Message} to a {@link TransformRequest} If any error occurs, a {@link TransformException} is thrown
|
||||
*
|
||||
* @param msg Message to be deserialized
|
||||
* @param msg
|
||||
* Message to be deserialized
|
||||
* @return The converted {@link TransformRequest} instance
|
||||
*/
|
||||
private Optional<TransformRequest> convert(final Message msg, String correlationId)
|
||||
@@ -142,42 +139,39 @@ public class QueueTransformService
|
||||
}
|
||||
catch (MessageConversionException e)
|
||||
{
|
||||
String message =
|
||||
"MessageConversionException during T-Request deserialization of message with correlationID "
|
||||
+ correlationId + ": ";
|
||||
String message = "MessageConversionException during T-Request deserialization of message with correlationID "
|
||||
+ correlationId + ": ";
|
||||
throw new TransformException(BAD_REQUEST, message + e.getMessage());
|
||||
}
|
||||
catch (JMSException e)
|
||||
{
|
||||
String message =
|
||||
"JMSException during T-Request deserialization of message with correlationID "
|
||||
+ correlationId + ": ";
|
||||
String message = "JMSException during T-Request deserialization of message with correlationID "
|
||||
+ correlationId + ": ";
|
||||
throw new TransformException(INTERNAL_SERVER_ERROR, message + e.getMessage());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
String message =
|
||||
"Exception during T-Request deserialization of message with correlationID "
|
||||
+ correlationId + ": ";
|
||||
String message = "Exception during T-Request deserialization of message with correlationID "
|
||||
+ correlationId + ": ";
|
||||
throw new TransformException(INTERNAL_SERVER_ERROR, message + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void replyWithInternalSvErr(final Destination destination, final String msg,
|
||||
final String correlationId)
|
||||
final String correlationId)
|
||||
{
|
||||
replyWithError(destination, INTERNAL_SERVER_ERROR, msg, correlationId);
|
||||
}
|
||||
|
||||
private void replyWithError(final Destination replyToQueue, final HttpStatus status,
|
||||
final String msg,
|
||||
final String correlationId)
|
||||
final String msg,
|
||||
final String correlationId)
|
||||
{
|
||||
final TransformReply reply = TransformReply
|
||||
.builder()
|
||||
.withStatus(status.value())
|
||||
.withErrorDetails(msg)
|
||||
.build();
|
||||
.builder()
|
||||
.withStatus(status.value())
|
||||
.withErrorDetails(msg)
|
||||
.build();
|
||||
|
||||
transformReplySender.send(replyToQueue, reply, correlationId);
|
||||
}
|
||||
|
@@ -27,11 +27,13 @@
|
||||
|
||||
package org.alfresco.transform.base.messaging;
|
||||
|
||||
import jakarta.jms.JMSException;
|
||||
import jakarta.jms.Message;
|
||||
import jakarta.jms.Session;
|
||||
|
||||
import com.fasterxml.jackson.databind.JavaType;
|
||||
import com.fasterxml.jackson.databind.type.TypeFactory;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import org.alfresco.transform.client.model.TransformReply;
|
||||
import org.alfresco.transform.client.model.TransformRequest;
|
||||
import org.springframework.jms.support.converter.MappingJackson2MessageConverter;
|
||||
import org.springframework.jms.support.converter.MessageConversionException;
|
||||
import org.springframework.jms.support.converter.MessageConverter;
|
||||
@@ -39,13 +41,11 @@ import org.springframework.jms.support.converter.MessageType;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import jakarta.jms.JMSException;
|
||||
import jakarta.jms.Message;
|
||||
import jakarta.jms.Session;
|
||||
import org.alfresco.transform.client.model.TransformReply;
|
||||
import org.alfresco.transform.client.model.TransformRequest;
|
||||
|
||||
/**
|
||||
* Copied from the t-router. We would need to create a common dependency between t-engine base and t-router that
|
||||
* knows about jms to remove this duplication.
|
||||
* Copied from the t-router. We would need to create a common dependency between t-engine base and t-router that knows about jms to remove this duplication.
|
||||
*
|
||||
* @author Cezar Leahu
|
||||
*/
|
||||
@@ -53,16 +53,13 @@ import jakarta.jms.Session;
|
||||
public class TransformMessageConverter implements MessageConverter
|
||||
{
|
||||
private static final MappingJackson2MessageConverter converter;
|
||||
private static final JavaType TRANSFORM_REQUEST_TYPE =
|
||||
TypeFactory.defaultInstance().constructType(TransformRequest.class);
|
||||
private static final JavaType TRANSFORM_REQUEST_TYPE = TypeFactory.defaultInstance().constructType(TransformRequest.class);
|
||||
|
||||
static
|
||||
{
|
||||
converter = new MappingJackson2MessageConverter()
|
||||
{
|
||||
converter = new MappingJackson2MessageConverter() {
|
||||
@Override
|
||||
@NonNull
|
||||
protected JavaType getJavaTypeForMessage(final Message message) throws JMSException
|
||||
@NonNull protected JavaType getJavaTypeForMessage(final Message message) throws JMSException
|
||||
{
|
||||
if (message.getStringProperty("_type") == null)
|
||||
{
|
||||
@@ -74,23 +71,20 @@ public class TransformMessageConverter implements MessageConverter
|
||||
converter.setTargetType(MessageType.BYTES);
|
||||
converter.setTypeIdPropertyName("_type");
|
||||
converter.setTypeIdMappings(ImmutableMap.of(
|
||||
TransformRequest.class.getName(), TransformRequest.class,
|
||||
TransformReply.class.getName(), TransformReply.class)
|
||||
);
|
||||
TransformRequest.class.getName(), TransformRequest.class,
|
||||
TransformReply.class.getName(), TransformReply.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public Message toMessage(
|
||||
@NonNull final Object object,
|
||||
@NonNull final Session session) throws JMSException, MessageConversionException
|
||||
@NonNull public Message toMessage(
|
||||
@NonNull final Object object,
|
||||
@NonNull final Session session) throws JMSException, MessageConversionException
|
||||
{
|
||||
return converter.toMessage(object, session);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public Object fromMessage(@NonNull final Message message) throws JMSException
|
||||
@NonNull public Object fromMessage(@NonNull final Message message) throws JMSException
|
||||
{
|
||||
return converter.fromMessage(message);
|
||||
}
|
||||
|
@@ -28,13 +28,14 @@ package org.alfresco.transform.base.messaging;
|
||||
|
||||
import jakarta.jms.Destination;
|
||||
|
||||
import org.alfresco.transform.client.model.TransformReply;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.jms.core.JmsTemplate;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import org.alfresco.transform.client.model.TransformReply;
|
||||
|
||||
/**
|
||||
* Copied from the t-router.
|
||||
*
|
||||
|
@@ -26,12 +26,7 @@
|
||||
*/
|
||||
package org.alfresco.transform.base.metadata;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.alfresco.transform.base.CustomTransformer;
|
||||
import org.alfresco.transform.base.TransformManager;
|
||||
import org.slf4j.Logger;
|
||||
import static org.alfresco.transform.base.metadata.AbstractMetadataExtractorEmbedder.Type.EMBEDDER;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
@@ -50,45 +45,38 @@ import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import static org.alfresco.transform.base.metadata.AbstractMetadataExtractorEmbedder.Type.EMBEDDER;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import org.alfresco.transform.base.CustomTransformer;
|
||||
import org.alfresco.transform.base.TransformManager;
|
||||
|
||||
/**
|
||||
* Helper methods for metadata extract and embed.
|
||||
* <p>
|
||||
* <i>Much of the code is based on AbstractMappingMetadataExtracter from the
|
||||
* content repository. The code has been simplified to only set up mapping one way.</i>
|
||||
* <i>Much of the code is based on AbstractMappingMetadataExtracter from the content repository. The code has been simplified to only set up mapping one way.</i>
|
||||
* <p>
|
||||
* If a transform specifies that it can convert from {@code "<MIMETYPE>"} to {@code "alfresco-metadata-extract"}
|
||||
* (specified in the {@code engine_config.json}), it is indicating that it can extract metadata from {@code <MIMETYPE>}.
|
||||
* If a transform specifies that it can convert from {@code "<MIMETYPE>"} to {@code "alfresco-metadata-extract"} (specified in the {@code engine_config.json}), it is indicating that it can extract metadata from {@code <MIMETYPE>}.
|
||||
*
|
||||
* The transform results in a Map of extracted properties encoded as json being returned to the content repository.
|
||||
* <ul>
|
||||
* <li>The method extracts ALL available metadata from the document with
|
||||
* {@link #extractMetadata(String, InputStream, String, OutputStream, Map, TransformManager)} and then calls
|
||||
* {@link #mapMetadataAndWrite(OutputStream, Map, Map)}.</li>
|
||||
* <li>Selected values from the available metadata are mapped into content repository property names and values,
|
||||
* depending on what is defined in a {@code "<classname>_metadata_extract.properties"} file.</li>
|
||||
* <li>The selected values are set back to the content repository as a JSON representation of a Map, where the values
|
||||
* are applied to the source node.</li>
|
||||
* <li>The method extracts ALL available metadata from the document with {@link #extractMetadata(String, InputStream, String, OutputStream, Map, TransformManager)} and then calls {@link #mapMetadataAndWrite(OutputStream, Map, Map)}.</li>
|
||||
* <li>Selected values from the available metadata are mapped into content repository property names and values, depending on what is defined in a {@code "<classname>_metadata_extract.properties"} file.</li>
|
||||
* <li>The selected values are set back to the content repository as a JSON representation of a Map, where the values are applied to the source node.</li>
|
||||
* </ul>
|
||||
* To support the same functionality as metadata extractors configured inside the content repository,
|
||||
* extra key value pairs may be returned from {@link #extractMetadata(String, InputStream, String, OutputStream, Map, TransformManager)}.
|
||||
* These are:
|
||||
* To support the same functionality as metadata extractors configured inside the content repository, extra key value pairs may be returned from {@link #extractMetadata(String, InputStream, String, OutputStream, Map, TransformManager)}. These are:
|
||||
* <ul>
|
||||
* <li>{@code "sys:overwritePolicy"} which can specify the
|
||||
* {@code org.alfresco.repo.content.metadata.MetadataExtracter.OverwritePolicy} name. Defaults to "PRAGMATIC".</li>
|
||||
* <li>{@code "sys:enableStringTagging"} if {@code "true"} finds or creates tags for each string mapped to
|
||||
* {@code cm:taggable}. Defaults to {@code "false"} to ignore mapping strings to tags.</li>
|
||||
* <li>{@code "sys:carryAspectProperties"} </li>
|
||||
* <li>{@code "sys:stringTaggingSeparators"} </li>
|
||||
* <li>{@code "sys:overwritePolicy"} which can specify the {@code org.alfresco.repo.content.metadata.MetadataExtracter.OverwritePolicy} name. Defaults to "PRAGMATIC".</li>
|
||||
* <li>{@code "sys:enableStringTagging"} if {@code "true"} finds or creates tags for each string mapped to {@code cm:taggable}. Defaults to {@code "false"} to ignore mapping strings to tags.</li>
|
||||
* <li>{@code "sys:carryAspectProperties"}</li>
|
||||
* <li>{@code "sys:stringTaggingSeparators"}</li>
|
||||
* </ul>
|
||||
*
|
||||
* If a transform specifies that it can convert from {@code "<MIMETYPE>"} to {@code "alfresco-metadata-embed"}, it is
|
||||
* indicating that it can embed metadata in {@code <MIMETYPE>}.
|
||||
* If a transform specifies that it can convert from {@code "<MIMETYPE>"} to {@code "alfresco-metadata-embed"}, it is indicating that it can embed metadata in {@code <MIMETYPE>}.
|
||||
*
|
||||
* The transform calls {@link #embedMetadata(String, InputStream, String, OutputStream, Map, TransformManager)}
|
||||
* which should results in a new version of supplied source file that contains the metadata supplied in the transform
|
||||
* options.
|
||||
* The transform calls {@link #embedMetadata(String, InputStream, String, OutputStream, Map, TransformManager)} which should results in a new version of supplied source file that contains the metadata supplied in the transform options.
|
||||
*
|
||||
* @author Jesper Steen Møller
|
||||
* @author Derek Hulley
|
||||
@@ -213,7 +201,8 @@ public abstract class AbstractMetadataExtractorEmbedder implements CustomTransfo
|
||||
logger.debug(
|
||||
"Converted system model values to metadata values: \n" +
|
||||
" System Properties: {}\n" +
|
||||
" Metadata Properties: {}", systemMetadata, metadataProperties);
|
||||
" Metadata Properties: {}",
|
||||
systemMetadata, metadataProperties);
|
||||
}
|
||||
return metadataProperties;
|
||||
}
|
||||
@@ -226,9 +215,8 @@ public abstract class AbstractMetadataExtractorEmbedder implements CustomTransfo
|
||||
/**
|
||||
* Based on AbstractMappingMetadataExtracter#getDefaultMapping.
|
||||
*
|
||||
* This method provides a <i>mapping</i> of where to store the values extracted from the documents. The list of
|
||||
* properties need <b>not</b> include all metadata values extracted from the document. This mapping should be
|
||||
* defined in a file based on the class name: {@code "<classname>_metadata_extract.properties"}
|
||||
* This method provides a <i>mapping</i> of where to store the values extracted from the documents. The list of properties need <b>not</b> include all metadata values extracted from the document. This mapping should be defined in a file based on the class name: {@code "<classname>_metadata_extract.properties"}
|
||||
*
|
||||
* @return Returns a static mapping. It may not be null.
|
||||
*/
|
||||
private Map<String, Set<String>> buildExtractMapping()
|
||||
@@ -278,13 +266,10 @@ public abstract class AbstractMetadataExtractorEmbedder implements CustomTransfo
|
||||
/**
|
||||
* Based on AbstractMappingMetadataExtracter#getDefaultEmbedMapping.
|
||||
*
|
||||
* This method provides a <i>mapping</i> of model properties that should be embedded in the content. The list of
|
||||
* properties need <b>not</b> include all properties. This mapping should be defined in a file based on the class
|
||||
* name: {@code "<classname>_metadata_embed.properties"}
|
||||
* This method provides a <i>mapping</i> of model properties that should be embedded in the content. The list of properties need <b>not</b> include all properties. This mapping should be defined in a file based on the class name: {@code "<classname>_metadata_embed.properties"}
|
||||
* <p>
|
||||
* If no {@code "<classname>_metadata_embed.properties"} file is found, a reverse of the
|
||||
* {@code "<classname>_metadata_extract.properties"} will be assumed. A last win approach will be used for handling
|
||||
* duplicates.
|
||||
* If no {@code "<classname>_metadata_embed.properties"} file is found, a reverse of the {@code "<classname>_metadata_extract.properties"} will be assumed. A last win approach will be used for handling duplicates.
|
||||
*
|
||||
* @return Returns a static mapping. It may not be null.
|
||||
*/
|
||||
private Map<String, Set<String>> buildEmbedMapping()
|
||||
@@ -388,8 +373,7 @@ public abstract class AbstractMetadataExtractorEmbedder implements CustomTransfo
|
||||
}
|
||||
}
|
||||
catch (IOException ignore)
|
||||
{
|
||||
}
|
||||
{}
|
||||
return properties;
|
||||
}
|
||||
|
||||
@@ -431,21 +415,21 @@ public abstract class AbstractMetadataExtractorEmbedder implements CustomTransfo
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a value to the map, conserving null values. Values are converted to null if:
|
||||
* Adds a value to the map, conserving null values. Values are converted to null if:
|
||||
* <ul>
|
||||
* <li>it is an empty string value after trimming</li>
|
||||
* <li>it is an empty collection</li>
|
||||
* <li>it is an empty array</li>
|
||||
* <li>it is an empty string value after trimming</li>
|
||||
* <li>it is an empty collection</li>
|
||||
* <li>it is an empty array</li>
|
||||
* </ul>
|
||||
* String values are trimmed before being put into the map.
|
||||
* Otherwise, it is up to the extracter to ensure that the value is a <tt>Serializable</tt>.
|
||||
* It is not appropriate to implicitly convert values in order to make them <tt>Serializable</tt>
|
||||
* - the best conversion method will depend on the value's specific meaning.
|
||||
* String values are trimmed before being put into the map. Otherwise, it is up to the extracter to ensure that the value is a <tt>Serializable</tt>. It is not appropriate to implicitly convert values in order to make them <tt>Serializable</tt> - the best conversion method will depend on the value's specific meaning.
|
||||
*
|
||||
* @param key the destination key
|
||||
* @param value the serializable value
|
||||
* @param destination the map to put values into
|
||||
* @return Returns <tt>true</tt> if set, otherwise <tt>false</tt>
|
||||
* @param key
|
||||
* the destination key
|
||||
* @param value
|
||||
* the serializable value
|
||||
* @param destination
|
||||
* the map to put values into
|
||||
* @return Returns <tt>true</tt> if set, otherwise <tt>false</tt>
|
||||
*/
|
||||
// Copied from the content repository's AbstractMappingMetadataExtracter.
|
||||
protected boolean putRawValue(String key, Serializable value, Map<String, Serializable> destination)
|
||||
@@ -514,8 +498,7 @@ public abstract class AbstractMetadataExtractorEmbedder implements CustomTransfo
|
||||
String targetMimetype, OutputStream outputStream, Map<String, String> transformOptions,
|
||||
TransformManager transformManager) throws Exception;
|
||||
|
||||
private Map<String, Set<String>> getExtractMappingFromOptions(Map<String, String> transformOptions, Map<String,
|
||||
Set<String>> defaultExtractMapping)
|
||||
private Map<String, Set<String>> getExtractMappingFromOptions(Map<String, String> transformOptions, Map<String, Set<String>> defaultExtractMapping)
|
||||
{
|
||||
String extractMappingOption = transformOptions.get(EXTRACT_MAPPING);
|
||||
if (extractMappingOption != null)
|
||||
@@ -527,19 +510,19 @@ public abstract class AbstractMetadataExtractorEmbedder implements CustomTransfo
|
||||
}
|
||||
catch (JsonProcessingException e)
|
||||
{
|
||||
throw new IllegalArgumentException("Failed to read "+ EXTRACT_MAPPING +" from request", e);
|
||||
throw new IllegalArgumentException("Failed to read " + EXTRACT_MAPPING + " from request", e);
|
||||
}
|
||||
}
|
||||
return defaultExtractMapping;
|
||||
}
|
||||
|
||||
public void mapMetadataAndWrite(OutputStream outputStream, Map<String, Serializable> metadata,
|
||||
Map<String, Set<String>> extractMapping) throws IOException
|
||||
Map<String, Set<String>> extractMapping) throws IOException
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Raw metadata:");
|
||||
metadata.forEach((k,v) -> logger.debug(" {}={}", k, v));
|
||||
metadata.forEach((k, v) -> logger.debug(" {}={}", k, v));
|
||||
}
|
||||
|
||||
metadata = mapRawToSystem(metadata, extractMapping);
|
||||
@@ -549,12 +532,14 @@ public abstract class AbstractMetadataExtractorEmbedder implements CustomTransfo
|
||||
/**
|
||||
* Based on AbstractMappingMetadataExtracter#mapRawToSystem.
|
||||
*
|
||||
* @param rawMetadata Metadata keyed by document properties
|
||||
* @param extractMapping Mapping between document ans system properties
|
||||
* @return Returns the metadata keyed by the system properties
|
||||
* @param rawMetadata
|
||||
* Metadata keyed by document properties
|
||||
* @param extractMapping
|
||||
* Mapping between document ans system properties
|
||||
* @return Returns the metadata keyed by the system properties
|
||||
*/
|
||||
private Map<String, Serializable> mapRawToSystem(Map<String, Serializable> rawMetadata,
|
||||
Map<String, Set<String>> extractMapping)
|
||||
Map<String, Set<String>> extractMapping)
|
||||
{
|
||||
boolean debugEnabled = logger.isDebugEnabled();
|
||||
if (debugEnabled)
|
||||
|
@@ -37,7 +37,8 @@ public class FileRefEntity
|
||||
{
|
||||
private String fileRef;
|
||||
|
||||
public FileRefEntity() {}
|
||||
public FileRefEntity()
|
||||
{}
|
||||
|
||||
public FileRefEntity(String fileRef)
|
||||
{
|
||||
@@ -57,8 +58,10 @@ public class FileRefEntity
|
||||
@Override
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
if (this == o)
|
||||
return true;
|
||||
if (o == null || getClass() != o.getClass())
|
||||
return false;
|
||||
FileRefEntity that = (FileRefEntity) o;
|
||||
return Objects.equals(fileRef, that.fileRef);
|
||||
}
|
||||
|
@@ -35,7 +35,8 @@ public class FileRefResponse
|
||||
{
|
||||
private FileRefEntity entry;
|
||||
|
||||
public FileRefResponse() {}
|
||||
public FileRefResponse()
|
||||
{}
|
||||
|
||||
public FileRefResponse(FileRefEntity entry)
|
||||
{
|
||||
|
@@ -26,11 +26,11 @@
|
||||
*/
|
||||
package org.alfresco.transform.base.probes;
|
||||
|
||||
import org.alfresco.transform.base.transform.TransformHandler;
|
||||
import org.alfresco.transform.base.logging.LogEntry;
|
||||
import org.alfresco.transform.exceptions.TransformException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import static org.springframework.http.HttpStatus.INSUFFICIENT_STORAGE;
|
||||
import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR;
|
||||
import static org.springframework.http.HttpStatus.TOO_MANY_REQUESTS;
|
||||
|
||||
import static org.alfresco.transform.base.fs.FileManager.TempFileProvider.createTempFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@@ -42,35 +42,33 @@ import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import static org.alfresco.transform.base.fs.FileManager.TempFileProvider.createTempFile;
|
||||
import static org.springframework.http.HttpStatus.INSUFFICIENT_STORAGE;
|
||||
import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR;
|
||||
import static org.springframework.http.HttpStatus.TOO_MANY_REQUESTS;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.alfresco.transform.base.logging.LogEntry;
|
||||
import org.alfresco.transform.base.transform.TransformHandler;
|
||||
import org.alfresco.transform.exceptions.TransformException;
|
||||
|
||||
/**
|
||||
* Provides test transformations and the logic used by k8 liveness and readiness probes.
|
||||
*
|
||||
* <p><b>K8s probes</b>: A readiness probe indicates if the pod should accept request. <b>It does not indicate that a
|
||||
* pod is ready after startup</b>. The liveness probe indicates when to kill the pod. <b>Both probes are called
|
||||
* throughout the lifetime of the pod</b> and a <b>liveness probes can take place before a readiness probe.</b> The k8s
|
||||
* <b>initialDelaySeconds field is not fully honoured</b> as it is multiplied by a random number, so is
|
||||
* actually a maximum initial delay in seconds, but could be 0. </p>
|
||||
* <p>
|
||||
* <b>K8s probes</b>: A readiness probe indicates if the pod should accept request. <b>It does not indicate that a pod is ready after startup</b>. The liveness probe indicates when to kill the pod. <b>Both probes are called throughout the lifetime of the pod</b> and a <b>liveness probes can take place before a readiness probe.</b> The k8s <b>initialDelaySeconds field is not fully honoured</b> as it is multiplied by a random number, so is actually a maximum initial delay in seconds, but could be 0.
|
||||
* </p>
|
||||
*
|
||||
* <p>Live and readiness probes do test transforms. The first 6 requests result in a transformation of a small test
|
||||
* file. The average time and size is remembered, but excludes the first one as it is normally slower. This is
|
||||
* used in future requests to discover if transformations are becoming slower or unexpectedly change size.</p>
|
||||
* <p>
|
||||
* Live and readiness probes do test transforms. The first 6 requests result in a transformation of a small test file. The average time and size is remembered, but excludes the first one as it is normally slower. This is used in future requests to discover if transformations are becoming slower or unexpectedly change size.
|
||||
* </p>
|
||||
*
|
||||
* <p>If a transform longer than a maximum time, a maximum number of transforms have been performed, a test transform is
|
||||
* an unexpected size or a test transform takes an unexpected time, then a non 200 status code is returned resulting in
|
||||
* k8s terminating the pod. These are controlled by:</p>
|
||||
* <p>
|
||||
* If a transform longer than a maximum time, a maximum number of transforms have been performed, a test transform is an unexpected size or a test transform takes an unexpected time, then a non 200 status code is returned resulting in k8s terminating the pod. These are controlled by:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li>expectedLength the expected length of the target file after a test transform</li>
|
||||
* <li>plusOrMinus allows for variation in the transformed size - generally caused by dates</li>
|
||||
* <li>livenessPercent allows for variation in transform time. Up to 2 and a half times is not
|
||||
* unreasonable under load</li>
|
||||
* <li>maxTransforms the maximum number of transforms (not just test ones) before a restart is triggered</li>
|
||||
* <li>maxTransformSeconds a maximum time any transform (not just test ones) is allowed to take before
|
||||
* a restart is triggered.</li>
|
||||
* <li>expectedLength the expected length of the target file after a test transform</li>
|
||||
* <li>plusOrMinus allows for variation in the transformed size - generally caused by dates</li>
|
||||
* <li>livenessPercent allows for variation in transform time. Up to 2 and a half times is not unreasonable under load</li>
|
||||
* <li>maxTransforms the maximum number of transforms (not just test ones) before a restart is triggered</li>
|
||||
* <li>maxTransformSeconds a maximum time any transform (not just test ones) is allowed to take before a restart is triggered.</li>
|
||||
* <li>livenessTransformPeriodSeconds The number of seconds between test transforms done for live probes</li>
|
||||
* </ul>
|
||||
*/
|
||||
@@ -114,8 +112,8 @@ public class ProbeTransform
|
||||
}
|
||||
|
||||
public ProbeTransform(String sourceFilename, String sourceMimetype, String targetMimetype, Map<String, String> transformOptions,
|
||||
long expectedLength, long plusOrMinus, int livenessPercent, long maxTransforms, long maxTransformSeconds,
|
||||
long livenessTransformPeriodSeconds)
|
||||
long expectedLength, long plusOrMinus, int livenessPercent, long maxTransforms, long maxTransformSeconds,
|
||||
long livenessTransformPeriodSeconds)
|
||||
{
|
||||
this.sourceFilename = sourceFilename;
|
||||
this.sourceMimetype = sourceMimetype;
|
||||
@@ -128,7 +126,7 @@ public class ProbeTransform
|
||||
maxTransformCount = getPositiveLongEnv("maxTransforms", maxTransforms);
|
||||
maxTransformTime = getPositiveLongEnv("maxTransformSeconds", maxTransformSeconds) * 1000;
|
||||
livenessTransformPeriod = getPositiveLongEnv("livenessTransformPeriodSeconds",
|
||||
livenessTransformPeriodSeconds) * 1000;
|
||||
livenessTransformPeriodSeconds) * 1000;
|
||||
livenessTransformEnabled = getBooleanEnvVar("livenessTransformEnabled", false);
|
||||
}
|
||||
|
||||
@@ -139,8 +137,7 @@ public class ProbeTransform
|
||||
return Boolean.parseBoolean(System.getenv(name));
|
||||
}
|
||||
catch (Exception ignore)
|
||||
{
|
||||
}
|
||||
{}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
@@ -155,8 +152,7 @@ public class ProbeTransform
|
||||
l = Long.parseLong(env);
|
||||
}
|
||||
catch (NumberFormatException ignore)
|
||||
{
|
||||
}
|
||||
{}
|
||||
}
|
||||
if (l <= 0)
|
||||
{
|
||||
@@ -182,9 +178,9 @@ public class ProbeTransform
|
||||
|
||||
String result = (isLiveProbe && livenessTransformPeriod > 0 &&
|
||||
(transCount <= AVERAGE_OVER_TRANSFORMS || nextTransformTime < System.currentTimeMillis()))
|
||||
|| !initialised.get()
|
||||
? doTransform(isLiveProbe, transformHandler)
|
||||
: doNothing(isLiveProbe);
|
||||
|| !initialised.get()
|
||||
? doTransform(isLiveProbe, transformHandler)
|
||||
: doNothing(isLiveProbe);
|
||||
|
||||
// Check if the test transformation was too slow.
|
||||
checkMaxTransformTimeAndCount(isLiveProbe);
|
||||
@@ -211,8 +207,7 @@ public class ProbeTransform
|
||||
do
|
||||
{
|
||||
nextTransformTime += livenessTransformPeriod;
|
||||
}
|
||||
while (nextTransformTime < start);
|
||||
} while (nextTransformTime < start);
|
||||
}
|
||||
|
||||
File sourceFile = getSourceFile(isLiveProbe);
|
||||
@@ -228,15 +223,15 @@ public class ProbeTransform
|
||||
if (time > maxTime)
|
||||
{
|
||||
throw new TransformException(INTERNAL_SERVER_ERROR,
|
||||
getMessagePrefix(isLiveProbe) +
|
||||
message + " which is more than " + livenessPercent +
|
||||
"% slower than the normal value of " + normalTime + "ms");
|
||||
getMessagePrefix(isLiveProbe) +
|
||||
message + " which is more than " + livenessPercent +
|
||||
"% slower than the normal value of " + normalTime + "ms");
|
||||
}
|
||||
|
||||
// We don't care if the ready or live probe works out if we are 'ready' to take requests.
|
||||
initialised.set(true);
|
||||
|
||||
return getProbeMessage(isLiveProbe) + "Success - "+message;
|
||||
return getProbeMessage(isLiveProbe) + "Success - " + message;
|
||||
}
|
||||
|
||||
private void checkMaxTransformTimeAndCount(boolean isLiveProbe)
|
||||
@@ -244,15 +239,15 @@ public class ProbeTransform
|
||||
if (die.get())
|
||||
{
|
||||
throw new TransformException(TOO_MANY_REQUESTS,
|
||||
getMessagePrefix(isLiveProbe) + "Transformer requested to die. A transform took " +
|
||||
"longer than " + (maxTransformTime / 1000) + " seconds");
|
||||
getMessagePrefix(isLiveProbe) + "Transformer requested to die. A transform took " +
|
||||
"longer than " + (maxTransformTime / 1000) + " seconds");
|
||||
}
|
||||
|
||||
if (maxTransformCount > 0 && transformCount.get() > maxTransformCount)
|
||||
{
|
||||
throw new TransformException(TOO_MANY_REQUESTS,
|
||||
getMessagePrefix(isLiveProbe) + "Transformer requested to die. It has performed " +
|
||||
"more than " + maxTransformCount + " transformations");
|
||||
getMessagePrefix(isLiveProbe) + "Transformer requested to die. It has performed " +
|
||||
"more than " + maxTransformCount + " transformations");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,7 +261,7 @@ public class ProbeTransform
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new TransformException(INSUFFICIENT_STORAGE,
|
||||
getMessagePrefix(isLiveProbe) + "Failed to store the source file", e);
|
||||
getMessagePrefix(isLiveProbe) + "Failed to store the source file", e);
|
||||
}
|
||||
long length = sourceFile.length();
|
||||
LogEntry.setSource(sourceFile.getName(), length);
|
||||
@@ -301,7 +296,7 @@ public class ProbeTransform
|
||||
maxTime = (normalTime * (livenessPercent + 100)) / 100;
|
||||
|
||||
if ((!isLiveProbe && !readySent.getAndSet(
|
||||
true)) || transCount > AVERAGE_OVER_TRANSFORMS)
|
||||
true)) || transCount > AVERAGE_OVER_TRANSFORMS)
|
||||
{
|
||||
nextTransformTime = System.currentTimeMillis() + livenessTransformPeriod;
|
||||
logger.trace("{} - {}ms+{}%={}ms", message, normalTime, livenessPercent, maxTime);
|
||||
@@ -320,16 +315,16 @@ public class ProbeTransform
|
||||
if (!targetFile.exists() || !targetFile.isFile())
|
||||
{
|
||||
throw new TransformException(INTERNAL_SERVER_ERROR,
|
||||
probeMessage + "Target File \"" + targetFile.getAbsolutePath() + "\" did not exist");
|
||||
probeMessage + "Target File \"" + targetFile.getAbsolutePath() + "\" did not exist");
|
||||
}
|
||||
long length = targetFile.length();
|
||||
targetFile.delete();
|
||||
if (length < minExpectedLength || length > maxExpectedLength)
|
||||
{
|
||||
throw new TransformException(INTERNAL_SERVER_ERROR,
|
||||
probeMessage + "Target File \"" + targetFile.getAbsolutePath() +
|
||||
"\" was the wrong size (" + length + "). Needed to be between " +
|
||||
minExpectedLength + " and " + maxExpectedLength);
|
||||
probeMessage + "Target File \"" + targetFile.getAbsolutePath() +
|
||||
"\" was the wrong size (" + length + "). Needed to be between " +
|
||||
minExpectedLength + " and " + maxExpectedLength);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -56,4 +56,4 @@ public abstract class AbstractTransformConfigSource implements TransformConfigSo
|
||||
{
|
||||
return baseUrl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -26,18 +26,19 @@
|
||||
*/
|
||||
package org.alfresco.transform.base.registry;
|
||||
|
||||
import org.alfresco.transform.base.CustomTransformer;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import org.alfresco.transform.base.CustomTransformer;
|
||||
|
||||
@Component
|
||||
public class CustomTransformers
|
||||
@@ -54,22 +55,21 @@ public class CustomTransformers
|
||||
{
|
||||
if (customTransformerList != null)
|
||||
{
|
||||
customTransformerList.forEach(customTransformer ->
|
||||
customTransformersByName.put(customTransformer.getTransformerName(), customTransformer));
|
||||
customTransformerList.forEach(customTransformer -> customTransformersByName.put(customTransformer.getTransformerName(), customTransformer));
|
||||
|
||||
List<String> nonNullTransformerNames = customTransformerList.stream()
|
||||
.map(CustomTransformer::getTransformerName)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
.map(CustomTransformer::getTransformerName)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (!nonNullTransformerNames.isEmpty())
|
||||
{
|
||||
logger.info("Custom Transformers:");
|
||||
nonNullTransformerNames
|
||||
.stream()
|
||||
.sorted()
|
||||
.map(name -> " "+name)
|
||||
.forEach(logger::debug);
|
||||
.stream()
|
||||
.sorted()
|
||||
.map(name -> " " + name)
|
||||
.forEach(logger::debug);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -80,7 +80,7 @@ public class CustomTransformers
|
||||
return customTransformer == null ? customTransformersByName.get(null) : customTransformer;
|
||||
}
|
||||
|
||||
public void put(String name, CustomTransformer customTransformer)
|
||||
public void put(String name, CustomTransformer customTransformer)
|
||||
{
|
||||
customTransformersByName.put(name, customTransformer);
|
||||
}
|
||||
|
@@ -26,14 +26,14 @@
|
||||
*/
|
||||
package org.alfresco.transform.base.registry;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.io.Resource;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.io.Resource;
|
||||
|
||||
@Configuration
|
||||
@ConfigurationProperties(prefix = "transform.config")
|
||||
public class TransformConfigFiles
|
||||
|
@@ -26,18 +26,18 @@
|
||||
*/
|
||||
package org.alfresco.transform.base.registry;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import static org.alfresco.transform.base.registry.TransformConfigFromFiles.retrieveResource;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.alfresco.transform.base.registry.TransformConfigFromFiles.retrieveResource;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
|
||||
/**
|
||||
* Similar to {@link TransformConfigFiles} but uses the names historically used by the t-router.
|
||||
@@ -50,8 +50,9 @@ public class TransformConfigFilesHistoric
|
||||
// environment variables like TRANSFORMER_ROUTES_ADDITIONAL_<engineName>.
|
||||
private final Map<String, String> additional = new HashMap<>();
|
||||
|
||||
//Used by ConfigurationProperties annotation
|
||||
public Map<String, String> getAdditional() {
|
||||
// Used by ConfigurationProperties annotation
|
||||
public Map<String, String> getAdditional()
|
||||
{
|
||||
return additional;
|
||||
}
|
||||
|
||||
|
@@ -26,8 +26,14 @@
|
||||
*/
|
||||
package org.alfresco.transform.base.registry;
|
||||
|
||||
import org.alfresco.transform.config.reader.TransformConfigResourceReader;
|
||||
import org.alfresco.transform.config.TransformConfig;
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
@@ -35,13 +41,8 @@ import org.springframework.core.io.FileSystemResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import static java.util.stream.Collectors.toList;
|
||||
import org.alfresco.transform.config.TransformConfig;
|
||||
import org.alfresco.transform.config.reader.TransformConfigResourceReader;
|
||||
|
||||
/**
|
||||
* Makes {@link TransformConfig} from files on the classpath or externally available to the {@link TransformRegistry}.
|
||||
@@ -66,30 +67,29 @@ public class TransformConfigFromFiles
|
||||
final List<Resource> resources = new ArrayList<>();
|
||||
resources.addAll(transformConfigFiles.retrieveResources());
|
||||
resources.addAll(transformConfigFilesHistoric.retrieveResources());
|
||||
resources.forEach(resource ->
|
||||
{
|
||||
resources.forEach(resource -> {
|
||||
String filename = resource.getFilename();
|
||||
transformConfigSources.add(
|
||||
new AbstractTransformConfigSource(filename, filename, isTRouter ? null : "---")
|
||||
{
|
||||
@Override public TransformConfig getTransformConfig()
|
||||
{
|
||||
return transformConfigResourceReader.read(resource);
|
||||
}
|
||||
});
|
||||
new AbstractTransformConfigSource(filename, filename, isTRouter ? null : "---") {
|
||||
@Override
|
||||
public TransformConfig getTransformConfig()
|
||||
{
|
||||
return transformConfigResourceReader.read(resource);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public static List<Resource> retrieveResources(Map<String, String> additional)
|
||||
{
|
||||
return additional
|
||||
.values()
|
||||
.stream()
|
||||
.filter(Objects::nonNull)
|
||||
.map(String::trim)
|
||||
.filter(s -> !s.isBlank())
|
||||
.map(TransformConfigFromFiles::retrieveResource)
|
||||
.collect(toList());
|
||||
.values()
|
||||
.stream()
|
||||
.filter(Objects::nonNull)
|
||||
.map(String::trim)
|
||||
.filter(s -> !s.isBlank())
|
||||
.map(TransformConfigFromFiles::retrieveResource)
|
||||
.collect(toList());
|
||||
}
|
||||
|
||||
public static Resource retrieveResource(final String filename)
|
||||
|
@@ -26,14 +26,15 @@
|
||||
*/
|
||||
package org.alfresco.transform.base.registry;
|
||||
|
||||
import org.alfresco.transform.base.TransformEngine;
|
||||
import org.alfresco.transform.config.TransformConfig;
|
||||
import java.util.List;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import java.util.List;
|
||||
import org.alfresco.transform.base.TransformEngine;
|
||||
import org.alfresco.transform.config.TransformConfig;
|
||||
|
||||
/**
|
||||
* Makes {@link TransformConfig} from {@link TransformEngine}s available to the {@link TransformRegistry}.
|
||||
@@ -54,21 +55,21 @@ public class TransformConfigFromTransformEngines
|
||||
if (transformEngines != null)
|
||||
{
|
||||
transformEngines.stream()
|
||||
.forEach(transformEngine -> {
|
||||
TransformConfig transformConfig = transformEngine.getTransformConfig();
|
||||
if (transformConfig != null) // if not a wrapping TransformEngine like all-in-one
|
||||
{
|
||||
String engineName = transformEngine.getTransformEngineName();
|
||||
transformConfigSources.add(
|
||||
new AbstractTransformConfigSource(engineName, engineName, isTRouter ? null : "---")
|
||||
{
|
||||
@Override public TransformConfig getTransformConfig()
|
||||
{
|
||||
return transformEngine.getTransformConfig();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
.forEach(transformEngine -> {
|
||||
TransformConfig transformConfig = transformEngine.getTransformConfig();
|
||||
if (transformConfig != null) // if not a wrapping TransformEngine like all-in-one
|
||||
{
|
||||
String engineName = transformEngine.getTransformEngineName();
|
||||
transformConfigSources.add(
|
||||
new AbstractTransformConfigSource(engineName, engineName, isTRouter ? null : "---") {
|
||||
@Override
|
||||
public TransformConfig getTransformConfig()
|
||||
{
|
||||
return transformEngine.getTransformConfig();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -25,17 +25,26 @@
|
||||
*/
|
||||
package org.alfresco.transform.base.registry;
|
||||
|
||||
import org.alfresco.transform.base.CustomTransformer;
|
||||
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.CombinedTransformConfig;
|
||||
import org.alfresco.transform.registry.Origin;
|
||||
import org.alfresco.transform.registry.TransformCache;
|
||||
import org.alfresco.transform.registry.TransformerType;
|
||||
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.springframework.util.CollectionUtils.isEmpty;
|
||||
|
||||
import static org.alfresco.transform.config.CoreVersionDecorator.setCoreVersionOnSingleStepTransformers;
|
||||
import static org.alfresco.transform.registry.TransformerType.FAILOVER_TRANSFORMER;
|
||||
import static org.alfresco.transform.registry.TransformerType.PIPELINE_TRANSFORMER;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -49,26 +58,20 @@ import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
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.registry.TransformerType.FAILOVER_TRANSFORMER;
|
||||
import static org.alfresco.transform.registry.TransformerType.PIPELINE_TRANSFORMER;
|
||||
import static org.springframework.util.CollectionUtils.isEmpty;
|
||||
import org.alfresco.transform.base.CustomTransformer;
|
||||
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.CombinedTransformConfig;
|
||||
import org.alfresco.transform.registry.Origin;
|
||||
import org.alfresco.transform.registry.TransformCache;
|
||||
import org.alfresco.transform.registry.TransformerType;
|
||||
|
||||
@Service
|
||||
@Scope( proxyMode = ScopedProxyMode.TARGET_CLASS )
|
||||
@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
|
||||
public class TransformRegistry extends AbstractTransformRegistry
|
||||
{
|
||||
private static final Logger logger = LoggerFactory.getLogger(TransformRegistry.class);
|
||||
@@ -91,7 +94,7 @@ public class TransformRegistry extends AbstractTransformRegistry
|
||||
{
|
||||
private TransformConfig transformConfig;
|
||||
private TransformConfig uncombinedTransformConfig;
|
||||
private Map<String,Origin<Transformer>> transformerByNameMap;
|
||||
private Map<String, Origin<Transformer>> transformerByNameMap;
|
||||
|
||||
public TransformConfig getTransformConfig()
|
||||
{
|
||||
@@ -143,8 +146,7 @@ public class TransformRegistry extends AbstractTransformRegistry
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the registry on application startup. This allows Components in projects that extend the t-engine base
|
||||
* to use @PostConstruct to add to {@code transformConfigSources}, before the registry is loaded.
|
||||
* Load the registry on application startup. This allows Components in projects that extend the t-engine base to use @PostConstruct to add to {@code transformConfigSources}, before the registry is loaded.
|
||||
*/
|
||||
@Async
|
||||
void initRegistryOnAppStartup(final ContextRefreshedEvent event)
|
||||
@@ -170,7 +172,7 @@ public class TransformRegistry extends AbstractTransformRegistry
|
||||
fixedDelayString = "#{${transform.engine.config.retry.timeout} * 1000}")
|
||||
public void retrieveEngineConfigsAfterFailure()
|
||||
{
|
||||
if(isRecoveryModeOn.get())
|
||||
if (isRecoveryModeOn.get())
|
||||
{
|
||||
logger.trace("Recovery mode, attempting to retrieve configs for all registered T-Engines.");
|
||||
retrieveConfig();
|
||||
@@ -191,8 +193,7 @@ public class TransformRegistry extends AbstractTransformRegistry
|
||||
TransformConfig transformConfig = source.getTransformConfig();
|
||||
availableTransformers.put(
|
||||
sortOnName,
|
||||
new LocalTransformConfigSource(transformConfig, sortOnName, source.getReadFrom(), source.getBaseUrl())
|
||||
);
|
||||
new LocalTransformConfigSource(transformConfig, sortOnName, source.getReadFrom(), source.getBaseUrl()));
|
||||
}
|
||||
catch (IllegalStateException e)
|
||||
{
|
||||
@@ -204,14 +205,13 @@ public class TransformRegistry extends AbstractTransformRegistry
|
||||
{
|
||||
logger.warn(
|
||||
"Failed to retrieved TransformConfig during refreshment. Stops refreshing TransformRegistry. {}",
|
||||
e.getMessage()
|
||||
);
|
||||
e.getMessage());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(transformConfigSources.size() == availableTransformers.size()
|
||||
if (transformConfigSources.size() == availableTransformers.size()
|
||||
&& isRecoveryModeOn.compareAndExchange(true, false))
|
||||
{
|
||||
logger.trace("All TransformConfigSources have been retrieved, turning off recovery mode.");
|
||||
@@ -219,11 +219,11 @@ public class TransformRegistry extends AbstractTransformRegistry
|
||||
|
||||
logger.debug("Creating CombinedTransformConfig.");
|
||||
availableTransformers.values().forEach(source -> {
|
||||
TransformConfig transformConfig = source.getTransformConfig();
|
||||
setCoreVersionOnSingleStepTransformers(transformConfig, coreVersion);
|
||||
combinedTransformConfig.addTransformConfig(transformConfig, source.getReadFrom(), source.getBaseUrl(),
|
||||
TransformConfig transformConfig = source.getTransformConfig();
|
||||
setCoreVersionOnSingleStepTransformers(transformConfig, coreVersion);
|
||||
combinedTransformConfig.addTransformConfig(transformConfig, source.getReadFrom(), source.getBaseUrl(),
|
||||
this);
|
||||
});
|
||||
});
|
||||
|
||||
TransformConfig uncombinedTransformConfig = combinedTransformConfig.buildTransformConfig();
|
||||
combinedTransformConfig.combineTransformerConfig(this);
|
||||
@@ -239,48 +239,48 @@ public class TransformRegistry extends AbstractTransformRegistry
|
||||
if (logger.isInfoEnabled())
|
||||
{
|
||||
Set<String> customTransformerNames = new HashSet<>(customTransformerList == null
|
||||
? Collections.emptySet()
|
||||
: customTransformerList.stream().map(CustomTransformer::getTransformerName).collect(Collectors.toSet()));
|
||||
List<String> nonNullTransformerNames = uncombinedTransformConfig.getTransformers().stream()
|
||||
.map(Transformer::getTransformerName)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
? Collections.emptySet()
|
||||
: customTransformerList.stream().map(CustomTransformer::getTransformerName).collect(Collectors.toSet()));
|
||||
List<String> nonNullTransformerNames = uncombinedTransformConfig.getTransformers().stream()
|
||||
.map(Transformer::getTransformerName)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
ArrayList<String> logMessages = new ArrayList<>();
|
||||
if (!nonNullTransformerNames.isEmpty())
|
||||
{
|
||||
logMessages.add("Transformers (" + nonNullTransformerNames.size() + ") Transforms (" + getData().getTransformCount()+ "):");
|
||||
logMessages.add("Transformers (" + nonNullTransformerNames.size() + ") Transforms (" + getData().getTransformCount() + "):");
|
||||
nonNullTransformerNames
|
||||
.stream()
|
||||
.sorted(String.CASE_INSENSITIVE_ORDER)
|
||||
.map(name -> {
|
||||
Origin<Transformer> transformerOrigin = transformerByNameMap.get(name);
|
||||
String message = " " + name + (transformerOrigin == null
|
||||
? " -- unavailable: see previous messages"
|
||||
: isTRouter
|
||||
? ""
|
||||
: TransformerType.valueOf(transformerOrigin.get()) == PIPELINE_TRANSFORMER
|
||||
? " -- unavailable: pipeline only available via t-router"
|
||||
: TransformerType.valueOf(transformerOrigin.get()) == FAILOVER_TRANSFORMER
|
||||
? " -- unavailable: failover only available via t-router"
|
||||
: !customTransformerNames.contains(name)
|
||||
? " -- missing: CustomTransformer"
|
||||
: "");
|
||||
customTransformerNames.remove(name);
|
||||
return message;
|
||||
})
|
||||
.forEach(logMessages::add);
|
||||
.stream()
|
||||
.sorted(String.CASE_INSENSITIVE_ORDER)
|
||||
.map(name -> {
|
||||
Origin<Transformer> transformerOrigin = transformerByNameMap.get(name);
|
||||
String message = " " + name + (transformerOrigin == null
|
||||
? " -- unavailable: see previous messages"
|
||||
: isTRouter
|
||||
? ""
|
||||
: TransformerType.valueOf(transformerOrigin.get()) == PIPELINE_TRANSFORMER
|
||||
? " -- unavailable: pipeline only available via t-router"
|
||||
: TransformerType.valueOf(transformerOrigin.get()) == FAILOVER_TRANSFORMER
|
||||
? " -- unavailable: failover only available via t-router"
|
||||
: !customTransformerNames.contains(name)
|
||||
? " -- missing: CustomTransformer"
|
||||
: "");
|
||||
customTransformerNames.remove(name);
|
||||
return message;
|
||||
})
|
||||
.forEach(logMessages::add);
|
||||
|
||||
List<String> unusedCustomTransformNames = customTransformerNames.stream()
|
||||
.filter(Objects::nonNull)
|
||||
.sorted()
|
||||
.collect(Collectors.toList());
|
||||
.filter(Objects::nonNull)
|
||||
.sorted()
|
||||
.collect(Collectors.toList());
|
||||
if (!unusedCustomTransformNames.isEmpty())
|
||||
{
|
||||
logMessages.add("Unused CustomTransformers (" + unusedCustomTransformNames.size() + ") - name is not in the transform config:");
|
||||
unusedCustomTransformNames
|
||||
.stream()
|
||||
.map(name -> " " + name)
|
||||
.forEach(logMessages::add);
|
||||
.stream()
|
||||
.map(name -> " " + name)
|
||||
.forEach(logMessages::add);
|
||||
}
|
||||
|
||||
int logMessageHashCode = logMessages.hashCode();
|
||||
@@ -301,8 +301,8 @@ public class TransformRegistry extends AbstractTransformRegistry
|
||||
{
|
||||
Data data = getData();
|
||||
return isTRouter
|
||||
? data.getTransformConfig()
|
||||
: data.getUncombinedTransformConfig();
|
||||
? data.getTransformConfig()
|
||||
: data.getUncombinedTransformConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -321,15 +321,15 @@ public class TransformRegistry extends AbstractTransformRegistry
|
||||
@Override
|
||||
public Data getData()
|
||||
{
|
||||
return concurrentRead(() -> data );
|
||||
return concurrentRead(() -> data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Lock for reads while updating, use {@link #concurrentRead} to access locked fields
|
||||
*/
|
||||
private void concurrentUpdate(CombinedTransformConfig combinedTransformConfig,
|
||||
TransformConfig uncombinedTransformConfig, TransformConfig transformConfig,
|
||||
Map<String, Origin<Transformer>> transformerByNameMap)
|
||||
TransformConfig uncombinedTransformConfig, TransformConfig transformConfig,
|
||||
Map<String, Origin<Transformer>> transformerByNameMap)
|
||||
{
|
||||
configRefreshLock.writeLock().lock();
|
||||
try
|
||||
@@ -372,10 +372,9 @@ public class TransformRegistry extends AbstractTransformRegistry
|
||||
}
|
||||
|
||||
public Transformer getTransformer(final String sourceMediaType, final Long fileSizeBytes,
|
||||
final String targetMediaType, final Map<String, String> transformOptions)
|
||||
final String targetMediaType, final Map<String, String> transformOptions)
|
||||
{
|
||||
return concurrentRead(() ->
|
||||
{
|
||||
return concurrentRead(() -> {
|
||||
long fileSize = fileSizeBytes == null ? 0 : fileSizeBytes;
|
||||
String transformerName = findTransformerName(sourceMediaType, fileSize, targetMediaType, transformOptions, null);
|
||||
return getTransformer(transformerName);
|
||||
@@ -395,15 +394,10 @@ public class TransformRegistry extends AbstractTransformRegistry
|
||||
|
||||
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);
|
||||
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)
|
||||
@@ -447,9 +441,9 @@ public class TransformRegistry extends AbstractTransformRegistry
|
||||
if (option instanceof TransformOptionGroup)
|
||||
{
|
||||
return ((TransformOptionGroup) option)
|
||||
.getTransformOptions()
|
||||
.stream()
|
||||
.flatMap(TransformRegistry::retrieveOptionsStrings);
|
||||
.getTransformOptions()
|
||||
.stream()
|
||||
.flatMap(TransformRegistry::retrieveOptionsStrings);
|
||||
}
|
||||
return Stream.of(((TransformOptionValue) option).getName());
|
||||
}
|
||||
|
@@ -33,10 +33,9 @@ import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
|
||||
import static org.springframework.http.MediaType.MULTIPART_FORM_DATA;
|
||||
|
||||
import java.io.File;
|
||||
import javax.net.ssl.SSLException;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
|
||||
import org.alfresco.transform.base.WebClientBuilderAdjuster;
|
||||
import org.alfresco.transform.exceptions.TransformException;
|
||||
import org.alfresco.transform.base.model.FileRefResponse;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -54,8 +53,9 @@ import org.springframework.web.client.HttpClientErrorException;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import javax.net.ssl.SSLException;
|
||||
import org.alfresco.transform.base.WebClientBuilderAdjuster;
|
||||
import org.alfresco.transform.base.model.FileRefResponse;
|
||||
import org.alfresco.transform.exceptions.TransformException;
|
||||
|
||||
/**
|
||||
* Simple Rest client that call Alfresco Shared File Store
|
||||
@@ -77,19 +77,21 @@ public class SharedFileStoreClient
|
||||
private WebClient client;
|
||||
|
||||
@PostConstruct
|
||||
public void init() throws SSLException {
|
||||
public void init() throws SSLException
|
||||
{
|
||||
final WebClient.Builder clientBuilder = WebClient.builder();
|
||||
adjuster.adjust(clientBuilder);
|
||||
client = clientBuilder.baseUrl(url.endsWith("/") ? url : url + "/")
|
||||
.defaultHeader(CONTENT_TYPE, APPLICATION_JSON_VALUE)
|
||||
.defaultHeader(ACCEPT, APPLICATION_JSON_VALUE)
|
||||
.build();
|
||||
.defaultHeader(CONTENT_TYPE, APPLICATION_JSON_VALUE)
|
||||
.defaultHeader(ACCEPT, APPLICATION_JSON_VALUE)
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a file from Shared File Store using given file reference
|
||||
*
|
||||
* @param fileRef File reference
|
||||
* @param fileRef
|
||||
* File reference
|
||||
* @return ResponseEntity<Resource>
|
||||
*/
|
||||
public ResponseEntity<Resource> retrieveFile(String fileRef)
|
||||
@@ -97,7 +99,7 @@ public class SharedFileStoreClient
|
||||
try
|
||||
{
|
||||
return restTemplate.getForEntity(url + "/" + fileRef,
|
||||
org.springframework.core.io.Resource.class);
|
||||
org.springframework.core.io.Resource.class);
|
||||
}
|
||||
catch (HttpClientErrorException e)
|
||||
{
|
||||
@@ -108,7 +110,8 @@ public class SharedFileStoreClient
|
||||
/**
|
||||
* Stores given file in Shared File Store
|
||||
*
|
||||
* @param file File to be stored
|
||||
* @param file
|
||||
* File to be stored
|
||||
* @return A FileRefResponse containing detail about file's reference
|
||||
*/
|
||||
public FileRefResponse saveFile(File file)
|
||||
@@ -121,9 +124,9 @@ public class SharedFileStoreClient
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MULTIPART_FORM_DATA);
|
||||
HttpEntity<LinkedMultiValueMap<String, Object>> requestEntity = new HttpEntity<>(map,
|
||||
headers);
|
||||
headers);
|
||||
ResponseEntity<FileRefResponse> responseEntity = restTemplate
|
||||
.exchange(url, POST, requestEntity, FileRefResponse.class);
|
||||
.exchange(url, POST, requestEntity, FileRefResponse.class);
|
||||
return responseEntity.getBody();
|
||||
}
|
||||
catch (HttpClientErrorException e)
|
||||
@@ -140,7 +143,7 @@ public class SharedFileStoreClient
|
||||
logger.debug(" Deleting intermediate file {}", fileReference);
|
||||
|
||||
client.delete().uri(fileReference)
|
||||
.exchange().block();
|
||||
.exchange().block();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
@@ -26,12 +26,12 @@
|
||||
*/
|
||||
package org.alfresco.transform.base.transform;
|
||||
|
||||
import org.alfresco.transform.exceptions.TransformException;
|
||||
import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR;
|
||||
import org.alfresco.transform.exceptions.TransformException;
|
||||
|
||||
/**
|
||||
* Separation of transform fragments logic from the {@link ProcessHandler} logic and {@link StreamHandler}.
|
||||
@@ -42,8 +42,7 @@ public abstract class FragmentHandler extends StreamHandler
|
||||
private boolean noMoreFragments;
|
||||
|
||||
protected void initTarget()
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
public OutputStream respondWithFragment(Integer index, boolean finished) throws IOException
|
||||
{
|
||||
@@ -74,8 +73,7 @@ public abstract class FragmentHandler extends StreamHandler
|
||||
}
|
||||
|
||||
protected void logFragment(Integer index, Long outputLength)
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
@Override
|
||||
protected void handleSuccessfulTransform() throws IOException
|
||||
|
@@ -26,22 +26,17 @@
|
||||
*/
|
||||
package org.alfresco.transform.base.transform;
|
||||
|
||||
import org.alfresco.transform.base.CustomTransformer;
|
||||
import org.alfresco.transform.base.TransformManager;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import org.alfresco.transform.base.CustomTransformer;
|
||||
import org.alfresco.transform.base.TransformManager;
|
||||
|
||||
/**
|
||||
* Separation of InputStream, OutputStream, sourceFile and targetFile from the {@link ProcessHandler} logic. Allows
|
||||
* {@link CustomTransformer} implementations to call {@link TransformManager#createSourceFile()} and
|
||||
* {@link TransformManager#createTargetFile()} so that extra Files are not created if there was one already in
|
||||
* existence.
|
||||
* Separation of InputStream, OutputStream, sourceFile and targetFile from the {@link ProcessHandler} logic. Allows {@link CustomTransformer} implementations to call {@link TransformManager#createSourceFile()} and {@link TransformManager#createTargetFile()} so that extra Files are not created if there was one already in existence.
|
||||
*
|
||||
* Subclasses MUST call transformManager.setSourceFile(File) and transformManager.setSourceFile(File) if they start
|
||||
* with files rather than streams, before calling the {@link #init()} method which calls
|
||||
* transformManager.setOutputStream(InputStream) and transformManager.setOutputStream(OutputStream).
|
||||
* Subclasses MUST call transformManager.setSourceFile(File) and transformManager.setSourceFile(File) if they start with files rather than streams, before calling the {@link #init()} method which calls transformManager.setOutputStream(InputStream) and transformManager.setOutputStream(OutputStream).
|
||||
*/
|
||||
public abstract class StreamHandler
|
||||
{
|
||||
@@ -95,8 +90,7 @@ public abstract class StreamHandler
|
||||
}
|
||||
|
||||
protected void onSuccessfulTransform()
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
protected void closeOutputStream() throws IOException
|
||||
{
|
||||
@@ -112,8 +106,7 @@ public abstract class StreamHandler
|
||||
inputStream.close();
|
||||
}
|
||||
catch (IOException ignore)
|
||||
{
|
||||
}
|
||||
{}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -26,34 +26,18 @@
|
||||
*/
|
||||
package org.alfresco.transform.base.transform;
|
||||
|
||||
import org.alfresco.transform.base.sfs.SharedFileStoreClient;
|
||||
import org.alfresco.transform.base.messaging.TransformReplySender;
|
||||
import org.alfresco.transform.base.model.FileRefResponse;
|
||||
import org.alfresco.transform.base.probes.ProbeTransform;
|
||||
import org.alfresco.transform.base.registry.CustomTransformers;
|
||||
import org.alfresco.transform.client.model.InternalContext;
|
||||
import org.alfresco.transform.client.model.TransformReply;
|
||||
import org.alfresco.transform.client.model.TransformRequest;
|
||||
import org.alfresco.transform.common.ExtensionService;
|
||||
import org.alfresco.transform.exceptions.TransformException;
|
||||
import org.alfresco.transform.common.TransformerDebug;
|
||||
import org.alfresco.transform.messages.TransformRequestValidator;
|
||||
import org.alfresco.transform.messages.TransformStack;
|
||||
import org.alfresco.transform.registry.TransformServiceRegistry;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.validation.DirectFieldBindingResult;
|
||||
import org.springframework.validation.Errors;
|
||||
import org.springframework.web.client.HttpClientErrorException;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import static java.util.stream.Collectors.joining;
|
||||
|
||||
import static org.springframework.http.HttpStatus.BAD_REQUEST;
|
||||
import static org.springframework.http.HttpStatus.CREATED;
|
||||
import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR;
|
||||
|
||||
import static org.alfresco.transform.base.fs.FileManager.createAttachment;
|
||||
import static org.alfresco.transform.base.fs.FileManager.createTargetFile;
|
||||
import static org.alfresco.transform.base.fs.FileManager.getDirectAccessUrlInputStream;
|
||||
import static org.alfresco.transform.base.fs.FileManager.getMultipartFileInputStream;
|
||||
import static org.alfresco.transform.common.RequestParamMap.DIRECT_ACCESS_URL;
|
||||
|
||||
import jakarta.jms.Destination;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
@@ -66,16 +50,35 @@ import java.io.OutputStream;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import jakarta.jms.Destination;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
import static java.util.stream.Collectors.joining;
|
||||
import static org.alfresco.transform.base.fs.FileManager.createAttachment;
|
||||
import static org.alfresco.transform.base.fs.FileManager.createTargetFile;
|
||||
import static org.alfresco.transform.base.fs.FileManager.getDirectAccessUrlInputStream;
|
||||
import static org.alfresco.transform.base.fs.FileManager.getMultipartFileInputStream;
|
||||
import static org.alfresco.transform.common.RequestParamMap.DIRECT_ACCESS_URL;
|
||||
import static org.springframework.http.HttpStatus.BAD_REQUEST;
|
||||
import static org.springframework.http.HttpStatus.CREATED;
|
||||
import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.validation.DirectFieldBindingResult;
|
||||
import org.springframework.validation.Errors;
|
||||
import org.springframework.web.client.HttpClientErrorException;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import org.alfresco.transform.base.messaging.TransformReplySender;
|
||||
import org.alfresco.transform.base.model.FileRefResponse;
|
||||
import org.alfresco.transform.base.probes.ProbeTransform;
|
||||
import org.alfresco.transform.base.registry.CustomTransformers;
|
||||
import org.alfresco.transform.base.sfs.SharedFileStoreClient;
|
||||
import org.alfresco.transform.client.model.InternalContext;
|
||||
import org.alfresco.transform.client.model.TransformReply;
|
||||
import org.alfresco.transform.client.model.TransformRequest;
|
||||
import org.alfresco.transform.common.ExtensionService;
|
||||
import org.alfresco.transform.common.TransformerDebug;
|
||||
import org.alfresco.transform.exceptions.TransformException;
|
||||
import org.alfresco.transform.messages.TransformRequestValidator;
|
||||
import org.alfresco.transform.messages.TransformStack;
|
||||
import org.alfresco.transform.registry.TransformServiceRegistry;
|
||||
|
||||
/**
|
||||
* Handles the transform requests from either http or a message.
|
||||
@@ -109,9 +112,8 @@ public class TransformHandler
|
||||
AtomicReference<ResponseEntity<Resource>> responseEntity = new AtomicReference<>();
|
||||
|
||||
new ProcessHandler(sourceMimetype, targetMimetype, requestParameters,
|
||||
"e" + httpRequestCount.getAndIncrement(), transformRegistry,
|
||||
transformerDebug, probeTransform, customTransformers)
|
||||
{
|
||||
"e" + httpRequestCount.getAndIncrement(), transformRegistry,
|
||||
transformerDebug, probeTransform, customTransformers) {
|
||||
@Override
|
||||
protected void init() throws IOException
|
||||
{
|
||||
@@ -143,7 +145,7 @@ public class TransformHandler
|
||||
protected void sendTransformResponse(TransformManagerImpl transformManager)
|
||||
{
|
||||
String extension = ExtensionService.getExtensionForTargetMimetype(targetMimetype, sourceMimetype);
|
||||
responseEntity.set(createAttachment("transform."+extension, transformManager.getTargetFile()));
|
||||
responseEntity.set(createAttachment("transform." + extension, transformManager.getTargetFile()));
|
||||
}
|
||||
}.handleTransformRequest();
|
||||
|
||||
@@ -151,12 +153,11 @@ public class TransformHandler
|
||||
}
|
||||
|
||||
public void handleProbeRequest(String sourceMimetype, String targetMimetype, Map<String, String> transformOptions,
|
||||
File sourceFile, File targetFile, ProbeTransform probeTransform)
|
||||
File sourceFile, File targetFile, ProbeTransform probeTransform)
|
||||
{
|
||||
new ProcessHandler(sourceMimetype, targetMimetype, transformOptions,
|
||||
"p" + httpRequestCount.getAndIncrement(), transformRegistry,
|
||||
transformerDebug, probeTransform, customTransformers)
|
||||
{
|
||||
"p" + httpRequestCount.getAndIncrement(), transformRegistry,
|
||||
transformerDebug, probeTransform, customTransformers) {
|
||||
@Override
|
||||
protected void init() throws IOException
|
||||
{
|
||||
@@ -187,13 +188,12 @@ public class TransformHandler
|
||||
}
|
||||
|
||||
public TransformReply handleMessageRequest(TransformRequest request, Long timeout, Destination replyToQueue,
|
||||
ProbeTransform probeTransform)
|
||||
ProbeTransform probeTransform)
|
||||
{
|
||||
TransformReply reply = createBasicTransformReply(request);
|
||||
new ProcessHandler(request.getSourceMediaType(), request.getTargetMediaType(),
|
||||
request.getTransformRequestOptions(),"unset", transformRegistry,
|
||||
transformerDebug, probeTransform, customTransformers)
|
||||
{
|
||||
request.getTransformRequestOptions(), "unset", transformRegistry,
|
||||
transformerDebug, probeTransform, customTransformers) {
|
||||
@Override
|
||||
protected void init() throws IOException
|
||||
{
|
||||
@@ -337,12 +337,12 @@ public class TransformHandler
|
||||
}
|
||||
|
||||
private InputStream getInputStreamForHandleHttpRequest(Map<String, String> requestParameters,
|
||||
MultipartFile sourceMultipartFile)
|
||||
MultipartFile sourceMultipartFile)
|
||||
{
|
||||
final String directUrl = requestParameters.getOrDefault(DIRECT_ACCESS_URL, "");
|
||||
return new BufferedInputStream(directUrl.isBlank()
|
||||
? getMultipartFileInputStream(sourceMultipartFile)
|
||||
: getDirectAccessUrlInputStream(directUrl));
|
||||
? getMultipartFileInputStream(sourceMultipartFile)
|
||||
: getDirectAccessUrlInputStream(directUrl));
|
||||
}
|
||||
|
||||
private InputStream getInputStreamForHandleProbeRequest(File sourceFile)
|
||||
@@ -419,8 +419,8 @@ public class TransformHandler
|
||||
{
|
||||
e = e.getCause();
|
||||
sb.append(", cause ")
|
||||
.append(e.getClass().getSimpleName()).append(": ")
|
||||
.append(e.getMessage());
|
||||
.append(e.getClass().getSimpleName()).append(": ")
|
||||
.append(e.getMessage());
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
|
@@ -26,17 +26,16 @@
|
||||
*/
|
||||
package org.alfresco.transform.base.util;
|
||||
|
||||
import org.alfresco.transform.base.CustomTransformer;
|
||||
import org.alfresco.transform.base.TransformManager;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.transform.base.CustomTransformer;
|
||||
import org.alfresco.transform.base.TransformManager;
|
||||
|
||||
/**
|
||||
* Helper interface for older code that uses Files rather than InputStreams and OutputStreams.
|
||||
* If you can, refactor your code to NOT use Files.
|
||||
* Helper interface for older code that uses Files rather than InputStreams and OutputStreams. If you can, refactor your code to NOT use Files.
|
||||
*/
|
||||
public interface CustomTransformerFileAdaptor extends CustomTransformer
|
||||
{
|
||||
@@ -52,4 +51,4 @@ public interface CustomTransformerFileAdaptor extends CustomTransformer
|
||||
|
||||
void transform(String sourceMimetype, String targetMimetype, Map<String, String> transformOptions,
|
||||
File sourceFile, File targetFile, TransformManager transformManager) throws Exception;
|
||||
}
|
||||
}
|
||||
|
@@ -61,4 +61,4 @@ public class OutputStreamLengthRecorder extends FilterOutputStream
|
||||
{
|
||||
super.write(b, off, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -29,13 +29,13 @@ package org.alfresco.transform.base.util;
|
||||
public class Util
|
||||
{
|
||||
private Util()
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
/**
|
||||
* Safely converts a {@link String} to an {@link Integer}
|
||||
*
|
||||
* @param param String to be converted
|
||||
* @param param
|
||||
* String to be converted
|
||||
* @return Null if param is null or converted value as {@link Integer}
|
||||
*/
|
||||
public static Integer stringToInteger(final String param)
|
||||
@@ -46,7 +46,8 @@ public class Util
|
||||
/**
|
||||
* Safely converts a {@link String} to a {@link Boolean}
|
||||
*
|
||||
* @param param String to be converted
|
||||
* @param param
|
||||
* String to be converted
|
||||
* @return Null if param is null or converted value as {@link Boolean}
|
||||
*/
|
||||
public static Boolean stringToBoolean(final String param)
|
||||
@@ -57,7 +58,8 @@ public class Util
|
||||
/**
|
||||
* Safely converts a {@link String} to a {@link Long}
|
||||
*
|
||||
* @param param String to be converted
|
||||
* @param param
|
||||
* String to be converted
|
||||
* @return Null if param is null or converted value as {@link Boolean}
|
||||
*/
|
||||
public static Long stringToLong(final String param)
|
||||
|
@@ -26,30 +26,22 @@
|
||||
*/
|
||||
package org.alfresco.transform.base;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.alfresco.transform.base.sfs.SharedFileStoreClient;
|
||||
import org.alfresco.transform.base.executors.CommandExecutor;
|
||||
import org.alfresco.transform.base.executors.RuntimeExec;
|
||||
import org.alfresco.transform.base.model.FileRefEntity;
|
||||
import org.alfresco.transform.base.model.FileRefResponse;
|
||||
import org.alfresco.transform.base.probes.ProbeTransform;
|
||||
import org.alfresco.transform.base.transform.TransformHandler;
|
||||
import org.alfresco.transform.client.model.TransformReply;
|
||||
import org.alfresco.transform.client.model.TransformRequest;
|
||||
import org.alfresco.transform.registry.TransformServiceRegistry;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.boot.test.mock.mockito.SpyBean;
|
||||
import org.springframework.mock.web.MockMultipartFile;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.ResultActions;
|
||||
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.springframework.http.HttpHeaders.ACCEPT;
|
||||
import static org.springframework.http.HttpHeaders.CONTENT_TYPE;
|
||||
import static org.springframework.http.HttpStatus.BAD_REQUEST;
|
||||
import static org.springframework.http.HttpStatus.CREATED;
|
||||
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
import static org.alfresco.transform.common.RequestParamMap.DIRECT_ACCESS_URL;
|
||||
import static org.alfresco.transform.common.RequestParamMap.ENDPOINT_TRANSFORM;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
@@ -64,25 +56,36 @@ import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
|
||||
import static org.alfresco.transform.common.RequestParamMap.DIRECT_ACCESS_URL;
|
||||
import static org.alfresco.transform.common.RequestParamMap.ENDPOINT_TRANSFORM;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.springframework.http.HttpHeaders.ACCEPT;
|
||||
import static org.springframework.http.HttpHeaders.CONTENT_TYPE;
|
||||
import static org.springframework.http.HttpStatus.BAD_REQUEST;
|
||||
import static org.springframework.http.HttpStatus.CREATED;
|
||||
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.boot.test.mock.mockito.SpyBean;
|
||||
import org.springframework.mock.web.MockMultipartFile;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.ResultActions;
|
||||
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||
|
||||
import org.alfresco.transform.base.executors.CommandExecutor;
|
||||
import org.alfresco.transform.base.executors.RuntimeExec;
|
||||
import org.alfresco.transform.base.model.FileRefEntity;
|
||||
import org.alfresco.transform.base.model.FileRefResponse;
|
||||
import org.alfresco.transform.base.probes.ProbeTransform;
|
||||
import org.alfresco.transform.base.sfs.SharedFileStoreClient;
|
||||
import org.alfresco.transform.base.transform.TransformHandler;
|
||||
import org.alfresco.transform.client.model.TransformReply;
|
||||
import org.alfresco.transform.client.model.TransformRequest;
|
||||
import org.alfresco.transform.registry.TransformServiceRegistry;
|
||||
|
||||
/**
|
||||
* Super class for unit testing.
|
||||
*/
|
||||
@SpringBootTest(classes={org.alfresco.transform.base.Application.class})
|
||||
@SpringBootTest(classes = {org.alfresco.transform.base.Application.class})
|
||||
@AutoConfigureMockMvc
|
||||
public abstract class AbstractBaseTest
|
||||
{
|
||||
@@ -123,8 +126,7 @@ public abstract class AbstractBaseTest
|
||||
/**
|
||||
* The expected result. Taken resting target quick file's bytes.
|
||||
*
|
||||
* Note: These checks generally don't work on Windows (Mac and Linux are okay). Possibly to do with byte order
|
||||
* loading.
|
||||
* Note: These checks generally don't work on Windows (Mac and Linux are okay). Possibly to do with byte order loading.
|
||||
*/
|
||||
protected byte[] expectedTargetFileBytes;
|
||||
|
||||
@@ -134,7 +136,7 @@ public abstract class AbstractBaseTest
|
||||
private RuntimeExec origCheckCommand;
|
||||
|
||||
protected void setMockExternalCommandsOnTransformer(CommandExecutor commandExecutor, RuntimeExec mockTransformCommand,
|
||||
RuntimeExec mockCheckCommand)
|
||||
RuntimeExec mockCheckCommand)
|
||||
{
|
||||
this.commandExecutor = commandExecutor;
|
||||
origTransformCommand = (RuntimeExec) ReflectionTestUtils.getField(commandExecutor, "transformCommand");
|
||||
@@ -150,27 +152,27 @@ public abstract class AbstractBaseTest
|
||||
}
|
||||
|
||||
protected void mockTransformCommand(String sourceExtension,
|
||||
String targetExtension, String sourceMimetype,
|
||||
boolean readTargetFileBytes) throws IOException
|
||||
{
|
||||
}
|
||||
String targetExtension, String sourceMimetype,
|
||||
boolean readTargetFileBytes) throws IOException
|
||||
{}
|
||||
|
||||
protected void updateTransformRequestWithSpecificOptions(TransformRequest transformRequest)
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
/**
|
||||
* This method ends up being the core of the mock.
|
||||
* It copies content from an existing file in the resources folder to the desired location
|
||||
* in order to simulate a successful transformation.
|
||||
* This method ends up being the core of the mock. It copies content from an existing file in the resources folder to the desired location in order to simulate a successful transformation.
|
||||
*
|
||||
* @param actualTargetExtension Requested extension.
|
||||
* @param testFile The test file (transformed) - basically the result.
|
||||
* @param targetFile The location where the content from the testFile should be copied
|
||||
* @throws IOException in case of any errors.
|
||||
* @param actualTargetExtension
|
||||
* Requested extension.
|
||||
* @param testFile
|
||||
* The test file (transformed) - basically the result.
|
||||
* @param targetFile
|
||||
* The location where the content from the testFile should be copied
|
||||
* @throws IOException
|
||||
* in case of any errors.
|
||||
*/
|
||||
public void generateTargetFileFromResourceFile(String actualTargetExtension, File testFile,
|
||||
File targetFile) throws IOException
|
||||
File targetFile) throws IOException
|
||||
{
|
||||
if (testFile == null)
|
||||
{
|
||||
@@ -179,13 +181,14 @@ public abstract class AbstractBaseTest
|
||||
if (testFile != null)
|
||||
{
|
||||
try (var inputStream = new FileInputStream(testFile);
|
||||
var outputStream = new FileOutputStream(targetFile))
|
||||
var outputStream = new FileOutputStream(targetFile))
|
||||
{
|
||||
FileChannel source = inputStream.getChannel();
|
||||
FileChannel target = outputStream.getChannel();
|
||||
target.transferFrom(source, 0, source.size());
|
||||
|
||||
} catch (Exception e)
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
@@ -218,7 +221,7 @@ public abstract class AbstractBaseTest
|
||||
{
|
||||
// Each use of the tempDir should result in a unique directory being used
|
||||
testFile = new File(tempDir, testFilename);
|
||||
Files.copy(classLoader.getResourceAsStream(testFilename), testFile.toPath(),REPLACE_EXISTING);
|
||||
Files.copy(classLoader.getResourceAsStream(testFilename), testFile.toPath(), REPLACE_EXISTING);
|
||||
}
|
||||
|
||||
return testFileUrl == null ? null : testFile;
|
||||
@@ -253,7 +256,7 @@ public abstract class AbstractBaseTest
|
||||
}
|
||||
|
||||
private MockHttpServletRequestBuilder mockMvcRequestWithMockMultipartFile(String url, MockMultipartFile sourceFile,
|
||||
String... params)
|
||||
String... params)
|
||||
{
|
||||
MockHttpServletRequestBuilder builder = MockMvcRequestBuilders.multipart(ENDPOINT_TRANSFORM).file(sourceFile);
|
||||
|
||||
@@ -272,18 +275,18 @@ public abstract class AbstractBaseTest
|
||||
protected TransformRequest createTransformRequest(String sourceFileRef, File sourceFile)
|
||||
{
|
||||
return TransformRequest.builder()
|
||||
.withRequestId("1")
|
||||
.withSchema(1)
|
||||
.withClientData("Alfresco Digital Business Platform")
|
||||
.withTransformRequestOptions(options)
|
||||
.withSourceReference(sourceFileRef)
|
||||
.withSourceExtension(sourceExtension)
|
||||
.withSourceMediaType(sourceMimetype)
|
||||
.withSourceSize(sourceFile.length())
|
||||
.withTargetExtension(targetExtension)
|
||||
.withTargetMediaType(targetMimetype)
|
||||
.withInternalContextForTransformEngineTests()
|
||||
.build();
|
||||
.withRequestId("1")
|
||||
.withSchema(1)
|
||||
.withClientData("Alfresco Digital Business Platform")
|
||||
.withTransformRequestOptions(options)
|
||||
.withSourceReference(sourceFileRef)
|
||||
.withSourceExtension(sourceExtension)
|
||||
.withSourceMediaType(sourceMimetype)
|
||||
.withSourceSize(sourceFile.length())
|
||||
.withTargetExtension(targetExtension)
|
||||
.withTargetMediaType(targetMimetype)
|
||||
.withInternalContextForTransformEngineTests()
|
||||
.build();
|
||||
}
|
||||
|
||||
public static void resetProbeForTesting(ProbeTransform probe)
|
||||
@@ -294,21 +297,21 @@ public abstract class AbstractBaseTest
|
||||
ReflectionTestUtils.setField(probe, "maxTime", Long.MAX_VALUE);
|
||||
ReflectionTestUtils.setField(probe, "nextTransformTime", 0);
|
||||
|
||||
((AtomicBoolean)ReflectionTestUtils.getField(probe, "initialised")).set(false);
|
||||
((AtomicBoolean)ReflectionTestUtils.getField(probe, "readySent")).set(false);
|
||||
((AtomicLong)ReflectionTestUtils.getField(probe, "transformCount")).set(0);
|
||||
((AtomicBoolean)ReflectionTestUtils.getField(probe, "die")).set(false);
|
||||
((AtomicBoolean) ReflectionTestUtils.getField(probe, "initialised")).set(false);
|
||||
((AtomicBoolean) ReflectionTestUtils.getField(probe, "readySent")).set(false);
|
||||
((AtomicLong) ReflectionTestUtils.getField(probe, "transformCount")).set(0);
|
||||
((AtomicBoolean) ReflectionTestUtils.getField(probe, "die")).set(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpleTransformTest() throws Exception
|
||||
{
|
||||
mockMvc.perform(
|
||||
mockMvcRequest(ENDPOINT_TRANSFORM, sourceFile))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().bytes(expectedTargetFileBytes))
|
||||
.andExpect(header().string("Content-Disposition",
|
||||
"attachment; filename*=UTF-8''transform." + targetExtension));
|
||||
mockMvcRequest(ENDPOINT_TRANSFORM, sourceFile))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().bytes(expectedTargetFileBytes))
|
||||
.andExpect(header().string("Content-Disposition",
|
||||
"attachment; filename*=UTF-8''transform." + targetExtension));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -317,11 +320,11 @@ public abstract class AbstractBaseTest
|
||||
sourceFile = new MockMultipartFile("file", "../quick." + sourceExtension, sourceMimetype, sourceFileBytes);
|
||||
|
||||
mockMvc.perform(
|
||||
mockMvcRequest(ENDPOINT_TRANSFORM, sourceFile))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().bytes(expectedTargetFileBytes))
|
||||
.andExpect(header().string("Content-Disposition",
|
||||
"attachment; filename*=UTF-8''transform." + targetExtension));
|
||||
mockMvcRequest(ENDPOINT_TRANSFORM, sourceFile))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().bytes(expectedTargetFileBytes))
|
||||
.andExpect(header().string("Content-Disposition",
|
||||
"attachment; filename*=UTF-8''transform." + targetExtension));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -330,11 +333,11 @@ public abstract class AbstractBaseTest
|
||||
sourceFile = new MockMultipartFile("file", "../quick", sourceMimetype, sourceFileBytes);
|
||||
|
||||
mockMvc.perform(
|
||||
mockMvcRequest(ENDPOINT_TRANSFORM, sourceFile))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().bytes(expectedTargetFileBytes))
|
||||
.andExpect(header().string("Content-Disposition",
|
||||
"attachment; filename*=UTF-8''transform." + targetExtension));
|
||||
mockMvcRequest(ENDPOINT_TRANSFORM, sourceFile))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().bytes(expectedTargetFileBytes))
|
||||
.andExpect(header().string("Content-Disposition",
|
||||
"attachment; filename*=UTF-8''transform." + targetExtension));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -345,14 +348,14 @@ public abstract class AbstractBaseTest
|
||||
probeTransform.setLivenessPercent(110);
|
||||
|
||||
long[][] values = new long[][]{
|
||||
{5000, 0, Long.MAX_VALUE}, // 1st transform is ignored
|
||||
{1000, 1000, 2100}, // 1000 + 1000*1.1
|
||||
{3000, 2000, 4200}, // 2000 + 2000*1.1
|
||||
{2000, 2000, 4200},
|
||||
{6000, 3000, 6300},
|
||||
{8000, 4000, 8400},
|
||||
{4444, 4000, 8400}, // no longer in the first few, so normal and max times don't change
|
||||
{5555, 4000, 8400}
|
||||
{5000, 0, Long.MAX_VALUE}, // 1st transform is ignored
|
||||
{1000, 1000, 2100}, // 1000 + 1000*1.1
|
||||
{3000, 2000, 4200}, // 2000 + 2000*1.1
|
||||
{2000, 2000, 4200},
|
||||
{6000, 3000, 6300},
|
||||
{8000, 4000, 8400},
|
||||
{4444, 4000, 8400}, // no longer in the first few, so normal and max times don't change
|
||||
{5555, 4000, 8400}
|
||||
};
|
||||
|
||||
for (long[] v : values)
|
||||
@@ -376,16 +379,16 @@ public abstract class AbstractBaseTest
|
||||
// Serialize and call the transformer
|
||||
String tr = objectMapper.writeValueAsString(transformRequest);
|
||||
String transformationReplyAsString = mockMvc
|
||||
.perform(MockMvcRequestBuilders
|
||||
.post(ENDPOINT_TRANSFORM)
|
||||
.header(ACCEPT, APPLICATION_JSON_VALUE)
|
||||
.header(CONTENT_TYPE, APPLICATION_JSON_VALUE)
|
||||
.content(tr))
|
||||
.andExpect(status().is(BAD_REQUEST.value()))
|
||||
.andReturn().getResponse().getContentAsString();
|
||||
.perform(MockMvcRequestBuilders
|
||||
.post(ENDPOINT_TRANSFORM)
|
||||
.header(ACCEPT, APPLICATION_JSON_VALUE)
|
||||
.header(CONTENT_TYPE, APPLICATION_JSON_VALUE)
|
||||
.content(tr))
|
||||
.andExpect(status().is(BAD_REQUEST.value()))
|
||||
.andReturn().getResponse().getContentAsString();
|
||||
|
||||
TransformReply transformReply = objectMapper.readValue(transformationReplyAsString,
|
||||
TransformReply.class);
|
||||
TransformReply.class);
|
||||
|
||||
// Assert the reply
|
||||
assertEquals(BAD_REQUEST.value(), transformReply.getStatus());
|
||||
@@ -437,11 +440,11 @@ public abstract class AbstractBaseTest
|
||||
String directUrl = "file://" + dauSourceFile.toPath();
|
||||
|
||||
ResultActions resultActions = mockMvc.perform(
|
||||
mockMvcRequest(ENDPOINT_TRANSFORM, null)
|
||||
.param(DIRECT_ACCESS_URL, directUrl))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(header().string("Content-Disposition",
|
||||
"attachment; filename*=UTF-8''transform."+targetExtension));
|
||||
mockMvcRequest(ENDPOINT_TRANSFORM, null)
|
||||
.param(DIRECT_ACCESS_URL, directUrl))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(header().string("Content-Disposition",
|
||||
"attachment; filename*=UTF-8''transform." + targetExtension));
|
||||
|
||||
if (expectedTargetFileBytes != null)
|
||||
{
|
||||
|
@@ -1,24 +1,19 @@
|
||||
package org.alfresco.transform.base;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
|
||||
import org.springframework.http.client.MultipartBodyBuilder;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import org.testcontainers.containers.GenericContainer;
|
||||
import org.testcontainers.containers.wait.strategy.Wait;
|
||||
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import static org.springframework.http.HttpStatus.OK;
|
||||
import static org.springframework.http.HttpStatus.TOO_MANY_REQUESTS;
|
||||
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.http.client.MultipartBodyBuilder;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
import org.testcontainers.containers.GenericContainer;
|
||||
import org.testcontainers.containers.wait.strategy.Wait;
|
||||
|
||||
public abstract class LivenessReadinessProbeTest
|
||||
{
|
||||
@@ -34,12 +29,9 @@ public abstract class LivenessReadinessProbeTest
|
||||
env.start();
|
||||
var url = "http://localhost:" + env.getFirstMappedPort();
|
||||
|
||||
/*
|
||||
Asserts that /ready probe hasn't died before sending a transformation request.
|
||||
Each /ready request creates a valid transformation and increases the counter of
|
||||
used transformations, hence the need to divide MAX_TRANSFORMS
|
||||
*/
|
||||
for (int i = 0; i<MAX_TRANSFORMS/2; i++) {
|
||||
/* Asserts that /ready probe hasn't died before sending a transformation request. Each /ready request creates a valid transformation and increases the counter of used transformations, hence the need to divide MAX_TRANSFORMS */
|
||||
for (int i = 0; i < MAX_TRANSFORMS / 2; i++)
|
||||
{
|
||||
assertProbeIsOk(url);
|
||||
sendTransformRequest(url, testData.sourceMimetype, testData.targetMimetype, testData.filename);
|
||||
}
|
||||
@@ -56,13 +48,13 @@ public abstract class LivenessReadinessProbeTest
|
||||
private GenericContainer<?> createEnv(String image) throws URISyntaxException
|
||||
{
|
||||
System.out.println(image);
|
||||
final GenericContainer<?> transformCore = new GenericContainer<>("alfresco/"+image+":latest");
|
||||
final GenericContainer<?> transformCore = new GenericContainer<>("alfresco/" + image + ":latest");
|
||||
|
||||
return transformCore.withEnv("livenessTransformEnabled", "true")
|
||||
.withEnv("maxTransforms", MAX_TRANSFORMS.toString())
|
||||
.withNetworkAliases(image)
|
||||
.withExposedPorts(8090)
|
||||
.waitingFor(Wait.forListeningPort());
|
||||
.withEnv("maxTransforms", MAX_TRANSFORMS.toString())
|
||||
.withNetworkAliases(image)
|
||||
.withExposedPorts(8090)
|
||||
.waitingFor(Wait.forListeningPort());
|
||||
}
|
||||
|
||||
protected static class ImagesForTests
|
||||
@@ -106,7 +98,7 @@ public abstract class LivenessReadinessProbeTest
|
||||
|
||||
private static void assertProbeDied(String url)
|
||||
{
|
||||
WebTestClient client = WebTestClient.bindToServer().baseUrl(url+"/ready").build();
|
||||
WebTestClient client = WebTestClient.bindToServer().baseUrl(url + "/ready").build();
|
||||
client.get()
|
||||
.exchange()
|
||||
.expectStatus().isEqualTo(TOO_MANY_REQUESTS);
|
||||
@@ -114,9 +106,9 @@ public abstract class LivenessReadinessProbeTest
|
||||
|
||||
private static void assertProbeIsOk(String url)
|
||||
{
|
||||
WebTestClient client = WebTestClient.bindToServer().baseUrl(url+"/ready").build();
|
||||
WebTestClient client = WebTestClient.bindToServer().baseUrl(url + "/ready").build();
|
||||
client.get()
|
||||
.exchange()
|
||||
.expectStatus().isEqualTo(OK);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -26,6 +26,18 @@
|
||||
*/
|
||||
package org.alfresco.transform.base;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.KeyStore;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.UnrecoverableKeyException;
|
||||
import java.security.cert.CertificateException;
|
||||
import javax.net.ssl.SSLContext;
|
||||
|
||||
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
|
||||
import org.apache.hc.client5.http.impl.classic.HttpClients;
|
||||
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
|
||||
@@ -42,19 +54,8 @@ import org.springframework.http.client.ClientHttpRequestFactory;
|
||||
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.KeyStore;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.UnrecoverableKeyException;
|
||||
import java.security.cert.CertificateException;
|
||||
|
||||
public class MtlsTestUtils {
|
||||
public class MtlsTestUtils
|
||||
{
|
||||
|
||||
private static final boolean MTLS_ENABLED = Boolean.parseBoolean(System.getProperty("test-mtls-enabled"));
|
||||
private static final boolean HOSTNAME_VERIFICATION_DISABLED = Boolean.parseBoolean(System.getProperty("test-client-disable-hostname-verification"));
|
||||
@@ -96,20 +97,20 @@ public class MtlsTestUtils {
|
||||
return HttpClients.custom().setConnectionManager(buildSslConnectionManager(sslContext)).build();
|
||||
}
|
||||
|
||||
private static HttpClientConnectionManager buildSslConnectionManager(SSLContext sslContext) {
|
||||
final SSLConnectionSocketFactoryBuilder sslConnectionSocketFactoryBuilder =
|
||||
SSLConnectionSocketFactoryBuilder.create()
|
||||
.setSslContext(sslContext)
|
||||
.setTlsVersions(TLS.V_1_2, TLS.V_1_3);
|
||||
if (HOSTNAME_VERIFICATION_DISABLED) {
|
||||
private static HttpClientConnectionManager buildSslConnectionManager(SSLContext sslContext)
|
||||
{
|
||||
final SSLConnectionSocketFactoryBuilder sslConnectionSocketFactoryBuilder = SSLConnectionSocketFactoryBuilder.create()
|
||||
.setSslContext(sslContext)
|
||||
.setTlsVersions(TLS.V_1_2, TLS.V_1_3);
|
||||
if (HOSTNAME_VERIFICATION_DISABLED)
|
||||
{
|
||||
sslConnectionSocketFactoryBuilder.setHostnameVerifier(NoopHostnameVerifier.INSTANCE);
|
||||
}
|
||||
final SSLConnectionSocketFactory sslConnectionSocketFactory = sslConnectionSocketFactoryBuilder.build();
|
||||
|
||||
final Registry<ConnectionSocketFactory> sslSocketFactoryRegistry =
|
||||
RegistryBuilder.<ConnectionSocketFactory> create()
|
||||
.register("https", sslConnectionSocketFactory)
|
||||
.build();
|
||||
final Registry<ConnectionSocketFactory> sslSocketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory> create()
|
||||
.register("https", sslConnectionSocketFactory)
|
||||
.build();
|
||||
|
||||
return new PoolingHttpClientConnectionManager(sslSocketFactoryRegistry);
|
||||
}
|
||||
@@ -117,9 +118,12 @@ public class MtlsTestUtils {
|
||||
public static RestTemplate restTemplateWithMtls()
|
||||
{
|
||||
ClientHttpRequestFactory requestFactory = null;
|
||||
try {
|
||||
try
|
||||
{
|
||||
requestFactory = new HttpComponentsClientHttpRequestFactory(httpClientWithMtls());
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
return new RestTemplate(requestFactory);
|
||||
@@ -130,7 +134,8 @@ public class MtlsTestUtils {
|
||||
return MtlsTestUtils.isMtlsEnabled() ? MtlsTestUtils.restTemplateWithMtls() : new RestTemplate();
|
||||
}
|
||||
|
||||
public static CloseableHttpClient getHttpClient() throws UnrecoverableKeyException, CertificateException, NoSuchAlgorithmException, KeyStoreException, IOException, KeyManagementException {
|
||||
public static CloseableHttpClient getHttpClient() throws UnrecoverableKeyException, CertificateException, NoSuchAlgorithmException, KeyStoreException, IOException, KeyManagementException
|
||||
{
|
||||
return MtlsTestUtils.isMtlsEnabled() ? MtlsTestUtils.httpClientWithMtls() : HttpClients.createDefault();
|
||||
}
|
||||
}
|
||||
|
@@ -8,12 +8,13 @@
|
||||
package org.alfresco.transform.base.clients;
|
||||
|
||||
import static java.util.Collections.emptyMap;
|
||||
import static org.alfresco.transform.common.RequestParamMap.ENDPOINT_TRANSFORM;
|
||||
|
||||
import static org.springframework.http.MediaType.MULTIPART_FORM_DATA;
|
||||
|
||||
import static org.alfresco.transform.common.RequestParamMap.ENDPOINT_TRANSFORM;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.transform.base.MtlsTestUtils;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.http.HttpEntity;
|
||||
@@ -23,6 +24,8 @@ import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import org.alfresco.transform.base.MtlsTestUtils;
|
||||
|
||||
/**
|
||||
* @author Cezar Leahu
|
||||
*/
|
||||
@@ -31,16 +34,16 @@ public class HttpClient
|
||||
private static final RestTemplate REST_TEMPLATE = MtlsTestUtils.getRestTemplate();
|
||||
|
||||
public static ResponseEntity<Resource> sendTRequest(
|
||||
final String engineUrl, final String sourceFile,
|
||||
final String sourceMimetype, final String targetMimetype, final String targetExtension)
|
||||
final String engineUrl, final String sourceFile,
|
||||
final String sourceMimetype, final String targetMimetype, final String targetExtension)
|
||||
{
|
||||
return sendTRequest(engineUrl, sourceFile, sourceMimetype, targetMimetype, targetExtension, emptyMap());
|
||||
}
|
||||
|
||||
public static ResponseEntity<Resource> sendTRequest(
|
||||
final String engineUrl, final String sourceFile,
|
||||
final String sourceMimetype, final String targetMimetype, final String targetExtension,
|
||||
final Map<String, String> transformOptions)
|
||||
final String engineUrl, final String sourceFile,
|
||||
final String sourceMimetype, final String targetMimetype, final String targetExtension,
|
||||
final Map<String, String> transformOptions)
|
||||
{
|
||||
final HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MULTIPART_FORM_DATA);
|
||||
|
@@ -34,7 +34,7 @@ public class JacksonSerializer
|
||||
public static <T> byte[] serialize(T value) throws Exception
|
||||
{
|
||||
try (final ByteArrayOutputStream stream = new ByteArrayOutputStream(1024);
|
||||
final OutputStreamWriter writer = new OutputStreamWriter(stream, UTF_8))
|
||||
final OutputStreamWriter writer = new OutputStreamWriter(stream, UTF_8))
|
||||
{
|
||||
MAPPER.writer().writeValue(writer, value);
|
||||
return stream.toByteArray();
|
||||
|
@@ -18,17 +18,16 @@ import jakarta.jms.MessageProducer;
|
||||
import jakarta.jms.Session;
|
||||
import jakarta.jms.TextMessage;
|
||||
|
||||
import org.alfresco.transform.client.model.TransformReply;
|
||||
import org.alfresco.transform.client.model.TransformRequest;
|
||||
import org.apache.activemq.ActiveMQConnection;
|
||||
import org.apache.activemq.ActiveMQConnectionFactory;
|
||||
import org.apache.activemq.command.ActiveMQQueue;
|
||||
|
||||
import org.alfresco.transform.client.model.TransformReply;
|
||||
import org.alfresco.transform.client.model.TransformRequest;
|
||||
|
||||
/**
|
||||
* JMSClient
|
||||
*
|
||||
* Contains the bare minimum logic necessary for sending and receiving T-Request/Reply messages
|
||||
* through the basic vanilla ActiveMQ client.
|
||||
* Contains the bare minimum logic necessary for sending and receiving T-Request/Reply messages through the basic vanilla ActiveMQ client.
|
||||
*
|
||||
* Used by Aspose t-engine and t-router, but likely to be useful in other t-engines.
|
||||
*
|
||||
@@ -51,29 +50,28 @@ public class JmsClient
|
||||
}
|
||||
|
||||
public void sendBytesMessage(final TransformRequest request)
|
||||
throws Exception
|
||||
throws Exception
|
||||
{
|
||||
sendBytesMessage(request, request.getRequestId());
|
||||
}
|
||||
|
||||
public void sendBytesMessage(final TransformRequest request, final String correlationID)
|
||||
throws Exception
|
||||
throws Exception
|
||||
{
|
||||
sendBytesMessage(JacksonSerializer.serialize(request), correlationID);
|
||||
}
|
||||
|
||||
public void sendBytesMessage(final TransformRequest request, final String correlationID,
|
||||
final Destination replyTo) throws Exception
|
||||
final Destination replyTo) throws Exception
|
||||
{
|
||||
sendBytesMessage(JacksonSerializer.serialize(request), correlationID, replyTo);
|
||||
}
|
||||
|
||||
public void sendBytesMessage(final byte[] data, final String correlationID) throws
|
||||
Exception
|
||||
public void sendBytesMessage(final byte[] data, final String correlationID) throws Exception
|
||||
{
|
||||
try (final Connection connection = factory.createConnection();
|
||||
final Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
|
||||
final MessageProducer producer = session.createProducer(queue))
|
||||
final Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
|
||||
final MessageProducer producer = session.createProducer(queue))
|
||||
{
|
||||
producer.setDeliveryMode(DeliveryMode.PERSISTENT);
|
||||
final BytesMessage message = session.createBytesMessage();
|
||||
@@ -87,11 +85,11 @@ public class JmsClient
|
||||
}
|
||||
|
||||
public void sendBytesMessage(final byte[] data, final String correlationID,
|
||||
final Destination replyTo) throws Exception
|
||||
final Destination replyTo) throws Exception
|
||||
{
|
||||
try (final Connection connection = factory.createConnection();
|
||||
final Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
|
||||
final MessageProducer producer = session.createProducer(queue))
|
||||
final Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
|
||||
final MessageProducer producer = session.createProducer(queue))
|
||||
{
|
||||
producer.setDeliveryMode(DeliveryMode.PERSISTENT);
|
||||
final BytesMessage message = session.createBytesMessage();
|
||||
@@ -109,23 +107,22 @@ public class JmsClient
|
||||
}
|
||||
|
||||
public void sendTextMessage(final TransformRequest request)
|
||||
throws Exception
|
||||
throws Exception
|
||||
{
|
||||
sendTextMessage(request, request.getRequestId());
|
||||
}
|
||||
|
||||
public void sendTextMessage(final TransformRequest request, final String correlationID)
|
||||
throws Exception
|
||||
throws Exception
|
||||
{
|
||||
sendTextMessage(new String(JacksonSerializer.serialize(request)), correlationID);
|
||||
}
|
||||
|
||||
public void sendTextMessage(final String data, final String correlationID) throws
|
||||
Exception
|
||||
public void sendTextMessage(final String data, final String correlationID) throws Exception
|
||||
{
|
||||
try (final Connection connection = factory.createConnection();
|
||||
final Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
|
||||
final MessageProducer producer = session.createProducer(queue))
|
||||
final Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
|
||||
final MessageProducer producer = session.createProducer(queue))
|
||||
{
|
||||
producer.setDeliveryMode(DeliveryMode.PERSISTENT);
|
||||
final TextMessage message = session.createTextMessage(data);
|
||||
@@ -143,11 +140,11 @@ public class JmsClient
|
||||
}
|
||||
|
||||
public TransformReply receiveMessage(final long timeout)
|
||||
throws Exception
|
||||
throws Exception
|
||||
{
|
||||
try (final Connection connection = factory.createConnection();
|
||||
final Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
|
||||
final MessageConsumer consumer = session.createConsumer(queue))
|
||||
final Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
|
||||
final MessageConsumer consumer = session.createConsumer(queue))
|
||||
{
|
||||
connection.start();
|
||||
|
||||
@@ -167,11 +164,9 @@ public class JmsClient
|
||||
try
|
||||
{
|
||||
while (receiveMessage(2 * 1000) != null)
|
||||
{
|
||||
}
|
||||
{}
|
||||
}
|
||||
catch (Exception ignore)
|
||||
{
|
||||
}
|
||||
{}
|
||||
}
|
||||
}
|
||||
|
@@ -21,7 +21,9 @@ import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
|
||||
import org.alfresco.transform.base.MtlsTestUtils;
|
||||
import ch.qos.logback.classic.Level;
|
||||
import ch.qos.logback.classic.Logger;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import org.apache.hc.client5.http.classic.methods.HttpGet;
|
||||
import org.apache.hc.client5.http.classic.methods.HttpHead;
|
||||
import org.apache.hc.client5.http.classic.methods.HttpPost;
|
||||
@@ -36,10 +38,7 @@ import org.apache.hc.core5.http.HttpResponse;
|
||||
import org.apache.hc.core5.http.io.entity.EntityUtils;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
import ch.qos.logback.classic.Level;
|
||||
import ch.qos.logback.classic.Logger;
|
||||
import org.alfresco.transform.base.MtlsTestUtils;
|
||||
|
||||
/**
|
||||
* Used by Aspose t-engine and t-router, but likely to be useful in other t-engines.
|
||||
@@ -69,12 +68,12 @@ public class SfsClient
|
||||
final File file = readFile(fileToUploadName);
|
||||
|
||||
final HttpPost post = new HttpPost(
|
||||
sfsBaseUrl+"/alfresco/api/-default-/private/sfs/versions/1/file");
|
||||
sfsBaseUrl + "/alfresco/api/-default-/private/sfs/versions/1/file");
|
||||
post.setEntity(MultipartEntityBuilder
|
||||
.create()
|
||||
.setMode(HttpMultipartMode.LEGACY)
|
||||
.addPart("file", new FileBody(file, ContentType.DEFAULT_BINARY))
|
||||
.build());
|
||||
.create()
|
||||
.setMode(HttpMultipartMode.LEGACY)
|
||||
.addPart("file", new FileBody(file, ContentType.DEFAULT_BINARY))
|
||||
.build());
|
||||
|
||||
try (CloseableHttpClient client = MtlsTestUtils.getHttpClient())
|
||||
{
|
||||
@@ -83,7 +82,7 @@ public class SfsClient
|
||||
if (status >= 200 && status < 300)
|
||||
{
|
||||
return JacksonSerializer.readStringValue(EntityUtils.toString(((HttpEntityContainer) response).getEntity()),
|
||||
"entry.fileRef");
|
||||
"entry.fileRef");
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -114,7 +113,7 @@ public class SfsClient
|
||||
{
|
||||
final String[] array = uri.toString().split("!");
|
||||
try (final FileSystem fs = FileSystems.newFileSystem(URI.create(array[0]),
|
||||
ImmutableMap.of("create", "true")))
|
||||
ImmutableMap.of("create", "true")))
|
||||
{
|
||||
File temp = File.createTempFile("temp-", "", new File(System.getProperty("user.dir")));
|
||||
temp.deleteOnExit();
|
||||
@@ -124,7 +123,7 @@ public class SfsClient
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean checkFile(final String uuid) throws Exception
|
||||
public static boolean checkFile(final String uuid) throws Exception
|
||||
{
|
||||
return checkFile(uuid, SFS_BASE_URL);
|
||||
}
|
||||
@@ -132,8 +131,8 @@ public class SfsClient
|
||||
public static boolean checkFile(final String uuid, final String sfsBaseUrl) throws Exception
|
||||
{
|
||||
final HttpHead head = new HttpHead(format(
|
||||
sfsBaseUrl+"/alfresco/api/-default-/private/sfs/versions/1/file/{0}",
|
||||
uuid));
|
||||
sfsBaseUrl + "/alfresco/api/-default-/private/sfs/versions/1/file/{0}",
|
||||
uuid));
|
||||
|
||||
try (CloseableHttpClient client = MtlsTestUtils.getHttpClient())
|
||||
{
|
||||
@@ -151,8 +150,8 @@ public class SfsClient
|
||||
public static File downloadFile(final String uuid, final String sfsBaseUrl) throws Exception
|
||||
{
|
||||
final HttpGet get = new HttpGet(format(
|
||||
sfsBaseUrl+"/alfresco/api/-default-/private/sfs/versions/1/file/{0}",
|
||||
uuid));
|
||||
sfsBaseUrl + "/alfresco/api/-default-/private/sfs/versions/1/file/{0}",
|
||||
uuid));
|
||||
|
||||
try (CloseableHttpClient client = MtlsTestUtils.getHttpClient())
|
||||
{
|
||||
@@ -169,7 +168,7 @@ public class SfsClient
|
||||
}
|
||||
|
||||
final File file = File.createTempFile(uuid, "_tmp",
|
||||
new File(System.getProperty("user.dir")));
|
||||
new File(System.getProperty("user.dir")));
|
||||
file.deleteOnExit();
|
||||
|
||||
try (OutputStream os = new FileOutputStream(file))
|
||||
|
@@ -47,11 +47,13 @@ public class SourceTarget
|
||||
@Override
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
if (this == o)
|
||||
return true;
|
||||
if (o == null || getClass() != o.getClass())
|
||||
return false;
|
||||
SourceTarget that = (SourceTarget) o;
|
||||
return Objects.equals(source, that.source) &&
|
||||
Objects.equals(target, that.target);
|
||||
Objects.equals(target, that.target);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -26,9 +26,10 @@
|
||||
*/
|
||||
package org.alfresco.transform.base.fakes;
|
||||
|
||||
import org.springframework.boot.test.context.TestComponent;
|
||||
|
||||
import org.alfresco.transform.base.TransformEngine;
|
||||
import org.alfresco.transform.base.probes.ProbeTransform;
|
||||
import org.springframework.boot.test.context.TestComponent;
|
||||
|
||||
/**
|
||||
* Subclass MUST be named FakeTransformEngineWith\<something> otherwise the engine name will be "undefined".
|
||||
@@ -39,18 +40,20 @@ public abstract class AbstractFakeTransformEngine implements TransformEngine
|
||||
|
||||
private static final String FAKE_TRANSFORM_ENGINE_WITH = "FakeTransformEngineWith";
|
||||
|
||||
@Override public String getTransformEngineName()
|
||||
@Override
|
||||
public String getTransformEngineName()
|
||||
{
|
||||
String simpleClassName = getClass().getSimpleName();
|
||||
return simpleClassName.startsWith(FAKE_TRANSFORM_ENGINE_WITH)
|
||||
? "0000 "+simpleClassName.substring(FAKE_TRANSFORM_ENGINE_WITH.length())
|
||||
: "undefined";
|
||||
? "0000 " + simpleClassName.substring(FAKE_TRANSFORM_ENGINE_WITH.length())
|
||||
: "undefined";
|
||||
}
|
||||
|
||||
@Override public String getStartupMessage()
|
||||
@Override
|
||||
public String getStartupMessage()
|
||||
{
|
||||
return "Startup "+getTransformEngineName()+
|
||||
"\nLine 2 "+getTransformEngineName()+
|
||||
return "Startup " + getTransformEngineName() +
|
||||
"\nLine 2 " + getTransformEngineName() +
|
||||
"\nLine 3";
|
||||
}
|
||||
|
||||
|
@@ -26,21 +26,21 @@
|
||||
*/
|
||||
package org.alfresco.transform.base.fakes;
|
||||
|
||||
import org.alfresco.transform.base.CustomTransformer;
|
||||
import org.alfresco.transform.base.TransformManager;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.test.context.TestComponent;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.test.context.TestComponent;
|
||||
|
||||
import org.alfresco.transform.base.CustomTransformer;
|
||||
import org.alfresco.transform.base.TransformManager;
|
||||
|
||||
/**
|
||||
* Subclass MUST be named FakeTransformer\<something>. Appends the name of the CustomTransformer and any t-options
|
||||
* to the output. The output is always a String regardless of the stated mimetypes.
|
||||
* Subclass MUST be named FakeTransformer\<something>. Appends the name of the CustomTransformer and any t-options to the output. The output is always a String regardless of the stated mimetypes.
|
||||
*/
|
||||
@TestComponent
|
||||
public abstract class AbstractFakeTransformer implements CustomTransformer
|
||||
@@ -65,9 +65,9 @@ public abstract class AbstractFakeTransformer implements CustomTransformer
|
||||
.append(getTransformerName())
|
||||
.append("(")
|
||||
.append(transformOptions.entrySet()
|
||||
.stream()
|
||||
.map(e -> e.getKey() + '=' + e.getValue())
|
||||
.collect(Collectors.joining(", ")))
|
||||
.stream()
|
||||
.map(e -> e.getKey() + '=' + e.getValue())
|
||||
.collect(Collectors.joining(", ")))
|
||||
.append(')')
|
||||
.toString();
|
||||
logger.info(newValue);
|
||||
|
@@ -26,23 +26,26 @@
|
||||
*/
|
||||
package org.alfresco.transform.base.fakes;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import org.alfresco.transform.base.probes.ProbeTransform;
|
||||
import org.alfresco.transform.config.TransformConfig;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
public class FakeTransformEngineWithAllInOne extends AbstractFakeTransformEngine
|
||||
{
|
||||
@Autowired
|
||||
private FakeTransformEngineWithTwoCustomTransformers oneOfTheTransformEngines;
|
||||
|
||||
@Override public TransformConfig getTransformConfig()
|
||||
@Override
|
||||
public TransformConfig getTransformConfig()
|
||||
{
|
||||
// Has no config of its own. The combined config of the others is returned from the t-engine.
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override public ProbeTransform getProbeTransform()
|
||||
@Override
|
||||
public ProbeTransform getProbeTransform()
|
||||
{
|
||||
return oneOfTheTransformEngines.getProbeTransform();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -26,38 +26,41 @@
|
||||
*/
|
||||
package org.alfresco.transform.base.fakes;
|
||||
|
||||
import static org.alfresco.transform.common.Mimetype.MIMETYPE_IMAGE_JPEG;
|
||||
import static org.alfresco.transform.common.Mimetype.MIMETYPE_PDF;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
import org.alfresco.transform.base.probes.ProbeTransform;
|
||||
import org.alfresco.transform.config.SupportedSourceAndTarget;
|
||||
import org.alfresco.transform.config.TransformConfig;
|
||||
import org.alfresco.transform.config.Transformer;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import static org.alfresco.transform.common.Mimetype.MIMETYPE_IMAGE_JPEG;
|
||||
import static org.alfresco.transform.common.Mimetype.MIMETYPE_PDF;
|
||||
|
||||
public class FakeTransformEngineWithFragments extends AbstractFakeTransformEngine
|
||||
public class FakeTransformEngineWithFragments extends AbstractFakeTransformEngine
|
||||
{
|
||||
@Override public TransformConfig getTransformConfig()
|
||||
@Override
|
||||
public TransformConfig getTransformConfig()
|
||||
{
|
||||
return TransformConfig.builder()
|
||||
.withTransformers(ImmutableList.of(
|
||||
Transformer.builder()
|
||||
.withTransformerName("Fragments")
|
||||
.withSupportedSourceAndTargetList(ImmutableSet.of(
|
||||
SupportedSourceAndTarget.builder()
|
||||
.withSourceMediaType(MIMETYPE_PDF)
|
||||
.withTargetMediaType(MIMETYPE_IMAGE_JPEG)
|
||||
.build()))
|
||||
.build()))
|
||||
.build();
|
||||
.withTransformers(ImmutableList.of(
|
||||
Transformer.builder()
|
||||
.withTransformerName("Fragments")
|
||||
.withSupportedSourceAndTargetList(ImmutableSet.of(
|
||||
SupportedSourceAndTarget.builder()
|
||||
.withSourceMediaType(MIMETYPE_PDF)
|
||||
.withTargetMediaType(MIMETYPE_IMAGE_JPEG)
|
||||
.build()))
|
||||
.build()))
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override public ProbeTransform getProbeTransform()
|
||||
@Override
|
||||
public ProbeTransform getProbeTransform()
|
||||
{
|
||||
return new ProbeTransform("probe.pdf", MIMETYPE_PDF, MIMETYPE_IMAGE_JPEG, Collections.emptyMap(),
|
||||
60, 16, 400, 10240, 60 * 30 + 1, 60 * 15 + 20);
|
||||
60, 16, 400, 10240, 60 * 30 + 1, 60 * 15 + 20);
|
||||
}
|
||||
}
|
||||
|
@@ -26,43 +26,46 @@
|
||||
*/
|
||||
package org.alfresco.transform.base.fakes;
|
||||
|
||||
import static org.alfresco.transform.common.Mimetype.MIMETYPE_IMAGE_JPEG;
|
||||
import static org.alfresco.transform.common.Mimetype.MIMETYPE_PDF;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
import org.alfresco.transform.base.probes.ProbeTransform;
|
||||
import org.alfresco.transform.config.SupportedSourceAndTarget;
|
||||
import org.alfresco.transform.config.TransformConfig;
|
||||
import org.alfresco.transform.config.TransformOptionValue;
|
||||
import org.alfresco.transform.config.Transformer;
|
||||
|
||||
import static org.alfresco.transform.common.Mimetype.MIMETYPE_IMAGE_JPEG;
|
||||
import static org.alfresco.transform.common.Mimetype.MIMETYPE_PDF;
|
||||
|
||||
public class FakeTransformEngineWithOneCustomTransformer extends AbstractFakeTransformEngine
|
||||
{
|
||||
@Override public TransformConfig getTransformConfig()
|
||||
@Override
|
||||
public TransformConfig getTransformConfig()
|
||||
{
|
||||
String imageOptions = "imageOptions";
|
||||
return TransformConfig.builder()
|
||||
.withTransformOptions(ImmutableMap.of(
|
||||
imageOptions, ImmutableSet.of(
|
||||
new TransformOptionValue(false, "width"),
|
||||
new TransformOptionValue(false, "height"))))
|
||||
.withTransformers(ImmutableList.of(
|
||||
Transformer.builder()
|
||||
.withTransformerName("Pdf2Jpg")
|
||||
.withSupportedSourceAndTargetList(ImmutableSet.of(
|
||||
SupportedSourceAndTarget.builder()
|
||||
.withSourceMediaType(MIMETYPE_PDF)
|
||||
.withTargetMediaType(MIMETYPE_IMAGE_JPEG)
|
||||
.build()))
|
||||
.withTransformOptions(ImmutableSet.of(imageOptions))
|
||||
.build()))
|
||||
.build();
|
||||
.withTransformOptions(ImmutableMap.of(
|
||||
imageOptions, ImmutableSet.of(
|
||||
new TransformOptionValue(false, "width"),
|
||||
new TransformOptionValue(false, "height"))))
|
||||
.withTransformers(ImmutableList.of(
|
||||
Transformer.builder()
|
||||
.withTransformerName("Pdf2Jpg")
|
||||
.withSupportedSourceAndTargetList(ImmutableSet.of(
|
||||
SupportedSourceAndTarget.builder()
|
||||
.withSourceMediaType(MIMETYPE_PDF)
|
||||
.withTargetMediaType(MIMETYPE_IMAGE_JPEG)
|
||||
.build()))
|
||||
.withTransformOptions(ImmutableSet.of(imageOptions))
|
||||
.build()))
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override public ProbeTransform getProbeTransform()
|
||||
@Override
|
||||
public ProbeTransform getProbeTransform()
|
||||
{
|
||||
return null; // Not used in tests
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -26,9 +26,18 @@
|
||||
*/
|
||||
package org.alfresco.transform.base.fakes;
|
||||
|
||||
import static org.alfresco.transform.common.Mimetype.MIMETYPE_IMAGE_JPEG;
|
||||
import static org.alfresco.transform.common.Mimetype.MIMETYPE_IMAGE_PNG;
|
||||
import static org.alfresco.transform.common.Mimetype.MIMETYPE_PDF;
|
||||
import static org.alfresco.transform.common.Mimetype.MIMETYPE_TEXT_PLAIN;
|
||||
import static org.alfresco.transform.common.RequestParamMap.SOURCE_ENCODING;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
import org.alfresco.transform.base.probes.ProbeTransform;
|
||||
import org.alfresco.transform.config.SupportedSourceAndTarget;
|
||||
import org.alfresco.transform.config.TransformConfig;
|
||||
@@ -36,14 +45,6 @@ import org.alfresco.transform.config.TransformOptionValue;
|
||||
import org.alfresco.transform.config.TransformStep;
|
||||
import org.alfresco.transform.config.Transformer;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.alfresco.transform.common.Mimetype.MIMETYPE_IMAGE_JPEG;
|
||||
import static org.alfresco.transform.common.Mimetype.MIMETYPE_IMAGE_PNG;
|
||||
import static org.alfresco.transform.common.Mimetype.MIMETYPE_PDF;
|
||||
import static org.alfresco.transform.common.Mimetype.MIMETYPE_TEXT_PLAIN;
|
||||
import static org.alfresco.transform.common.RequestParamMap.SOURCE_ENCODING;
|
||||
|
||||
public class FakeTransformEngineWithTwoCustomTransformers extends AbstractFakeTransformEngine
|
||||
{
|
||||
@Override
|
||||
@@ -52,63 +53,63 @@ public class FakeTransformEngineWithTwoCustomTransformers extends AbstractFakeTr
|
||||
String docOptions = "docOptions";
|
||||
String imageOptions = "imageOptions";
|
||||
return TransformConfig.builder()
|
||||
.withTransformOptions(ImmutableMap.of(
|
||||
docOptions, ImmutableSet.of(
|
||||
new TransformOptionValue(false, "page")),
|
||||
imageOptions, ImmutableSet.of(
|
||||
new TransformOptionValue(false, "width"),
|
||||
new TransformOptionValue(false, "height"))))
|
||||
.withTransformers(ImmutableList.of(
|
||||
Transformer.builder()
|
||||
.withTransformerName("TxT2Pdf")
|
||||
.withSupportedSourceAndTargetList(ImmutableSet.of(
|
||||
SupportedSourceAndTarget.builder()
|
||||
.withSourceMediaType(MIMETYPE_TEXT_PLAIN)
|
||||
.withTargetMediaType(MIMETYPE_PDF)
|
||||
.build()))
|
||||
.withTransformOptions(ImmutableSet.of(docOptions))
|
||||
.build(),
|
||||
Transformer.builder()
|
||||
.withTransformerName("Pdf2Png")
|
||||
.withSupportedSourceAndTargetList(ImmutableSet.of(
|
||||
SupportedSourceAndTarget.builder()
|
||||
.withSourceMediaType(MIMETYPE_PDF)
|
||||
.withTargetMediaType(MIMETYPE_IMAGE_PNG)
|
||||
.build()))
|
||||
.withTransformOptions(ImmutableSet.of(imageOptions))
|
||||
.build(),
|
||||
Transformer.builder()
|
||||
.withTransformerName("Txt2PngViaPdf")
|
||||
.withTransformerPipeline(List.of(
|
||||
new TransformStep("TxT2Pdf", MIMETYPE_PDF),
|
||||
new TransformStep("Pdf2Png", null)))
|
||||
.withSupportedSourceAndTargetList(ImmutableSet.of(
|
||||
SupportedSourceAndTarget.builder()
|
||||
.withSourceMediaType(MIMETYPE_TEXT_PLAIN)
|
||||
.withTargetMediaType(MIMETYPE_IMAGE_PNG)
|
||||
.build()))
|
||||
.withTransformOptions(ImmutableSet.of(imageOptions))
|
||||
.build(),
|
||||
Transformer.builder() // Unavailable until Pdf2Jpg is added
|
||||
.withTransformerName("Txt2JpgViaPdf")
|
||||
.withTransformerPipeline(List.of(
|
||||
new TransformStep("TxT2Pdf", MIMETYPE_PDF),
|
||||
new TransformStep("Pdf2Jpg", null)))
|
||||
.withSupportedSourceAndTargetList(ImmutableSet.of(
|
||||
SupportedSourceAndTarget.builder()
|
||||
.withSourceMediaType(MIMETYPE_TEXT_PLAIN)
|
||||
.withTargetMediaType(MIMETYPE_IMAGE_JPEG)
|
||||
.build()))
|
||||
.withTransformOptions(ImmutableSet.of(imageOptions))
|
||||
.build()))
|
||||
.build();
|
||||
.withTransformOptions(ImmutableMap.of(
|
||||
docOptions, ImmutableSet.of(
|
||||
new TransformOptionValue(false, "page")),
|
||||
imageOptions, ImmutableSet.of(
|
||||
new TransformOptionValue(false, "width"),
|
||||
new TransformOptionValue(false, "height"))))
|
||||
.withTransformers(ImmutableList.of(
|
||||
Transformer.builder()
|
||||
.withTransformerName("TxT2Pdf")
|
||||
.withSupportedSourceAndTargetList(ImmutableSet.of(
|
||||
SupportedSourceAndTarget.builder()
|
||||
.withSourceMediaType(MIMETYPE_TEXT_PLAIN)
|
||||
.withTargetMediaType(MIMETYPE_PDF)
|
||||
.build()))
|
||||
.withTransformOptions(ImmutableSet.of(docOptions))
|
||||
.build(),
|
||||
Transformer.builder()
|
||||
.withTransformerName("Pdf2Png")
|
||||
.withSupportedSourceAndTargetList(ImmutableSet.of(
|
||||
SupportedSourceAndTarget.builder()
|
||||
.withSourceMediaType(MIMETYPE_PDF)
|
||||
.withTargetMediaType(MIMETYPE_IMAGE_PNG)
|
||||
.build()))
|
||||
.withTransformOptions(ImmutableSet.of(imageOptions))
|
||||
.build(),
|
||||
Transformer.builder()
|
||||
.withTransformerName("Txt2PngViaPdf")
|
||||
.withTransformerPipeline(List.of(
|
||||
new TransformStep("TxT2Pdf", MIMETYPE_PDF),
|
||||
new TransformStep("Pdf2Png", null)))
|
||||
.withSupportedSourceAndTargetList(ImmutableSet.of(
|
||||
SupportedSourceAndTarget.builder()
|
||||
.withSourceMediaType(MIMETYPE_TEXT_PLAIN)
|
||||
.withTargetMediaType(MIMETYPE_IMAGE_PNG)
|
||||
.build()))
|
||||
.withTransformOptions(ImmutableSet.of(imageOptions))
|
||||
.build(),
|
||||
Transformer.builder() // Unavailable until Pdf2Jpg is added
|
||||
.withTransformerName("Txt2JpgViaPdf")
|
||||
.withTransformerPipeline(List.of(
|
||||
new TransformStep("TxT2Pdf", MIMETYPE_PDF),
|
||||
new TransformStep("Pdf2Jpg", null)))
|
||||
.withSupportedSourceAndTargetList(ImmutableSet.of(
|
||||
SupportedSourceAndTarget.builder()
|
||||
.withSourceMediaType(MIMETYPE_TEXT_PLAIN)
|
||||
.withTargetMediaType(MIMETYPE_IMAGE_JPEG)
|
||||
.build()))
|
||||
.withTransformOptions(ImmutableSet.of(imageOptions))
|
||||
.build()))
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProbeTransform getProbeTransform()
|
||||
{
|
||||
return new ProbeTransform("original.txt", MIMETYPE_TEXT_PLAIN, MIMETYPE_PDF,
|
||||
ImmutableMap.of(SOURCE_ENCODING, "UTF-8"), 46, 0,
|
||||
150, 1024, 1, 60 * 2);
|
||||
ImmutableMap.of(SOURCE_ENCODING, "UTF-8"), 46, 0,
|
||||
150, 1024, 1, 60 * 2);
|
||||
}
|
||||
}
|
||||
|
@@ -26,31 +26,23 @@
|
||||
*/
|
||||
package org.alfresco.transform.base.fakes;
|
||||
|
||||
import org.alfresco.transform.base.TransformManager;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.transform.base.TransformManager;
|
||||
|
||||
/**
|
||||
* Returns lines in the supplied input as a sequence of transform result fragments.
|
||||
* - If the current line is {@code "Null"} no output is made and {@code null} is passed as the {@code index} to
|
||||
* {@link TransformManager#respondWithFragment(Integer, boolean)}. The {code finished} parameter is unset.
|
||||
* - If {@code "Finished"}, the text is written and the {code finished} parameter is set.
|
||||
* - If the current line is {@code "NullFinished"} no output is made and {@code null} is passed as the {@code index} to
|
||||
* {@code respondWithFragment}. The {code finished} parameter is set.
|
||||
* - If {@code "Ignored"} it will be written to the output, but the {@code respondWithFragment} method will not be
|
||||
* called, so should be ignored if the final line.
|
||||
* If the input is "WithoutFragments", {@code respondWithFragment} is not called.
|
||||
* Returns lines in the supplied input as a sequence of transform result fragments. - If the current line is {@code "Null"} no output is made and {@code null} is passed as the {@code index} to {@link TransformManager#respondWithFragment(Integer, boolean)}. The {code finished} parameter is unset. - If {@code "Finished"}, the text is written and the {code finished} parameter is set. - If the current line is {@code "NullFinished"} no output is made and {@code null} is passed as the {@code index} to {@code respondWithFragment}. The {code finished} parameter is set. - If {@code "Ignored"} it will be written to the output, but the {@code respondWithFragment} method will not be called, so should be ignored if the final line. If the input is "WithoutFragments", {@code respondWithFragment} is not called.
|
||||
*/
|
||||
public class FakeTransformerFragments extends AbstractFakeTransformer
|
||||
{
|
||||
@Override
|
||||
public void transform(String sourceMimetype, InputStream inputStream, String targetMimetype,
|
||||
OutputStream outputStream, Map<String, String> transformOptions, TransformManager transformManager)
|
||||
throws Exception
|
||||
OutputStream outputStream, Map<String, String> transformOptions, TransformManager transformManager)
|
||||
throws Exception
|
||||
{
|
||||
String input = new String(inputStream.readAllBytes(), StandardCharsets.UTF_8);
|
||||
String[] lines = input.split("\n");
|
||||
@@ -69,7 +61,8 @@ public class FakeTransformerFragments extends AbstractFakeTransformer
|
||||
{
|
||||
write(outputStream, line);
|
||||
}
|
||||
if (!"Ignored".equals(line)) {
|
||||
if (!"Ignored".equals(line))
|
||||
{
|
||||
outputStream = transformManager.respondWithFragment(index, finished);
|
||||
}
|
||||
}
|
||||
|
@@ -27,5 +27,4 @@
|
||||
package org.alfresco.transform.base.fakes;
|
||||
|
||||
public class FakeTransformerPdf2Jpg extends AbstractFakeTransformer
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
@@ -27,5 +27,4 @@
|
||||
package org.alfresco.transform.base.fakes;
|
||||
|
||||
public class FakeTransformerPdf2Png extends AbstractFakeTransformer
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
@@ -27,5 +27,4 @@
|
||||
package org.alfresco.transform.base.fakes;
|
||||
|
||||
public class FakeTransformerTxT2Pdf extends AbstractFakeTransformer
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
@@ -26,21 +26,23 @@
|
||||
*/
|
||||
package org.alfresco.transform.base.http;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import org.alfresco.transform.config.TransformOption;
|
||||
import org.alfresco.transform.config.TransformOptionGroup;
|
||||
import org.alfresco.transform.config.TransformOptionValue;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import static org.alfresco.transform.base.html.OptionsHelper.getOptionNames;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.alfresco.transform.base.html.OptionsHelper.getOptionNames;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.alfresco.transform.config.TransformOption;
|
||||
import org.alfresco.transform.config.TransformOptionGroup;
|
||||
import org.alfresco.transform.config.TransformOptionValue;
|
||||
|
||||
public class OptionsHelperTest
|
||||
{
|
||||
@@ -56,7 +58,7 @@ public class OptionsHelperTest
|
||||
public void singleOptionNameWithSingleValue()
|
||||
{
|
||||
Map<String, Set<TransformOption>> transformOptionsByName = ImmutableMap.of("Dummy", ImmutableSet.of(
|
||||
new TransformOptionValue(true, "startPage")));
|
||||
new TransformOptionValue(true, "startPage")));
|
||||
|
||||
assertEquals(ImmutableSet.of("startPage"), getOptionNames(transformOptionsByName));
|
||||
}
|
||||
@@ -65,7 +67,7 @@ public class OptionsHelperTest
|
||||
public void whenOptionNameEndsInOptions_stripIt()
|
||||
{
|
||||
Map<String, Set<TransformOption>> transformOptionsByName = ImmutableMap.of("DummyOptions", ImmutableSet.of(
|
||||
new TransformOptionValue(true, "startPage")));
|
||||
new TransformOptionValue(true, "startPage")));
|
||||
|
||||
assertEquals(ImmutableSet.of("startPage"), getOptionNames(transformOptionsByName));
|
||||
}
|
||||
@@ -74,7 +76,7 @@ public class OptionsHelperTest
|
||||
public void singleOptionNameWithASingleRequiredValue()
|
||||
{
|
||||
Map<String, Set<TransformOption>> transformOptionsByName = ImmutableMap.of("DummyOptions", ImmutableSet.of(
|
||||
new TransformOptionValue(true, "startPage")));
|
||||
new TransformOptionValue(true, "startPage")));
|
||||
|
||||
assertEquals(ImmutableSet.of("startPage"), getOptionNames(transformOptionsByName));
|
||||
}
|
||||
@@ -83,8 +85,8 @@ public class OptionsHelperTest
|
||||
public void singleOptionNameWithACoupleOfValues()
|
||||
{
|
||||
Map<String, Set<TransformOption>> transformOptionsByName = ImmutableMap.of("DummyOptions", ImmutableSet.of(
|
||||
new TransformOptionValue(false, "startPage"),
|
||||
new TransformOptionValue(true, "endPage")));
|
||||
new TransformOptionValue(false, "startPage"),
|
||||
new TransformOptionValue(true, "endPage")));
|
||||
|
||||
assertEquals(ImmutableSet.of("startPage", "endPage"), getOptionNames(transformOptionsByName));
|
||||
}
|
||||
@@ -93,11 +95,11 @@ public class OptionsHelperTest
|
||||
public void sortedValues()
|
||||
{
|
||||
Map<String, Set<TransformOption>> transformOptionsByName = ImmutableMap.of("DummyOptions", ImmutableSet.of(
|
||||
new TransformOptionValue(false, "a"),
|
||||
new TransformOptionValue(false, "n"),
|
||||
new TransformOptionValue(false, "k"),
|
||||
new TransformOptionValue(false, "f"),
|
||||
new TransformOptionValue(true, "z")));
|
||||
new TransformOptionValue(false, "a"),
|
||||
new TransformOptionValue(false, "n"),
|
||||
new TransformOptionValue(false, "k"),
|
||||
new TransformOptionValue(false, "f"),
|
||||
new TransformOptionValue(true, "z")));
|
||||
|
||||
assertEquals(ImmutableList.of("a", "f", "k", "n", "z"), new ArrayList<>(getOptionNames(transformOptionsByName)));
|
||||
}
|
||||
@@ -108,13 +110,12 @@ public class OptionsHelperTest
|
||||
Map<String, Set<TransformOption>> transformOptionsByName = ImmutableMap.of("DummyOptions", ImmutableSet.of(
|
||||
new TransformOptionValue(false, "startPage"),
|
||||
new TransformOptionValue(true, "endPage")),
|
||||
"Another", ImmutableSet.of(
|
||||
new TransformOptionValue(false, "scale")),
|
||||
"YetAnother", ImmutableSet.of(
|
||||
new TransformOptionValue(false, "x"),
|
||||
new TransformOptionValue(false, "y"),
|
||||
new TransformOptionValue(true, "ratio"))
|
||||
);
|
||||
"Another", ImmutableSet.of(
|
||||
new TransformOptionValue(false, "scale")),
|
||||
"YetAnother", ImmutableSet.of(
|
||||
new TransformOptionValue(false, "x"),
|
||||
new TransformOptionValue(false, "y"),
|
||||
new TransformOptionValue(true, "ratio")));
|
||||
|
||||
assertEquals(ImmutableSet.of(
|
||||
"startPage",
|
||||
@@ -123,7 +124,7 @@ public class OptionsHelperTest
|
||||
"x",
|
||||
"y",
|
||||
"ratio"),
|
||||
getOptionNames(transformOptionsByName));
|
||||
getOptionNames(transformOptionsByName));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -132,13 +133,12 @@ public class OptionsHelperTest
|
||||
Map<String, Set<TransformOption>> transformOptionsByName = ImmutableMap.of("DummyOptions", ImmutableSet.of(
|
||||
new TransformOptionValue(false, "startPage"),
|
||||
new TransformOptionValue(true, "endPage")),
|
||||
"Another", ImmutableSet.of(
|
||||
new TransformOptionValue(false, "scale")),
|
||||
"YetAnother", ImmutableSet.of(
|
||||
new TransformOptionValue(false, "x"),
|
||||
new TransformOptionValue(false, "y"),
|
||||
new TransformOptionValue(true, "scale"))
|
||||
);
|
||||
"Another", ImmutableSet.of(
|
||||
new TransformOptionValue(false, "scale")),
|
||||
"YetAnother", ImmutableSet.of(
|
||||
new TransformOptionValue(false, "x"),
|
||||
new TransformOptionValue(false, "y"),
|
||||
new TransformOptionValue(true, "scale")));
|
||||
|
||||
assertEquals(ImmutableSet.of(
|
||||
"startPage",
|
||||
@@ -146,27 +146,27 @@ public class OptionsHelperTest
|
||||
"scale",
|
||||
"x",
|
||||
"y"),
|
||||
getOptionNames(transformOptionsByName));
|
||||
getOptionNames(transformOptionsByName));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nestedGroups()
|
||||
{
|
||||
Map<String, Set<TransformOption>> transformOptionsByName = ImmutableMap.of("DummyOptions", ImmutableSet.of(
|
||||
new TransformOptionValue(false, "1"),
|
||||
new TransformOptionValue(true, "2"),
|
||||
new TransformOptionGroup(false, ImmutableSet.of(
|
||||
new TransformOptionValue(false, "3.1"),
|
||||
new TransformOptionValue(true, "3.2"),
|
||||
new TransformOptionValue(false, "3.3"))),
|
||||
new TransformOptionGroup(true, ImmutableSet.of(
|
||||
new TransformOptionValue(false, "4.1"),
|
||||
new TransformOptionValue(false, "1"),
|
||||
new TransformOptionValue(true, "2"),
|
||||
new TransformOptionGroup(false, ImmutableSet.of(
|
||||
new TransformOptionValue(false, "4.2.1"),
|
||||
new TransformOptionGroup(true, ImmutableSet.of(
|
||||
new TransformOptionValue(false, "4.2.2.1"))),
|
||||
new TransformOptionValue(true, "4.2.3"))),
|
||||
new TransformOptionValue(false, "4.3")))));
|
||||
new TransformOptionValue(false, "3.1"),
|
||||
new TransformOptionValue(true, "3.2"),
|
||||
new TransformOptionValue(false, "3.3"))),
|
||||
new TransformOptionGroup(true, ImmutableSet.of(
|
||||
new TransformOptionValue(false, "4.1"),
|
||||
new TransformOptionGroup(false, ImmutableSet.of(
|
||||
new TransformOptionValue(false, "4.2.1"),
|
||||
new TransformOptionGroup(true, ImmutableSet.of(
|
||||
new TransformOptionValue(false, "4.2.2.1"))),
|
||||
new TransformOptionValue(true, "4.2.3"))),
|
||||
new TransformOptionValue(false, "4.3")))));
|
||||
|
||||
assertEquals(ImmutableSet.of(
|
||||
"1",
|
||||
@@ -179,6 +179,6 @@ public class OptionsHelperTest
|
||||
"4.2.2.1",
|
||||
"4.2.3",
|
||||
"4.3"),
|
||||
getOptionNames(transformOptionsByName));
|
||||
getOptionNames(transformOptionsByName));
|
||||
}
|
||||
}
|
||||
|
@@ -26,9 +26,18 @@
|
||||
*/
|
||||
package org.alfresco.transform.base.http;
|
||||
|
||||
import org.alfresco.transform.base.fakes.FakeTransformEngineWithTwoCustomTransformers;
|
||||
import org.alfresco.transform.base.fakes.FakeTransformerPdf2Png;
|
||||
import org.alfresco.transform.base.fakes.FakeTransformerTxT2Pdf;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.springframework.http.HttpMethod.POST;
|
||||
import static org.springframework.http.MediaType.MULTIPART_FORM_DATA;
|
||||
|
||||
import static org.alfresco.transform.common.Mimetype.MIMETYPE_PDF;
|
||||
import static org.alfresco.transform.common.Mimetype.MIMETYPE_TEXT_PLAIN;
|
||||
import static org.alfresco.transform.common.RequestParamMap.DIRECT_ACCESS_URL;
|
||||
import static org.alfresco.transform.common.RequestParamMap.ENDPOINT_TRANSFORM;
|
||||
import static org.alfresco.transform.common.RequestParamMap.SOURCE_MIMETYPE;
|
||||
import static org.alfresco.transform.common.RequestParamMap.TARGET_MIMETYPE;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
@@ -39,33 +48,27 @@ import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
|
||||
import static org.alfresco.transform.common.Mimetype.MIMETYPE_PDF;
|
||||
import static org.alfresco.transform.common.Mimetype.MIMETYPE_TEXT_PLAIN;
|
||||
import static org.alfresco.transform.common.RequestParamMap.DIRECT_ACCESS_URL;
|
||||
import static org.alfresco.transform.common.RequestParamMap.ENDPOINT_TRANSFORM;
|
||||
import static org.alfresco.transform.common.RequestParamMap.SOURCE_MIMETYPE;
|
||||
import static org.alfresco.transform.common.RequestParamMap.TARGET_MIMETYPE;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.springframework.http.HttpMethod.POST;
|
||||
import static org.springframework.http.MediaType.MULTIPART_FORM_DATA;
|
||||
import org.alfresco.transform.base.fakes.FakeTransformEngineWithTwoCustomTransformers;
|
||||
import org.alfresco.transform.base.fakes.FakeTransformerPdf2Png;
|
||||
import org.alfresco.transform.base.fakes.FakeTransformerTxT2Pdf;
|
||||
|
||||
/**
|
||||
* Very basic requests to the TransformController using http.
|
||||
*/
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
|
||||
classes={org.alfresco.transform.base.Application.class})
|
||||
classes = {org.alfresco.transform.base.Application.class})
|
||||
@ContextConfiguration(classes = {
|
||||
FakeTransformEngineWithTwoCustomTransformers.class,
|
||||
FakeTransformerTxT2Pdf.class,
|
||||
FakeTransformerPdf2Png.class})
|
||||
FakeTransformEngineWithTwoCustomTransformers.class,
|
||||
FakeTransformerTxT2Pdf.class,
|
||||
FakeTransformerPdf2Png.class})
|
||||
public class RestTest
|
||||
{
|
||||
@Autowired
|
||||
private TestRestTemplate restTemplate;
|
||||
|
||||
private static final HttpHeaders HEADERS = new HttpHeaders();
|
||||
static {
|
||||
static
|
||||
{
|
||||
HEADERS.setContentType(MULTIPART_FORM_DATA);
|
||||
}
|
||||
|
||||
@@ -92,7 +95,7 @@ public class RestTest
|
||||
parameters.add("file", new org.springframework.core.io.ClassPathResource("original.txt"));
|
||||
|
||||
ResponseEntity<String> response = restTemplate.exchange(ENDPOINT_TRANSFORM, POST,
|
||||
new HttpEntity<>(parameters, HEADERS), String.class, "");
|
||||
new HttpEntity<>(parameters, HEADERS), String.class, "");
|
||||
|
||||
assertTrue(response.getBody().contains("Direct Access Url not found."));
|
||||
}
|
||||
@@ -106,7 +109,7 @@ public class RestTest
|
||||
parameters.add("file", new org.springframework.core.io.ClassPathResource("original.txt"));
|
||||
|
||||
ResponseEntity<String> response = restTemplate.exchange(ENDPOINT_TRANSFORM, POST,
|
||||
new HttpEntity<>(parameters, HEADERS), String.class, "");
|
||||
new HttpEntity<>(parameters, HEADERS), String.class, "");
|
||||
|
||||
assertEquals("Original Text -> TxT2Pdf()", response.getBody());
|
||||
}
|
||||
|
@@ -30,25 +30,23 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import jakarta.jms.Queue;
|
||||
|
||||
import org.alfresco.transform.client.model.TransformReply;
|
||||
import org.alfresco.transform.client.model.TransformRequest;
|
||||
import org.apache.activemq.command.ActiveMQQueue;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.jms.core.JmsTemplate;
|
||||
|
||||
import org.alfresco.transform.client.model.TransformReply;
|
||||
import org.alfresco.transform.client.model.TransformRequest;
|
||||
|
||||
/**
|
||||
* Checks that a t-engine can respond to its message queue. This is really just checking that
|
||||
* ${queue.engineRequestQueue} has been configured. The transform request can (and does fail
|
||||
* because the shared file store does not exist).
|
||||
* Checks that a t-engine can respond to its message queue. This is really just checking that ${queue.engineRequestQueue} has been configured. The transform request can (and does fail because the shared file store does not exist).
|
||||
*
|
||||
* @author Lucian Tuca
|
||||
* created on 15/01/2019
|
||||
* @author Lucian Tuca created on 15/01/2019
|
||||
*/
|
||||
@SpringBootTest(classes={org.alfresco.transform.base.Application.class},
|
||||
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
|
||||
properties = {"activemq.url=nio://localhost:61616"})
|
||||
@SpringBootTest(classes = {org.alfresco.transform.base.Application.class},
|
||||
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
|
||||
properties = {"activemq.url=nio://localhost:61616"})
|
||||
public abstract class AbstractQueueIT
|
||||
{
|
||||
@Autowired
|
||||
|
@@ -27,21 +27,6 @@
|
||||
|
||||
package org.alfresco.transform.base.messaging;
|
||||
|
||||
import org.alfresco.transform.base.TransformController;
|
||||
import org.alfresco.transform.client.model.TransformReply;
|
||||
import org.alfresco.transform.client.model.TransformRequest;
|
||||
import org.apache.activemq.command.ActiveMQObjectMessage;
|
||||
import org.apache.activemq.command.ActiveMQQueue;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.jms.support.converter.MessageConversionException;
|
||||
|
||||
import jakarta.jms.Destination;
|
||||
import jakarta.jms.JMSException;
|
||||
import jakarta.jms.Message;
|
||||
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.doThrow;
|
||||
@@ -52,7 +37,23 @@ import static org.springframework.http.HttpStatus.BAD_REQUEST;
|
||||
import static org.springframework.http.HttpStatus.CREATED;
|
||||
import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR;
|
||||
|
||||
@SpringBootTest(classes={org.alfresco.transform.base.Application.class})
|
||||
import jakarta.jms.Destination;
|
||||
import jakarta.jms.JMSException;
|
||||
import jakarta.jms.Message;
|
||||
|
||||
import org.apache.activemq.command.ActiveMQObjectMessage;
|
||||
import org.apache.activemq.command.ActiveMQQueue;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.jms.support.converter.MessageConversionException;
|
||||
|
||||
import org.alfresco.transform.base.TransformController;
|
||||
import org.alfresco.transform.client.model.TransformReply;
|
||||
import org.alfresco.transform.client.model.TransformRequest;
|
||||
|
||||
@SpringBootTest(classes = {org.alfresco.transform.base.Application.class})
|
||||
public class QueueTransformServiceTest
|
||||
{
|
||||
@Mock
|
||||
@@ -94,12 +95,12 @@ public class QueueTransformServiceTest
|
||||
msg.setJMSReplyTo(destination);
|
||||
|
||||
TransformReply reply = TransformReply
|
||||
.builder()
|
||||
.withStatus(INTERNAL_SERVER_ERROR.value())
|
||||
.withErrorDetails(
|
||||
"JMS exception during T-Request deserialization of message with correlationID "
|
||||
+ msg.getCorrelationId() + ": null")
|
||||
.build();
|
||||
.builder()
|
||||
.withStatus(INTERNAL_SERVER_ERROR.value())
|
||||
.withErrorDetails(
|
||||
"JMS exception during T-Request deserialization of message with correlationID "
|
||||
+ msg.getCorrelationId() + ": null")
|
||||
.build();
|
||||
|
||||
doReturn(null).when(transformMessageConverter).fromMessage(msg);
|
||||
|
||||
@@ -113,7 +114,7 @@ public class QueueTransformServiceTest
|
||||
|
||||
@Test
|
||||
public void testConvertMessageThrowsMessageConversionExceptionThenReplyWithBadRequest()
|
||||
throws JMSException
|
||||
throws JMSException
|
||||
{
|
||||
ActiveMQObjectMessage msg = new ActiveMQObjectMessage();
|
||||
msg.setCorrelationId("1234");
|
||||
@@ -121,12 +122,12 @@ public class QueueTransformServiceTest
|
||||
msg.setJMSReplyTo(destination);
|
||||
|
||||
TransformReply reply = TransformReply
|
||||
.builder()
|
||||
.withStatus(BAD_REQUEST.value())
|
||||
.withErrorDetails(
|
||||
"Message conversion exception during T-Request deserialization of message with correlationID"
|
||||
+ msg.getCorrelationId() + ": null")
|
||||
.build();
|
||||
.builder()
|
||||
.withStatus(BAD_REQUEST.value())
|
||||
.withErrorDetails(
|
||||
"Message conversion exception during T-Request deserialization of message with correlationID"
|
||||
+ msg.getCorrelationId() + ": null")
|
||||
.build();
|
||||
|
||||
doThrow(MessageConversionException.class).when(transformMessageConverter).fromMessage(msg);
|
||||
|
||||
@@ -140,7 +141,7 @@ public class QueueTransformServiceTest
|
||||
|
||||
@Test
|
||||
public void testConvertMessageThrowsJMSExceptionThenReplyWithInternalServerError()
|
||||
throws JMSException
|
||||
throws JMSException
|
||||
{
|
||||
ActiveMQObjectMessage msg = new ActiveMQObjectMessage();
|
||||
msg.setCorrelationId("1234");
|
||||
@@ -148,12 +149,12 @@ public class QueueTransformServiceTest
|
||||
msg.setJMSReplyTo(destination);
|
||||
|
||||
TransformReply reply = TransformReply
|
||||
.builder()
|
||||
.withStatus(INTERNAL_SERVER_ERROR.value())
|
||||
.withErrorDetails(
|
||||
"JMSException during T-Request deserialization of message with correlationID " +
|
||||
msg.getCorrelationId() + ": null")
|
||||
.build();
|
||||
.builder()
|
||||
.withStatus(INTERNAL_SERVER_ERROR.value())
|
||||
.withErrorDetails(
|
||||
"JMSException during T-Request deserialization of message with correlationID " +
|
||||
msg.getCorrelationId() + ": null")
|
||||
.build();
|
||||
|
||||
doThrow(JMSException.class).when(transformMessageConverter).fromMessage(msg);
|
||||
|
||||
@@ -174,13 +175,16 @@ public class QueueTransformServiceTest
|
||||
|
||||
TransformRequest request = new TransformRequest();
|
||||
TransformReply reply = TransformReply
|
||||
.builder()
|
||||
.withStatus(CREATED.value())
|
||||
.build();
|
||||
.builder()
|
||||
.withStatus(CREATED.value())
|
||||
.build();
|
||||
|
||||
doReturn(request).when(transformMessageConverter).fromMessage(msg);
|
||||
doAnswer(invocation -> {transformReplySender.send(destination, reply); return null;})
|
||||
.when(transformController).transform(request, null, destination);
|
||||
doAnswer(invocation -> {
|
||||
transformReplySender.send(destination, reply);
|
||||
return null;
|
||||
})
|
||||
.when(transformController).transform(request, null, destination);
|
||||
|
||||
queueTransformService.receive(msg);
|
||||
|
||||
@@ -205,7 +209,7 @@ public class QueueTransformServiceTest
|
||||
|
||||
@Test
|
||||
public void testWhenExceptionOnCorrelationIdIsThrownThenContinueFlowWithNullCorrelationId()
|
||||
throws JMSException
|
||||
throws JMSException
|
||||
{
|
||||
Message msg = mock(Message.class);
|
||||
Destination destination = mock(Destination.class);
|
||||
@@ -215,13 +219,16 @@ public class QueueTransformServiceTest
|
||||
|
||||
TransformRequest request = new TransformRequest();
|
||||
TransformReply reply = TransformReply
|
||||
.builder()
|
||||
.withStatus(CREATED.value())
|
||||
.build();
|
||||
.builder()
|
||||
.withStatus(CREATED.value())
|
||||
.build();
|
||||
|
||||
doReturn(request).when(transformMessageConverter).fromMessage(msg);
|
||||
doAnswer(invocation -> {transformReplySender.send(destination, reply); return null;})
|
||||
.when(transformController).transform(request, null, destination);
|
||||
doAnswer(invocation -> {
|
||||
transformReplySender.send(destination, reply);
|
||||
return null;
|
||||
})
|
||||
.when(transformController).transform(request, null, destination);
|
||||
|
||||
queueTransformService.receive(msg);
|
||||
|
||||
|
@@ -27,12 +27,14 @@
|
||||
package org.alfresco.transform.base.metadata;
|
||||
|
||||
import static java.text.MessageFormat.format;
|
||||
import static org.alfresco.transform.base.clients.HttpClient.sendTRequest;
|
||||
import static org.alfresco.transform.common.Mimetype.MIMETYPE_METADATA_EXTRACT;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
import static org.springframework.http.HttpStatus.OK;
|
||||
|
||||
import static org.alfresco.transform.base.clients.HttpClient.sendTRequest;
|
||||
import static org.alfresco.transform.common.Mimetype.MIMETYPE_METADATA_EXTRACT;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
@@ -42,20 +44,20 @@ import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import org.alfresco.transform.base.clients.FileInfo;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
|
||||
import org.alfresco.transform.base.clients.FileInfo;
|
||||
|
||||
/**
|
||||
* Super class of metadata integration tests. Sub classes should provide the following:
|
||||
* <p>
|
||||
* <ul>
|
||||
* <li>A method providing a
|
||||
* Stream of test files: {@code public static Stream<FileInfo> engineTransformations()}; </li>
|
||||
* <li> Provide expected json files (<sourceFilename>"_metadata.json") as resources on the classpath.</li>
|
||||
* <li> Override the method {@code testTransformation(FileInfo testFileInfo)} such that it calls
|
||||
* the super method as a {@code @ParameterizedTest} for example:</li> </ul>
|
||||
* <li>A method providing a Stream of test files: {@code public static Stream<FileInfo> engineTransformations()};</li>
|
||||
* <li>Provide expected json files (<sourceFilename>"_metadata.json") as resources on the classpath.</li>
|
||||
* <li>Override the method {@code testTransformation(FileInfo testFileInfo)} such that it calls the super method as a {@code @ParameterizedTest} for example:</li>
|
||||
* </ul>
|
||||
*
|
||||
* <pre>
|
||||
* @ParameterizedTest
|
||||
*
|
||||
@@ -68,7 +70,7 @@ import org.springframework.http.ResponseEntity;
|
||||
* {
|
||||
* super.testTransformation(FileInfo testFileInfo)
|
||||
* }
|
||||
* </pre>
|
||||
* </pre>
|
||||
*
|
||||
* @author adavis
|
||||
* @author dedwards
|
||||
@@ -82,7 +84,6 @@ public abstract class AbstractMetadataExtractsIT
|
||||
|
||||
private final ObjectMapper jsonObjectMapper = new ObjectMapper();
|
||||
|
||||
|
||||
public void testTransformation(FileInfo fileInfo)
|
||||
{
|
||||
final String sourceMimetype = fileInfo.getMimeType();
|
||||
@@ -104,7 +105,7 @@ public abstract class AbstractMetadataExtractsIT
|
||||
|
||||
Map<String, Serializable> expectedMetadata = readExpectedMetadata(metadataFilename, actualMetadataFile);
|
||||
assertEquals(expectedMetadata, actualMetadata,
|
||||
sourceFile+": The metadata did not match the expected value. It has been saved in "+actualMetadataFile.getAbsolutePath());
|
||||
sourceFile + ": The metadata did not match the expected value. It has been saved in " + actualMetadataFile.getAbsolutePath());
|
||||
actualMetadataFile.delete();
|
||||
}
|
||||
catch (Exception e)
|
||||
@@ -120,8 +121,8 @@ public abstract class AbstractMetadataExtractsIT
|
||||
{
|
||||
if (inputStream == null)
|
||||
{
|
||||
fail("The expected metadata file "+filename+" did not exist.\n"+
|
||||
"The actual metadata has been saved in "+actualMetadataFile.getAbsoluteFile());
|
||||
fail("The expected metadata file " + filename + " did not exist.\n" +
|
||||
"The actual metadata has been saved in " + actualMetadataFile.getAbsoluteFile());
|
||||
}
|
||||
return readMetadata(inputStream);
|
||||
}
|
||||
|
@@ -7,10 +7,12 @@
|
||||
*/
|
||||
package org.alfresco.transform.base.registry;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import org.alfresco.transform.base.fakes.FakeTransformEngineWithTwoCustomTransformers;
|
||||
import org.alfresco.transform.base.fakes.FakeTransformerPdf2Png;
|
||||
import org.alfresco.transform.base.fakes.FakeTransformerTxT2Pdf;
|
||||
import org.awaitility.Awaitility;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -21,19 +23,16 @@ import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.mockito.Mockito.atLeast;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import org.alfresco.transform.base.fakes.FakeTransformEngineWithTwoCustomTransformers;
|
||||
import org.alfresco.transform.base.fakes.FakeTransformerPdf2Png;
|
||||
import org.alfresco.transform.base.fakes.FakeTransformerTxT2Pdf;
|
||||
|
||||
@AutoConfigureMockMvc
|
||||
@SpringBootTest(classes={org.alfresco.transform.base.Application.class}, properties={"transform.engine.config.cron=*/1 * * * * *"})
|
||||
@SpringBootTest(classes = {org.alfresco.transform.base.Application.class}, properties = {"transform.engine.config.cron=*/1 * * * * *"})
|
||||
@ContextConfiguration(classes = {
|
||||
FakeTransformEngineWithTwoCustomTransformers.class,
|
||||
FakeTransformerTxT2Pdf.class,
|
||||
FakeTransformerPdf2Png.class})
|
||||
FakeTransformEngineWithTwoCustomTransformers.class,
|
||||
FakeTransformerTxT2Pdf.class,
|
||||
FakeTransformerPdf2Png.class})
|
||||
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)
|
||||
public class TransformRegistryRefreshTest
|
||||
{
|
||||
@@ -53,11 +52,11 @@ public class TransformRegistryRefreshTest
|
||||
|
||||
// As we can't change the content of a classpath resource, lets change what is read.
|
||||
ReflectionTestUtils.setField(transformConfigFiles, "files", ImmutableMap.of(
|
||||
"a", "config/addA2B.json",
|
||||
"foo", "config/addB2C.json"));
|
||||
"a", "config/addA2B.json",
|
||||
"foo", "config/addB2C.json"));
|
||||
transformConfigFromFiles.initFileConfig();
|
||||
|
||||
Awaitility.await().pollDelay(3, TimeUnit.SECONDS).until( () -> { // i.e. Thread.sleep(3_000) - but keeps sona happy
|
||||
Awaitility.await().pollDelay(3, TimeUnit.SECONDS).until(() -> { // i.e. Thread.sleep(3_000) - but keeps sona happy
|
||||
transformRegistry.retrieveConfig();
|
||||
assertEquals(6, transformRegistry.getTransformConfig().getTransformers().size());
|
||||
return true;
|
||||
@@ -67,8 +66,8 @@ public class TransformRegistryRefreshTest
|
||||
private void waitForRegistryReady() throws InterruptedException
|
||||
{
|
||||
Awaitility.await().atMost(1, TimeUnit.SECONDS)
|
||||
.pollInterval(100, TimeUnit.MILLISECONDS)
|
||||
.pollDelay(Duration.ZERO)
|
||||
.until(() -> transformRegistry.isReadyForTransformRequests());
|
||||
.pollInterval(100, TimeUnit.MILLISECONDS)
|
||||
.pollDelay(Duration.ZERO)
|
||||
.until(() -> transformRegistry.isReadyForTransformRequests());
|
||||
}
|
||||
}
|
||||
|
@@ -26,16 +26,21 @@
|
||||
*/
|
||||
package org.alfresco.transform.base.registry;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import static org.alfresco.transform.common.Mimetype.MIMETYPE_EXCEL;
|
||||
import static org.alfresco.transform.common.Mimetype.MIMETYPE_PDF;
|
||||
import static org.alfresco.transform.common.Mimetype.MIMETYPE_WORD;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import org.alfresco.transform.base.fakes.AbstractFakeTransformEngine;
|
||||
import org.alfresco.transform.base.fakes.FakeTransformEngineWithAllInOne;
|
||||
import org.alfresco.transform.base.fakes.FakeTransformEngineWithOneCustomTransformer;
|
||||
import org.alfresco.transform.base.fakes.FakeTransformEngineWithTwoCustomTransformers;
|
||||
import org.alfresco.transform.config.SupportedSourceAndTarget;
|
||||
import org.alfresco.transform.config.TransformConfig;
|
||||
import org.alfresco.transform.config.Transformer;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -43,20 +48,16 @@ import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMock
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.alfresco.transform.common.Mimetype.MIMETYPE_EXCEL;
|
||||
import static org.alfresco.transform.common.Mimetype.MIMETYPE_PDF;
|
||||
import static org.alfresco.transform.common.Mimetype.MIMETYPE_WORD;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import org.alfresco.transform.base.fakes.AbstractFakeTransformEngine;
|
||||
import org.alfresco.transform.base.fakes.FakeTransformEngineWithAllInOne;
|
||||
import org.alfresco.transform.base.fakes.FakeTransformEngineWithOneCustomTransformer;
|
||||
import org.alfresco.transform.base.fakes.FakeTransformEngineWithTwoCustomTransformers;
|
||||
import org.alfresco.transform.config.SupportedSourceAndTarget;
|
||||
import org.alfresco.transform.config.TransformConfig;
|
||||
import org.alfresco.transform.config.Transformer;
|
||||
|
||||
@AutoConfigureMockMvc
|
||||
@SpringBootTest(classes={org.alfresco.transform.base.Application.class})
|
||||
@SpringBootTest(classes = {org.alfresco.transform.base.Application.class})
|
||||
public class TransformRegistryTest
|
||||
{
|
||||
@Autowired
|
||||
@@ -86,9 +87,9 @@ public class TransformRegistryTest
|
||||
private String getTransformerNames(TransformConfig transformConfig)
|
||||
{
|
||||
return transformConfig.getTransformers().stream()
|
||||
.map(Transformer::getTransformerName)
|
||||
.sorted()
|
||||
.collect(Collectors.joining(", "));
|
||||
.map(Transformer::getTransformerName)
|
||||
.sorted()
|
||||
.collect(Collectors.joining(", "));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -101,7 +102,7 @@ public class TransformRegistryTest
|
||||
public void singleTransformEngine()
|
||||
{
|
||||
ReflectionTestUtils.setField(transformConfigFromTransformEngines, "transformEngines", ImmutableList.of(
|
||||
new FakeTransformEngineWithOneCustomTransformer()));
|
||||
new FakeTransformEngineWithOneCustomTransformer()));
|
||||
transformConfigFromTransformEngines.initTransformEngineConfig();
|
||||
transformRegistry.retrieveConfig();
|
||||
|
||||
@@ -112,34 +113,34 @@ public class TransformRegistryTest
|
||||
public void multipleTransformEngines()
|
||||
{
|
||||
ReflectionTestUtils.setField(transformConfigFromTransformEngines, "transformEngines", ImmutableList.of(
|
||||
new FakeTransformEngineWithAllInOne(),
|
||||
new FakeTransformEngineWithOneCustomTransformer(),
|
||||
new FakeTransformEngineWithTwoCustomTransformers()));
|
||||
new FakeTransformEngineWithAllInOne(),
|
||||
new FakeTransformEngineWithOneCustomTransformer(),
|
||||
new FakeTransformEngineWithTwoCustomTransformers()));
|
||||
transformConfigFromTransformEngines.initTransformEngineConfig();
|
||||
transformRegistry.retrieveConfig();
|
||||
|
||||
assertEquals("Pdf2Jpg, Pdf2Png, TxT2Pdf, Txt2JpgViaPdf, Txt2PngViaPdf",
|
||||
getTransformerNames(transformRegistry.getTransformConfig()));
|
||||
getTransformerNames(transformRegistry.getTransformConfig()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void uncombinedConfigFromEngine()
|
||||
{
|
||||
ReflectionTestUtils.setField(transformConfigFromTransformEngines, "transformEngines", ImmutableList.of(
|
||||
new FakeTransformEngineWithAllInOne(),
|
||||
new FakeTransformEngineWithTwoCustomTransformers()));
|
||||
new FakeTransformEngineWithAllInOne(),
|
||||
new FakeTransformEngineWithTwoCustomTransformers()));
|
||||
transformConfigFromTransformEngines.initTransformEngineConfig();
|
||||
transformRegistry.retrieveConfig();
|
||||
|
||||
assertEquals("Pdf2Png, TxT2Pdf, Txt2JpgViaPdf, Txt2PngViaPdf",
|
||||
getTransformerNames(transformRegistry.getTransformConfig()));
|
||||
getTransformerNames(transformRegistry.getTransformConfig()));
|
||||
|
||||
ReflectionTestUtils.setField(transformRegistry, "isTRouter", true);
|
||||
transformConfigFromTransformEngines.initTransformEngineConfig();
|
||||
transformRegistry.retrieveConfig();
|
||||
|
||||
assertEquals("Pdf2Png, TxT2Pdf, Txt2PngViaPdf",
|
||||
getTransformerNames(transformRegistry.getTransformConfig()));
|
||||
getTransformerNames(transformRegistry.getTransformConfig()));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -147,23 +148,23 @@ public class TransformRegistryTest
|
||||
{
|
||||
ReflectionTestUtils.setField(transformRegistry, "isTRouter", true);
|
||||
ReflectionTestUtils.setField(transformConfigFromTransformEngines, "transformEngines", ImmutableList.of(
|
||||
new FakeTransformEngineWithAllInOne(),
|
||||
new FakeTransformEngineWithTwoCustomTransformers()));
|
||||
new FakeTransformEngineWithAllInOne(),
|
||||
new FakeTransformEngineWithTwoCustomTransformers()));
|
||||
transformConfigFromTransformEngines.initTransformEngineConfig();
|
||||
transformRegistry.retrieveConfig();
|
||||
|
||||
assertEquals("Pdf2Png, TxT2Pdf, Txt2PngViaPdf",
|
||||
getTransformerNames(transformRegistry.getTransformConfig()));
|
||||
getTransformerNames(transformRegistry.getTransformConfig()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void singleTransformEngineWithAdditionalConfig()
|
||||
{
|
||||
ReflectionTestUtils.setField(transformConfigFromTransformEngines, "transformEngines", ImmutableList.of(
|
||||
new FakeTransformEngineWithOneCustomTransformer()));
|
||||
new FakeTransformEngineWithOneCustomTransformer()));
|
||||
ReflectionTestUtils.setField(transformConfigFiles, "files", ImmutableMap.of(
|
||||
"a", "config/addA2B.json",
|
||||
"foo", "config/addB2C.json"));
|
||||
"a", "config/addA2B.json",
|
||||
"foo", "config/addB2C.json"));
|
||||
|
||||
transformConfigFromTransformEngines.initTransformEngineConfig();
|
||||
transformConfigFromFiles.initFileConfig();
|
||||
@@ -176,10 +177,10 @@ public class TransformRegistryTest
|
||||
public void singleTransformEngineWithHistoricAdditionalRoutes()
|
||||
{
|
||||
ReflectionTestUtils.setField(transformConfigFromTransformEngines, "transformEngines", ImmutableList.of(
|
||||
new FakeTransformEngineWithOneCustomTransformer()));
|
||||
new FakeTransformEngineWithOneCustomTransformer()));
|
||||
ReflectionTestUtils.setField(transformConfigFilesHistoric, "additional", ImmutableMap.of(
|
||||
"a", "config/addA2B.json",
|
||||
"foo", "config/addB2C.json"));
|
||||
"a", "config/addA2B.json",
|
||||
"foo", "config/addB2C.json"));
|
||||
|
||||
transformConfigFromTransformEngines.initTransformEngineConfig();
|
||||
transformConfigFromFiles.initFileConfig();
|
||||
@@ -192,11 +193,11 @@ public class TransformRegistryTest
|
||||
public void singleTransformEngineWithHistoricTransformerRoutesExternalFile()
|
||||
{
|
||||
ReflectionTestUtils.setField(transformConfigFromTransformEngines, "transformEngines", ImmutableList.of(
|
||||
new FakeTransformEngineWithOneCustomTransformer()));
|
||||
new FakeTransformEngineWithOneCustomTransformer()));
|
||||
ReflectionTestUtils.setField(transformConfigFilesHistoric, "TRANSFORMER_ROUTES_FROM_CLASSPATH",
|
||||
"config/removePdf2JpgAndAddA2Z.json"); // checking it is ignored
|
||||
"config/removePdf2JpgAndAddA2Z.json"); // checking it is ignored
|
||||
ReflectionTestUtils.setField(transformConfigFilesHistoric, "transformerRoutesExternalFile",
|
||||
"config/addA2B.json");
|
||||
"config/addA2B.json");
|
||||
|
||||
transformConfigFromTransformEngines.initTransformEngineConfig();
|
||||
transformConfigFromFiles.initFileConfig();
|
||||
@@ -209,9 +210,9 @@ public class TransformRegistryTest
|
||||
public void singleTransformEngineWithHistoricTransformerRoutesOnClasspath()
|
||||
{
|
||||
ReflectionTestUtils.setField(transformConfigFromTransformEngines, "transformEngines", ImmutableList.of(
|
||||
new FakeTransformEngineWithOneCustomTransformer()));
|
||||
new FakeTransformEngineWithOneCustomTransformer()));
|
||||
ReflectionTestUtils.setField(transformConfigFilesHistoric, "TRANSFORMER_ROUTES_FROM_CLASSPATH",
|
||||
"config/removePdf2JpgAndAddA2Z.json");
|
||||
"config/removePdf2JpgAndAddA2Z.json");
|
||||
|
||||
transformConfigFromTransformEngines.initTransformEngineConfig();
|
||||
transformConfigFromFiles.initFileConfig();
|
||||
@@ -228,7 +229,7 @@ public class TransformRegistryTest
|
||||
assertFalse(transformRegistry.isReadyForTransformRequests());
|
||||
|
||||
ReflectionTestUtils.setField(transformConfigFromTransformEngines, "transformEngines", ImmutableList.of(
|
||||
new FakeTransformEngineWithOneCustomTransformer()));
|
||||
new FakeTransformEngineWithOneCustomTransformer()));
|
||||
transformConfigFromTransformEngines.initTransformEngineConfig();
|
||||
transformRegistry.retrieveConfig();
|
||||
|
||||
@@ -239,33 +240,33 @@ public class TransformRegistryTest
|
||||
public void testCheckSourceSize()
|
||||
{
|
||||
ReflectionTestUtils.setField(transformConfigFromTransformEngines, "transformEngines", ImmutableList.of(
|
||||
new AbstractFakeTransformEngine()
|
||||
{
|
||||
@Override public TransformConfig getTransformConfig()
|
||||
{
|
||||
return TransformConfig.builder()
|
||||
.withTransformers(ImmutableList.of(
|
||||
Transformer.builder()
|
||||
.withTransformerName("transformerName")
|
||||
.withSupportedSourceAndTargetList(ImmutableSet.of(
|
||||
SupportedSourceAndTarget.builder()
|
||||
.withSourceMediaType(MIMETYPE_WORD)
|
||||
.withTargetMediaType(MIMETYPE_PDF)
|
||||
.build(),
|
||||
SupportedSourceAndTarget.builder()
|
||||
.withSourceMediaType(MIMETYPE_EXCEL)
|
||||
.withTargetMediaType(MIMETYPE_PDF)
|
||||
.withMaxSourceSizeBytes(12345L)
|
||||
.build()))
|
||||
.build()))
|
||||
.build();
|
||||
}
|
||||
}));
|
||||
new AbstractFakeTransformEngine() {
|
||||
@Override
|
||||
public TransformConfig getTransformConfig()
|
||||
{
|
||||
return TransformConfig.builder()
|
||||
.withTransformers(ImmutableList.of(
|
||||
Transformer.builder()
|
||||
.withTransformerName("transformerName")
|
||||
.withSupportedSourceAndTargetList(ImmutableSet.of(
|
||||
SupportedSourceAndTarget.builder()
|
||||
.withSourceMediaType(MIMETYPE_WORD)
|
||||
.withTargetMediaType(MIMETYPE_PDF)
|
||||
.build(),
|
||||
SupportedSourceAndTarget.builder()
|
||||
.withSourceMediaType(MIMETYPE_EXCEL)
|
||||
.withTargetMediaType(MIMETYPE_PDF)
|
||||
.withMaxSourceSizeBytes(12345L)
|
||||
.build()))
|
||||
.build()))
|
||||
.build();
|
||||
}
|
||||
}));
|
||||
transformConfigFromTransformEngines.initTransformEngineConfig();
|
||||
transformRegistry.retrieveConfig();
|
||||
|
||||
assertTrue( transformRegistry.checkSourceSize("transformerName", MIMETYPE_WORD, Long.MAX_VALUE, MIMETYPE_PDF));
|
||||
assertTrue( transformRegistry.checkSourceSize("transformerName", MIMETYPE_EXCEL, 12345L, MIMETYPE_PDF));
|
||||
assertTrue(transformRegistry.checkSourceSize("transformerName", MIMETYPE_WORD, Long.MAX_VALUE, MIMETYPE_PDF));
|
||||
assertTrue(transformRegistry.checkSourceSize("transformerName", MIMETYPE_EXCEL, 12345L, MIMETYPE_PDF));
|
||||
assertFalse(transformRegistry.checkSourceSize("transformerName", MIMETYPE_EXCEL, 12346L, MIMETYPE_PDF));
|
||||
assertFalse(transformRegistry.checkSourceSize("transformerName", "doesNotExist", 12345L, MIMETYPE_PDF));
|
||||
assertFalse(transformRegistry.checkSourceSize("doesNotExist", MIMETYPE_WORD, 12345L, MIMETYPE_PDF));
|
||||
|
@@ -26,16 +26,28 @@
|
||||
*/
|
||||
package org.alfresco.transform.base.transform;
|
||||
|
||||
import static org.awaitility.Awaitility.await;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.springframework.http.HttpStatus.OK;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
import static org.alfresco.transform.base.transform.StreamHandlerTest.read;
|
||||
import static org.alfresco.transform.common.Mimetype.*;
|
||||
import static org.alfresco.transform.common.RequestParamMap.*;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import jakarta.jms.Destination;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import org.alfresco.transform.base.fakes.FakeTransformEngineWithFragments;
|
||||
import org.alfresco.transform.base.fakes.FakeTransformerFragments;
|
||||
import org.alfresco.transform.base.messaging.TransformReplySender;
|
||||
import org.alfresco.transform.base.model.FileRefEntity;
|
||||
import org.alfresco.transform.base.model.FileRefResponse;
|
||||
import org.alfresco.transform.base.probes.ProbeTransform;
|
||||
import org.alfresco.transform.base.sfs.SharedFileStoreClient;
|
||||
import org.alfresco.transform.client.model.TransformReply;
|
||||
import org.alfresco.transform.client.model.TransformRequest;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -51,31 +63,21 @@ import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||
|
||||
import jakarta.jms.Destination;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.alfresco.transform.base.transform.StreamHandlerTest.read;
|
||||
import static org.alfresco.transform.common.Mimetype.*;
|
||||
import static org.alfresco.transform.common.RequestParamMap.*;
|
||||
import static org.awaitility.Awaitility.await;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.springframework.http.HttpStatus.OK;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
import org.alfresco.transform.base.fakes.FakeTransformEngineWithFragments;
|
||||
import org.alfresco.transform.base.fakes.FakeTransformerFragments;
|
||||
import org.alfresco.transform.base.messaging.TransformReplySender;
|
||||
import org.alfresco.transform.base.model.FileRefEntity;
|
||||
import org.alfresco.transform.base.model.FileRefResponse;
|
||||
import org.alfresco.transform.base.probes.ProbeTransform;
|
||||
import org.alfresco.transform.base.sfs.SharedFileStoreClient;
|
||||
import org.alfresco.transform.client.model.TransformReply;
|
||||
import org.alfresco.transform.client.model.TransformRequest;
|
||||
|
||||
@AutoConfigureMockMvc
|
||||
@SpringBootTest(classes={org.alfresco.transform.base.Application.class})
|
||||
@SpringBootTest(classes = {org.alfresco.transform.base.Application.class})
|
||||
@ContextConfiguration(classes = {
|
||||
FakeTransformEngineWithFragments.class,
|
||||
FakeTransformerFragments.class})
|
||||
FakeTransformEngineWithFragments.class,
|
||||
FakeTransformerFragments.class})
|
||||
public class FragmentHandlerTest
|
||||
{
|
||||
@Autowired
|
||||
@@ -99,34 +101,32 @@ public class FragmentHandlerTest
|
||||
String targetReference = UUID.randomUUID().toString();
|
||||
|
||||
when(fakeSfsClient.retrieveFile(any()))
|
||||
.thenReturn(new ResponseEntity<>(new ByteArrayResource(sourceText.getBytes(StandardCharsets.UTF_8)),
|
||||
new HttpHeaders(), OK));
|
||||
.thenReturn(new ResponseEntity<>(new ByteArrayResource(sourceText.getBytes(StandardCharsets.UTF_8)),
|
||||
new HttpHeaders(), OK));
|
||||
|
||||
when(fakeSfsClient.saveFile(any()))
|
||||
.thenAnswer(invocation ->
|
||||
{
|
||||
lines.add(read(invocation.getArgument(0)));
|
||||
return new FileRefResponse(new FileRefEntity(targetReference));
|
||||
});
|
||||
.thenAnswer(invocation -> {
|
||||
lines.add(read(invocation.getArgument(0)));
|
||||
return new FileRefResponse(new FileRefEntity(targetReference));
|
||||
});
|
||||
|
||||
doAnswer(invocation ->
|
||||
{
|
||||
doAnswer(invocation -> {
|
||||
replies.add(Pair.of(invocation.getArgument(0), invocation.getArgument(1)));
|
||||
return null;
|
||||
}).when(transformReplySender).send(any(), any());
|
||||
|
||||
TransformRequest request = TransformRequest
|
||||
.builder()
|
||||
.withRequestId(UUID.randomUUID().toString())
|
||||
.withSourceMediaType(MIMETYPE_PDF)
|
||||
.withTargetMediaType(MIMETYPE_IMAGE_JPEG)
|
||||
.withTargetExtension("jpeg")
|
||||
.withSchema(1)
|
||||
.withClientData("ACS")
|
||||
.withSourceReference(sourceReference)
|
||||
.withSourceSize(32L)
|
||||
.withInternalContextForTransformEngineTests()
|
||||
.build();
|
||||
.builder()
|
||||
.withRequestId(UUID.randomUUID().toString())
|
||||
.withSourceMediaType(MIMETYPE_PDF)
|
||||
.withTargetMediaType(MIMETYPE_IMAGE_JPEG)
|
||||
.withTargetExtension("jpeg")
|
||||
.withSchema(1)
|
||||
.withClientData("ACS")
|
||||
.withSourceReference(sourceReference)
|
||||
.withSourceSize(32L)
|
||||
.withInternalContextForTransformEngineTests()
|
||||
.build();
|
||||
transformHandler.handleMessageRequest(request, Long.MAX_VALUE, null, probeTransform);
|
||||
|
||||
TransformReply lastReply = replies.get(replies.size() - 1).getRight();
|
||||
@@ -139,25 +139,26 @@ public class FragmentHandlerTest
|
||||
}
|
||||
else
|
||||
{
|
||||
assertEquals("Transform failed - "+expectedError, errorDetails);
|
||||
assertEquals("Transform failed - " + expectedError, errorDetails);
|
||||
assertEquals(HttpStatus.INTERNAL_SERVER_ERROR.value(), status);
|
||||
}
|
||||
assertEquals(expectedLines, lines);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testErrorIfHttp() {
|
||||
public void testErrorIfHttp()
|
||||
{
|
||||
String expectedError = "Fragments may only be sent via message queues. This an http request";
|
||||
await()
|
||||
.atMost(10, TimeUnit.SECONDS)
|
||||
.untilAsserted(() -> mockMvc.perform(
|
||||
MockMvcRequestBuilders.multipart(ENDPOINT_TRANSFORM)
|
||||
.file(new MockMultipartFile("file", null, MIMETYPE_TEXT_PLAIN,
|
||||
"Start".getBytes(StandardCharsets.UTF_8)))
|
||||
.param(SOURCE_MIMETYPE, MIMETYPE_PDF)
|
||||
.param(TARGET_MIMETYPE, MIMETYPE_IMAGE_JPEG))
|
||||
.andExpect(status().isInternalServerError())
|
||||
.andExpect(status().reason(containsString(expectedError))));
|
||||
.atMost(10, TimeUnit.SECONDS)
|
||||
.untilAsserted(() -> mockMvc.perform(
|
||||
MockMvcRequestBuilders.multipart(ENDPOINT_TRANSFORM)
|
||||
.file(new MockMultipartFile("file", null, MIMETYPE_TEXT_PLAIN,
|
||||
"Start".getBytes(StandardCharsets.UTF_8)))
|
||||
.param(SOURCE_MIMETYPE, MIMETYPE_PDF)
|
||||
.param(TARGET_MIMETYPE, MIMETYPE_IMAGE_JPEG))
|
||||
.andExpect(status().isInternalServerError())
|
||||
.andExpect(status().reason(containsString(expectedError))));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -176,21 +177,21 @@ public class FragmentHandlerTest
|
||||
public void testMultipleFragmentCallsWithFinished()
|
||||
{
|
||||
assertFragments("line1\nline2\nFinished", null,
|
||||
ImmutableList.of("line1", "line2", "Finished"));
|
||||
ImmutableList.of("line1", "line2", "Finished"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultipleFragmentsCallsWithoutFinish()
|
||||
{
|
||||
assertFragments("line1\nline2\nline3", null,
|
||||
ImmutableList.of("line1", "line2", "line3"));
|
||||
ImmutableList.of("line1", "line2", "line3"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultipleFragmentsCallsWithoutSendingLastFragment()
|
||||
{
|
||||
assertFragments("line1\nline2\nline3\nIgnored", null,
|
||||
ImmutableList.of("line1", "line2", "line3"));
|
||||
ImmutableList.of("line1", "line2", "line3"));
|
||||
|
||||
}
|
||||
|
||||
@@ -204,14 +205,14 @@ public class FragmentHandlerTest
|
||||
public void testEndTooEarlyUsingFinished()
|
||||
{
|
||||
assertFragments("line1\nFinished\nline3", "Final fragment already sent",
|
||||
ImmutableList.of("line1", "Finished"));
|
||||
ImmutableList.of("line1", "Finished"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEndTooEarlyUsingNull()
|
||||
{
|
||||
assertFragments("line1\nNull\nline3", "Final fragment already sent",
|
||||
ImmutableList.of("line1"));
|
||||
ImmutableList.of("line1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -232,6 +233,6 @@ public class FragmentHandlerTest
|
||||
public void testNullAndFinished()
|
||||
{
|
||||
assertFragments("line1\nNull\nFinished", "Final fragment already sent",
|
||||
ImmutableList.of("line1"));
|
||||
ImmutableList.of("line1"));
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user