This is an automated email from the ASF dual-hosted git repository.
tallison pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tika.git
The following commit(s) were added to refs/heads/main by this push:
new c29b4810b1 TIKA-4564 -- replace string.replace with actual json
interpolation in unit tests (#2439)
c29b4810b1 is described below
commit c29b4810b1011e734200bf84dcc65bca5bc9d44e
Author: Tim Allison <[email protected]>
AuthorDate: Thu Dec 11 08:56:24 2025 -0500
TIKA-4564 -- replace string.replace with actual json interpolation in unit
tests (#2439)
---
.../java/org/apache/tika/cli/TikaCLIAsyncTest.java | 27 +-
.../tika/pipes/kafka/tests/TikaPipesKafkaTest.java | 29 +-
.../pipes/opensearch/tests/OpenSearchTest.java | 47 ++-
.../resources/opensearch/plugins-template.json | 2 +-
.../tika/pipes/s3/tests/S3PipeIntegrationTest.java | 45 ++-
.../src/test/resources/s3/plugins-template.json | 34 +--
.../pipes/solr/tests/TikaPipesSolrTestBase.java | 49 ++-
.../src/test/resources/solr/plugins-template.json | 8 +-
.../apache/tika/async/cli/AsyncProcessorTest.java | 24 +-
.../apache/tika/pipes/core/PluginsTestHelper.java | 39 +--
.../pipes/core/emitter/EmitterManagerTest.java | 23 +-
.../pipes/core/fetcher/FetcherManagerTest.java | 23 +-
.../test/resources/configs/tika-config-basic.json | 2 +-
.../resources/configs/tika-config-passback.json | 2 +-
.../org/apache/tika/config/JsonConfigHelper.java | 288 ++++++++++++++++++
.../apache/tika/config/JsonConfigHelperTest.java | 336 +++++++++++++++++++++
.../src/test/resources/configs/template-test.json | 20 ++
.../org/apache/tika/server/core/CXFTestBase.java | 62 ++--
.../tika/server/core/TikaResourceFetcherTest.java | 27 +-
.../resources/configs/cxf-test-base-template.json | 4 +-
.../tika-config-server-fetcher-template.json | 2 +-
.../resources/configs/cxf-test-base-template.json | 4 +-
22 files changed, 849 insertions(+), 248 deletions(-)
diff --git a/tika-app/src/test/java/org/apache/tika/cli/TikaCLIAsyncTest.java
b/tika-app/src/test/java/org/apache/tika/cli/TikaCLIAsyncTest.java
index 5351078e93..697cc1e7e5 100644
--- a/tika-app/src/test/java/org/apache/tika/cli/TikaCLIAsyncTest.java
+++ b/tika-app/src/test/java/org/apache/tika/cli/TikaCLIAsyncTest.java
@@ -24,10 +24,11 @@ import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
-import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
+import java.util.HashMap;
+import java.util.Map;
import org.apache.commons.io.FileUtils;
import org.junit.jupiter.api.AfterEach;
@@ -38,6 +39,8 @@ import org.junit.jupiter.api.io.TempDir;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.apache.tika.config.JsonConfigHelper;
+
public class TikaCLIAsyncTest {
private static final Logger LOG = LoggerFactory.getLogger(TikaCLI.class);
@@ -60,21 +63,17 @@ public class TikaCLIAsyncTest {
TIKA_CONFIG = Files.createTempFile(ASYNC_OUTPUT_DIR, "plugins-",
".json");
Path pluginsDir = Paths.get("target/plugins");
- if (! Files.isDirectory(pluginsDir)) {
+ if (!Files.isDirectory(pluginsDir)) {
LOG.warn("CAN'T FIND PLUGINS DIR. pwd={}",
Paths.get("").toAbsolutePath().toString());
}
- String jsonTemplate =
Files.readString(Paths.get(TikaCLIAsyncTest.class.getResource("/configs/config-template.json").toURI()),
- StandardCharsets.UTF_8);
-
- String json = jsonTemplate.replace("FETCHER_BASE_PATH",
TEST_DATA_FILE.getAbsolutePath().toString())
- .replace("EMITTER_BASE_PATH",
ASYNC_OUTPUT_DIR.toAbsolutePath().toString())
- .replace("PLUGIN_ROOTS",
pluginsDir.toAbsolutePath().toString())
- .replace("TIKA_CONFIG", TIKA_CONFIG
- .toAbsolutePath().toString());
-
- ;
- json = json.replace("\\", "/");
- Files.writeString(TIKA_CONFIG, json, UTF_8);
+
+ Map<String, Object> replacements = new HashMap<>();
+ replacements.put("FETCHER_BASE_PATH", TEST_DATA_FILE.toPath());
+ replacements.put("EMITTER_BASE_PATH", ASYNC_OUTPUT_DIR);
+ replacements.put("PLUGIN_ROOTS", pluginsDir);
+
+
JsonConfigHelper.writeConfigFromResource("/configs/config-template.json",
+ TikaCLIAsyncTest.class, replacements, TIKA_CONFIG);
}
/**
diff --git
a/tika-integration-tests/tika-pipes-kafka-integration-tests/src/test/java/org/apache/tika/pipes/kafka/tests/TikaPipesKafkaTest.java
b/tika-integration-tests/tika-pipes-kafka-integration-tests/src/test/java/org/apache/tika/pipes/kafka/tests/TikaPipesKafkaTest.java
index 4884d82c9e..e42b4fb8a0 100644
---
a/tika-integration-tests/tika-pipes-kafka-integration-tests/src/test/java/org/apache/tika/pipes/kafka/tests/TikaPipesKafkaTest.java
+++
b/tika-integration-tests/tika-pipes-kafka-integration-tests/src/test/java/org/apache/tika/pipes/kafka/tests/TikaPipesKafkaTest.java
@@ -36,13 +36,11 @@ import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
-import java.util.regex.Matcher;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Stopwatch;
import org.apache.commons.io.FilenameUtils;
-import org.apache.commons.io.IOUtils;
import org.apache.kafka.clients.consumer.ConsumerConfig;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.consumer.ConsumerRecords;
@@ -65,6 +63,7 @@ import org.testcontainers.kafka.ConfluentKafkaContainer;
import org.testcontainers.utility.DockerImageName;
import org.apache.tika.cli.TikaCLI;
+import org.apache.tika.config.JsonConfigHelper;
import org.apache.tika.pipes.api.HandlerConfig;
import org.apache.tika.utils.SystemUtils;
@@ -208,30 +207,24 @@ public class TikaPipesKafkaTest {
@NotNull
private Path getTikaConfig(Path pipesDirectory, Path testFileFolderPath)
throws Exception {
- String json;
- try (InputStream is =
this.getClass().getResourceAsStream("/kafka/plugins-template.json")) {
- assert is != null;
- json = IOUtils.toString(is, StandardCharsets.UTF_8);
- }
-
- String res = json.replace("PIPE_ITERATOR_TOPIC", PIPE_ITERATOR_TOPIC)
- .replace("EMITTER_TOPIC", EMITTER_TOPIC)
- .replace("BOOTSTRAP_SERVERS", kafka.getBootstrapServers())
- .replaceAll("FETCHER_BASE_PATH",
-
Matcher.quoteReplacement(testFileFolderPath.toAbsolutePath().toString()))
- .replace("PARSE_MODE", HandlerConfig.PARSE_MODE.RMETA.name());
Path tikaConfig = pipesDirectory.resolve("tika-config.json");
- res = res.replace("TIKA_CONFIG",
tikaConfig.toAbsolutePath().toString());
-
Path log4jPropFile = pipesDirectory.resolve("log4j2.xml");
try (InputStream is =
this.getClass().getResourceAsStream("/pipes-fork-server-custom-log4j2.xml")) {
assert is != null;
Files.copy(is, log4jPropFile);
}
- res = res.replace("LOG4J_PROPERTIES_FILE",
log4jPropFile.toAbsolutePath().toString());
- Files.writeString(tikaConfig, res, StandardCharsets.UTF_8);
+ Map<String, Object> replacements = new HashMap<>();
+ replacements.put("PIPE_ITERATOR_TOPIC", PIPE_ITERATOR_TOPIC);
+ replacements.put("EMITTER_TOPIC", EMITTER_TOPIC);
+ replacements.put("BOOTSTRAP_SERVERS", kafka.getBootstrapServers());
+ replacements.put("FETCHER_BASE_PATH", testFileFolderPath);
+ replacements.put("PARSE_MODE", HandlerConfig.PARSE_MODE.RMETA.name());
+ replacements.put("LOG4J_PROPERTIES_FILE", log4jPropFile);
+
+
JsonConfigHelper.writeConfigFromResource("/kafka/plugins-template.json",
+ TikaPipesKafkaTest.class, replacements, tikaConfig);
return tikaConfig;
}
}
diff --git
a/tika-integration-tests/tika-pipes-opensearch-integration-tests/src/test/java/org/apache/tika/pipes/opensearch/tests/OpenSearchTest.java
b/tika-integration-tests/tika-pipes-opensearch-integration-tests/src/test/java/org/apache/tika/pipes/opensearch/tests/OpenSearchTest.java
index 59c41c078f..c284f96c7c 100644
---
a/tika-integration-tests/tika-pipes-opensearch-integration-tests/src/test/java/org/apache/tika/pipes/opensearch/tests/OpenSearchTest.java
+++
b/tika-integration-tests/tika-pipes-opensearch-integration-tests/src/test/java/org/apache/tika/pipes/opensearch/tests/OpenSearchTest.java
@@ -48,6 +48,7 @@ import org.testcontainers.utility.DockerImageName;
import org.apache.tika.cli.TikaCLI;
import org.apache.tika.client.HttpClientFactory;
+import org.apache.tika.config.JsonConfigHelper;
import org.apache.tika.config.loader.TikaJsonConfig;
import org.apache.tika.exception.TikaConfigException;
import org.apache.tika.metadata.Metadata;
@@ -453,43 +454,29 @@ public class OpenSearchTest {
HandlerConfig.PARSE_MODE parseMode,
String endpoint, Path testDocDirectory) throws IOException {
Path tikaConfig = pipesDirectory.resolve("plugins-config.json");
-
- String json = new
String(OpenSearchTest.class.getResourceAsStream("/opensearch/plugins-template.json").readAllBytes(),
StandardCharsets.UTF_8);
- String res =
- json.replace("ATTACHMENT_STRATEGY",
attachmentStrategy.toString())
- .replace("UPDATE_STRATEGY",
updateStrategy.toString())
- .replace("USER_NAME", CONTAINER.getUsername())
- .replace("PASSWORD", CONTAINER.getPassword())
- .replaceAll("FETCHER_BASE_PATH",
-
Matcher.quoteReplacement(testDocDirectory.toAbsolutePath().toString()))
- .replace("PARSE_MODE", parseMode.name());
-
- if (attachmentStrategy ==
OpenSearchEmitterConfig.AttachmentStrategy.PARENT_CHILD) {
- res = res.replace("INCLUDE_ROUTING", "true");
- } else {
- res = res.replace("INCLUDE_ROUTING", "false");
- }
- res = res.replace("OPEN_SEARCH_URL", endpoint);
-
- res = res.replace("TIKA_CONFIG", tikaConfig
- .toAbsolutePath()
- .toString());
-
Path log4jPropFile = pipesDirectory.resolve("log4j2.xml");
try (InputStream is = OpenSearchTest.class
.getResourceAsStream("/pipes-fork-server-custom-log4j2.xml")) {
Files.copy(is, log4jPropFile);
}
- res = res.replace("LOG4J_PROPERTIES_FILE",
log4jPropFile.toAbsolutePath().toString());
- res = res.replace("\\", "/");
- Files.writeString(tikaConfig, res, StandardCharsets.UTF_8);
- return tikaConfig;
- }
+ boolean includeRouting = (attachmentStrategy ==
OpenSearchEmitterConfig.AttachmentStrategy.PARENT_CHILD);
+
+ Map<String, Object> replacements = new HashMap<>();
+ replacements.put("ATTACHMENT_STRATEGY", attachmentStrategy.toString());
+ replacements.put("UPDATE_STRATEGY", updateStrategy.toString());
+ replacements.put("USER_NAME", CONTAINER.getUsername());
+ replacements.put("PASSWORD", CONTAINER.getPassword());
+ replacements.put("FETCHER_BASE_PATH", testDocDirectory);
+ replacements.put("PARSE_MODE", parseMode.name());
+ replacements.put("INCLUDE_ROUTING", includeRouting);
+ replacements.put("OPEN_SEARCH_URL", endpoint);
+ replacements.put("LOG4J_PROPERTIES_FILE", log4jPropFile);
- private String createTikaConfigXml(Path tikaConfigFile, String xml) {
- xml = xml.replace("TIKA_CONFIG",
tikaConfigFile.toAbsolutePath().toString());
- return xml;
+
JsonConfigHelper.writeConfigFromResource("/opensearch/plugins-template.json",
+ OpenSearchTest.class, replacements, tikaConfig);
+
+ return tikaConfig;
}
private void createTestHtmlFiles(String bodyContent, int numHtmlDocs, Path
testDocDirectory) throws Exception {
diff --git
a/tika-integration-tests/tika-pipes-opensearch-integration-tests/src/test/resources/opensearch/plugins-template.json
b/tika-integration-tests/tika-pipes-opensearch-integration-tests/src/test/resources/opensearch/plugins-template.json
index 3a3286039b..7c3663a156 100644
---
a/tika-integration-tests/tika-pipes-opensearch-integration-tests/src/test/resources/opensearch/plugins-template.json
+++
b/tika-integration-tests/tika-pipes-opensearch-integration-tests/src/test/resources/opensearch/plugins-template.json
@@ -49,7 +49,7 @@
"opensearch-pipes-reporter": {
"openSearchUrl": "OPEN_SEARCH_URL",
"keyPrefix": "my_test_",
- "includeRouting": INCLUDE_ROUTING,
+ "includeRouting": "INCLUDE_ROUTING",
"httpClientConfig": {
"userName": "USER_NAME",
"password": "PASSWORD",
diff --git
a/tika-integration-tests/tika-pipes-s3-integration-tests/src/test/java/org/apache/tika/pipes/s3/tests/S3PipeIntegrationTest.java
b/tika-integration-tests/tika-pipes-s3-integration-tests/src/test/java/org/apache/tika/pipes/s3/tests/S3PipeIntegrationTest.java
index 7fe0c9370b..b33d77c672 100644
---
a/tika-integration-tests/tika-pipes-s3-integration-tests/src/test/java/org/apache/tika/pipes/s3/tests/S3PipeIntegrationTest.java
+++
b/tika-integration-tests/tika-pipes-s3-integration-tests/src/test/java/org/apache/tika/pipes/s3/tests/S3PipeIntegrationTest.java
@@ -21,14 +21,16 @@ import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
+import java.nio.file.Path;
import java.security.NoSuchAlgorithmException;
import java.time.Duration;
import java.time.temporal.ChronoUnit;
+import java.util.HashMap;
import java.util.HashSet;
+import java.util.Map;
import java.util.Set;
import org.apache.commons.io.FileUtils;
-import org.apache.commons.io.IOUtils;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
@@ -52,6 +54,7 @@ import
software.amazon.awssdk.services.s3.model.GetObjectResponse;
import software.amazon.awssdk.services.s3.model.PutObjectRequest;
import org.apache.tika.cli.TikaCLI;
+import org.apache.tika.config.JsonConfigHelper;
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@Testcontainers(disabledWithoutDocker = true)
@@ -125,38 +128,32 @@ class S3PipeIntegrationTest {
createTestFiles();
// Setup config files
- File log4jPropFile = new File("target", "tmp-log4j2.xml");
- File tikaConfigFile = new File("target", "plugins-config-s3.json");
+ Path log4jPropFile = Path.of("target", "tmp-log4j2.xml");
+ Path tikaConfigFile = Path.of("target", "plugins-config-s3.json");
try (InputStream is = this.getClass()
.getResourceAsStream("/pipes-fork-server-custom-log4j2.xml")) {
Assertions.assertNotNull(is);
- FileUtils.copyInputStreamToFile(is, log4jPropFile);
+ FileUtils.copyInputStreamToFile(is, log4jPropFile.toFile());
}
// Create plugins config JSON
- String pluginsTemplate;
- try (InputStream is =
this.getClass().getResourceAsStream("/s3/plugins-template.json")) {
- assert is != null;
- pluginsTemplate = IOUtils.toString(is, StandardCharsets.UTF_8);
- }
-
- String pluginsConfig = pluginsTemplate
- .replace("{TIKA_CONFIG}", tikaConfigFile.getAbsolutePath())
- .replace("{LOG4J_PROPERTIES_FILE}",
log4jPropFile.getAbsolutePath())
- .replace("{PARSE_MODE}",
org.apache.tika.pipes.api.HandlerConfig.PARSE_MODE.RMETA.name())
- .replace("{PIPE_ITERATOR_BUCKET}", FETCH_BUCKET)
- .replace("{EMIT_BUCKET}", EMIT_BUCKET)
- .replace("{FETCH_BUCKET}", FETCH_BUCKET)
- .replace("{ACCESS_KEY}", ACCESS_KEY)
- .replace("{SECRET_KEY}", SECRET_KEY)
- .replace("{ENDPOINT_CONFIGURATION_SERVICE}", MINIO_ENDPOINT)
- .replace("{REGION}", REGION.id());
-
- FileUtils.writeStringToFile(tikaConfigFile, pluginsConfig,
StandardCharsets.UTF_8);
+ Map<String, Object> replacements = new HashMap<>();
+ replacements.put("LOG4J_PROPERTIES_FILE", log4jPropFile);
+ replacements.put("PARSE_MODE",
org.apache.tika.pipes.api.HandlerConfig.PARSE_MODE.RMETA.name());
+ replacements.put("PIPE_ITERATOR_BUCKET", FETCH_BUCKET);
+ replacements.put("EMIT_BUCKET", EMIT_BUCKET);
+ replacements.put("FETCH_BUCKET", FETCH_BUCKET);
+ replacements.put("ACCESS_KEY", ACCESS_KEY);
+ replacements.put("SECRET_KEY", SECRET_KEY);
+ replacements.put("ENDPOINT_CONFIGURATION_SERVICE", MINIO_ENDPOINT);
+ replacements.put("REGION", REGION.id());
+
+ JsonConfigHelper.writeConfigFromResource("/s3/plugins-template.json",
+ S3PipeIntegrationTest.class, replacements, tikaConfigFile);
try {
- TikaCLI.main(new String[]{"-a", "-c",
tikaConfigFile.getAbsolutePath()});
+ TikaCLI.main(new String[]{"-a", "-c",
tikaConfigFile.toAbsolutePath().toString()});
} catch (Exception e) {
throw new RuntimeException(e);
}
diff --git
a/tika-integration-tests/tika-pipes-s3-integration-tests/src/test/resources/s3/plugins-template.json
b/tika-integration-tests/tika-pipes-s3-integration-tests/src/test/resources/s3/plugins-template.json
index d0a61ae18a..a39705a2d4 100644
---
a/tika-integration-tests/tika-pipes-s3-integration-tests/src/test/resources/s3/plugins-template.json
+++
b/tika-integration-tests/tika-pipes-s3-integration-tests/src/test/resources/s3/plugins-template.json
@@ -2,12 +2,12 @@
"fetchers": {
"s3f": {
"s3-fetcher": {
- "region": "{REGION}",
- "bucket": "{FETCH_BUCKET}",
+ "region": "REGION",
+ "bucket": "FETCH_BUCKET",
"credentialsProvider": "key_secret",
- "accessKey": "{ACCESS_KEY}",
- "secretKey": "{SECRET_KEY}",
- "endpointConfigurationService": "{ENDPOINT_CONFIGURATION_SERVICE}",
+ "accessKey": "ACCESS_KEY",
+ "secretKey": "SECRET_KEY",
+ "endpointConfigurationService": "ENDPOINT_CONFIGURATION_SERVICE",
"pathStyleAccessEnabled": true,
"maxConnections": 50,
"throttleSeconds": [
@@ -22,12 +22,12 @@
"emitters": {
"s3e": {
"s3-emitter": {
- "region": "{REGION}",
- "bucket": "{EMIT_BUCKET}",
+ "region": "REGION",
+ "bucket": "EMIT_BUCKET",
"credentialsProvider": "key_secret",
- "accessKey": "{ACCESS_KEY}",
- "secretKey": "{SECRET_KEY}",
- "endpointConfigurationService": "{ENDPOINT_CONFIGURATION_SERVICE}",
+ "accessKey": "ACCESS_KEY",
+ "secretKey": "SECRET_KEY",
+ "endpointConfigurationService": "ENDPOINT_CONFIGURATION_SERVICE",
"pathStyleAccessEnabled": true,
"maxConnections": 50,
"fileExtension": "json",
@@ -37,19 +37,19 @@
},
"pipes-iterator": {
"s3-pipes-iterator": {
- "region": "{REGION}",
- "bucket": "{PIPE_ITERATOR_BUCKET}",
+ "region": "REGION",
+ "bucket": "PIPE_ITERATOR_BUCKET",
"credentialsProvider": "key_secret",
- "accessKey": "{ACCESS_KEY}",
- "secretKey": "{SECRET_KEY}",
- "endpointConfigurationService": "{ENDPOINT_CONFIGURATION_SERVICE}",
+ "accessKey": "ACCESS_KEY",
+ "secretKey": "SECRET_KEY",
+ "endpointConfigurationService": "ENDPOINT_CONFIGURATION_SERVICE",
"pathStyleAccessEnabled": true,
"baseConfig": {
"fetcherId": "s3f",
"emitterId": "s3e",
"handlerConfig": {
"type": "TEXT",
- "parseMode": "{PARSE_MODE}",
+ "parseMode": "PARSE_MODE",
"writeLimit": -1,
"maxEmbeddedResources": -1,
"throwOnWriteLimitReached": true
@@ -69,7 +69,7 @@
"-Xmx1g",
"-XX:ParallelGCThreads=2",
"-XX:+ExitOnOutOfMemoryError",
- "-Dlog4j.configurationFile={LOG4J_PROPERTIES_FILE}"
+ "-Dlog4j.configurationFile=LOG4J_PROPERTIES_FILE"
],
"timeoutMillis": 60000,
"emitStrategy": {
diff --git
a/tika-integration-tests/tika-pipes-solr-integration-tests/src/test/java/org/apache/tika/pipes/solr/tests/TikaPipesSolrTestBase.java
b/tika-integration-tests/tika-pipes-solr-integration-tests/src/test/java/org/apache/tika/pipes/solr/tests/TikaPipesSolrTestBase.java
index 942716be45..622243870d 100644
---
a/tika-integration-tests/tika-pipes-solr-integration-tests/src/test/java/org/apache/tika/pipes/solr/tests/TikaPipesSolrTestBase.java
+++
b/tika-integration-tests/tika-pipes-solr-integration-tests/src/test/java/org/apache/tika/pipes/solr/tests/TikaPipesSolrTestBase.java
@@ -23,10 +23,11 @@ import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
-import java.util.regex.Matcher;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
import org.apache.commons.io.FileUtils;
-import org.apache.commons.io.IOUtils;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
@@ -46,6 +47,7 @@ import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.utility.DockerImageName;
import org.apache.tika.cli.TikaCLI;
+import org.apache.tika.config.JsonConfigHelper;
import org.apache.tika.pipes.api.HandlerConfig;
import org.apache.tika.pipes.emitter.solr.SolrEmitterConfig;
import org.apache.tika.utils.SystemUtils;
@@ -264,38 +266,33 @@ public abstract class TikaPipesSolrTestBase {
HandlerConfig.PARSE_MODE parseMode) throws
IOException {
Path tikaConfig = pipesDirectory.resolve("plugins-config.json");
- String json;
- try (InputStream is =
this.getClass().getResourceAsStream("/solr/plugins-template.json")) {
- json = IOUtils.toString(is, StandardCharsets.UTF_8);
+ Path log4jPropFile = pipesDirectory.resolve("log4j2.xml");
+ try (InputStream is =
this.getClass().getResourceAsStream("/pipes-fork-server-custom-log4j2.xml")) {
+ Files.copy(is, log4jPropFile,
java.nio.file.StandardCopyOption.REPLACE_EXISTING);
}
- String solrUrls;
- String solrZkHosts;
+ List<String> solrUrls;
+ List<String> solrZkHosts;
if (useZk()) {
- solrUrls = "[]";
- solrZkHosts = "[\"" + solrHost + ":" + zkPort + "\"]";
+ solrUrls = List.of();
+ solrZkHosts = List.of(solrHost + ":" + zkPort);
} else {
- solrUrls = "[\"http://" + solrHost + ":" + solrPort + "/solr\"]";
- solrZkHosts = "[]";
+ solrUrls = List.of("http://" + solrHost + ":" + solrPort +
"/solr");
+ solrZkHosts = List.of();
}
- String res = json.replace("UPDATE_STRATEGY", updateStrategy.toString())
- .replace("ATTACHMENT_STRATEGY", attachmentStrategy.toString())
- .replaceAll("FETCHER_BASE_PATH",
-
Matcher.quoteReplacement(testFileFolder.toAbsolutePath().toString()))
- .replace("PARSE_MODE", parseMode.name())
- .replace("SOLR_URLS", solrUrls)
- .replace("SOLR_ZK_HOSTS", solrZkHosts);
-
- res = res.replace("TIKA_CONFIG",
tikaConfig.toAbsolutePath().toString());
+ Map<String, Object> replacements = new HashMap<>();
+ replacements.put("UPDATE_STRATEGY", updateStrategy.toString());
+ replacements.put("ATTACHMENT_STRATEGY", attachmentStrategy.toString());
+ replacements.put("FETCHER_BASE_PATH", testFileFolder);
+ replacements.put("PARSE_MODE", parseMode.name());
+ replacements.put("SOLR_URLS", solrUrls);
+ replacements.put("SOLR_ZK_HOSTS", solrZkHosts);
+ replacements.put("LOG4J_PROPERTIES_FILE", log4jPropFile);
- Path log4jPropFile = pipesDirectory.resolve("log4j2.xml");
- try (InputStream is =
this.getClass().getResourceAsStream("/pipes-fork-server-custom-log4j2.xml")) {
- Files.copy(is, log4jPropFile,
java.nio.file.StandardCopyOption.REPLACE_EXISTING);
- }
- res = res.replace("LOG4J_PROPERTIES_FILE",
log4jPropFile.toAbsolutePath().toString());
+ JsonConfigHelper.writeConfigFromResource("/solr/plugins-template.json",
+ TikaPipesSolrTestBase.class, replacements, tikaConfig);
- Files.writeString(tikaConfig, res, StandardCharsets.UTF_8);
return tikaConfig;
}
diff --git
a/tika-integration-tests/tika-pipes-solr-integration-tests/src/test/resources/solr/plugins-template.json
b/tika-integration-tests/tika-pipes-solr-integration-tests/src/test/resources/solr/plugins-template.json
index c448920871..3359a08b46 100644
---
a/tika-integration-tests/tika-pipes-solr-integration-tests/src/test/resources/solr/plugins-template.json
+++
b/tika-integration-tests/tika-pipes-solr-integration-tests/src/test/resources/solr/plugins-template.json
@@ -50,8 +50,8 @@
"se": {
"solr-emitter": {
"solrCollection": "testcol",
- "solrUrls": SOLR_URLS,
- "solrZkHosts": SOLR_ZK_HOSTS,
+ "solrUrls": "SOLR_URLS",
+ "solrZkHosts": "SOLR_ZK_HOSTS",
"updateStrategy": "UPDATE_STRATEGY",
"attachmentStrategy": "ATTACHMENT_STRATEGY",
"commitWithin": 1,
@@ -65,8 +65,8 @@
"pipes-iterator": {
"solr-pipes-iterator": {
"solrCollection": "testcol",
- "solrUrls": SOLR_URLS,
- "solrZkHosts": SOLR_ZK_HOSTS,
+ "solrUrls": "SOLR_URLS",
+ "solrZkHosts": "SOLR_ZK_HOSTS",
"idField": "id",
"parsingIdField": "parsing_id_i",
"failCountField": "fail_count_i",
diff --git
a/tika-pipes/tika-async-cli/src/test/java/org/apache/tika/async/cli/AsyncProcessorTest.java
b/tika-pipes/tika-async-cli/src/test/java/org/apache/tika/async/cli/AsyncProcessorTest.java
index c3c5f100f5..51aff03a09 100644
---
a/tika-pipes/tika-async-cli/src/test/java/org/apache/tika/async/cli/AsyncProcessorTest.java
+++
b/tika-pipes/tika-async-cli/src/test/java/org/apache/tika/async/cli/AsyncProcessorTest.java
@@ -22,11 +22,12 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
import java.io.BufferedReader;
import java.io.OutputStream;
-import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import org.apache.commons.io.IOUtils;
import org.junit.jupiter.api.BeforeEach;
@@ -36,6 +37,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.tika.TikaTest;
+import org.apache.tika.config.JsonConfigHelper;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.metadata.TikaCoreProperties;
import org.apache.tika.parser.ParseContext;
@@ -84,20 +86,20 @@ public class AsyncProcessorTest extends TikaTest {
Files.createDirectories(inputDir);
Path pluginsDir = Paths.get("target/plugins");
- if (! Files.isDirectory(pluginsDir)) {
+ if (!Files.isDirectory(pluginsDir)) {
LOG.warn("CAN'T FIND PLUGINS DIR. pwd={}",
Paths.get("").toAbsolutePath().toString());
}
tikaConfigPath = configDir.resolve("tika-config.json");
- String json =
Files.readString(Paths.get(AsyncProcessorTest.class.getResource("/configs/config-template.json").toURI()),
StandardCharsets.UTF_8);
- String jsonTemp = json
- .replace("FETCHER_BASE_PATH",
inputDir.toAbsolutePath().toString())
- .replace("JSON_EMITTER_BASE_PATH",
jsonOutputDir.toAbsolutePath().toString())
- .replace("BYTES_EMITTER_BASE_PATH",
bytesOutputDir.toAbsolutePath().toString())
- .replace("PLUGIN_ROOTS",
pluginsDir.toAbsolutePath().toString())
- .replace("TIKA_CONFIG",
tikaConfigPath.toAbsolutePath().toString());
- jsonTemp = jsonTemp.replace("\\", "/");
- Files.writeString(tikaConfigPath, jsonTemp, StandardCharsets.UTF_8);
+
+ Map<String, Object> replacements = new HashMap<>();
+ replacements.put("FETCHER_BASE_PATH", inputDir);
+ replacements.put("JSON_EMITTER_BASE_PATH", jsonOutputDir);
+ replacements.put("BYTES_EMITTER_BASE_PATH", bytesOutputDir);
+ replacements.put("PLUGIN_ROOTS", pluginsDir);
+
+
JsonConfigHelper.writeConfigFromResource("/configs/config-template.json",
+ AsyncProcessorTest.class, replacements, tikaConfigPath);
Path mock = inputDir.resolve("mock.xml");
try (OutputStream os = Files.newOutputStream(mock)) {
diff --git
a/tika-pipes/tika-pipes-integration-tests/src/test/java/org/apache/tika/pipes/core/PluginsTestHelper.java
b/tika-pipes/tika-pipes-integration-tests/src/test/java/org/apache/tika/pipes/core/PluginsTestHelper.java
index 5e8676094d..3ae317358e 100644
---
a/tika-pipes/tika-pipes-integration-tests/src/test/java/org/apache/tika/pipes/core/PluginsTestHelper.java
+++
b/tika-pipes/tika-pipes-integration-tests/src/test/java/org/apache/tika/pipes/core/PluginsTestHelper.java
@@ -17,14 +17,17 @@
package org.apache.tika.pipes.core;
import java.io.IOException;
-import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
+import java.util.HashMap;
+import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.apache.tika.config.JsonConfigHelper;
+
public class PluginsTestHelper {
private static final Logger LOG =
LoggerFactory.getLogger(PluginsTestHelper.class);
@@ -49,29 +52,25 @@ public class PluginsTestHelper {
public static Path getFileSystemFetcherConfig(String templateName, Path
configBase, Path fetcherBase, Path emitterBase, boolean
emitIntermediateResults) throws Exception {
Path pipesConfig = configBase.resolve("pipes-config.json");
- Path tikaPluginsTemplate =
Paths.get(PluginsTestHelper.class.getResource("/configs/" +
templateName).toURI());
- String json = Files.readString(tikaPluginsTemplate,
StandardCharsets.UTF_8);
-
- json = json.replace("FETCHER_BASE_PATH", fetcherBase
- .toAbsolutePath()
- .toString());
+ Map<String, Object> replacements = new HashMap<>();
+ replacements.put("FETCHER_BASE_PATH", fetcherBase);
if (emitterBase != null) {
- json = json.replace("EMITTER_BASE_PATH", emitterBase
- .toAbsolutePath()
- .toString());
+ replacements.put("EMITTER_BASE_PATH", emitterBase);
}
+
Path pwd = Paths.get("");
Path plugins = pwd.resolve("target/plugins");
if (Files.isDirectory(plugins)) {
- json = json.replace("PLUGINS_PATHS",
plugins.toAbsolutePath().toString());
+ replacements.put("PLUGINS_PATHS", plugins);
LOG.info("found plugins path");
} else {
- LOG.warn("Couldn't find plugins from {}", pwd.toAbsolutePath());
+ LOG.warn("Couldn't find plugins from {}", pwd.toAbsolutePath());
}
- json = json.replace("EMIT_INTERMEDIATE_RESULTS",
String.valueOf(emitIntermediateResults));
- json = json.replace("\\", "/");
- Files.write(pipesConfig, json.getBytes(StandardCharsets.UTF_8));
+ replacements.put("EMIT_INTERMEDIATE_RESULTS", emitIntermediateResults);
+
+ JsonConfigHelper.writeConfigFromResource("/configs/" + templateName,
+ PluginsTestHelper.class, replacements, pipesConfig);
return pipesConfig;
}
@@ -85,14 +84,4 @@ public class PluginsTestHelper {
}
}
- /**
- * Converts a Path to a JSON-safe string with forward slashes.
- * This ensures paths work correctly in JSON configs on both Windows and
Unix systems.
- *
- * @param path the path to convert
- * @return a string representation with forward slashes
- */
- public static String toJsonPath(Path path) {
- return path.toString().replace("\\", "/");
- }
}
diff --git
a/tika-pipes/tika-pipes-integration-tests/src/test/java/org/apache/tika/pipes/core/emitter/EmitterManagerTest.java
b/tika-pipes/tika-pipes-integration-tests/src/test/java/org/apache/tika/pipes/core/emitter/EmitterManagerTest.java
index 5b7ce9ced2..b2f7a9c62f 100644
---
a/tika-pipes/tika-pipes-integration-tests/src/test/java/org/apache/tika/pipes/core/emitter/EmitterManagerTest.java
+++
b/tika-pipes/tika-pipes-integration-tests/src/test/java/org/apache/tika/pipes/core/emitter/EmitterManagerTest.java
@@ -37,6 +37,7 @@ import java.util.concurrent.TimeUnit;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
+import org.apache.tika.config.JsonConfigHelper;
import org.apache.tika.config.loader.TikaJsonConfig;
import org.apache.tika.exception.TikaConfigException;
import org.apache.tika.pipes.api.emitter.Emitter;
@@ -110,8 +111,8 @@ public class EmitterManagerTest {
},
"plugin-roots": "target/plugins"
}
- """, PluginsTestHelper.toJsonPath(tmpDir.resolve("output1")),
- PluginsTestHelper.toJsonPath(tmpDir.resolve("output2")));
+ """, JsonConfigHelper.toJsonPath(tmpDir.resolve("output1")),
+ JsonConfigHelper.toJsonPath(tmpDir.resolve("output2")));
Path configPath = tmpDir.resolve("config.json");
Files.writeString(configPath, configJson, StandardCharsets.UTF_8);
@@ -272,8 +273,8 @@ public class EmitterManagerTest {
},
"plugin-roots": "target/plugins"
}
- """, PluginsTestHelper.toJsonPath(tmpDir.resolve("output1")),
- PluginsTestHelper.toJsonPath(tmpDir.resolve("output2")));
+ """, JsonConfigHelper.toJsonPath(tmpDir.resolve("output1")),
+ JsonConfigHelper.toJsonPath(tmpDir.resolve("output2")));
Path configPath = tmpDir.resolve("config.json");
Files.writeString(configPath, configJson, StandardCharsets.UTF_8);
@@ -323,8 +324,8 @@ public class EmitterManagerTest {
},
"plugin-roots": "target/plugins"
}
- """, PluginsTestHelper.toJsonPath(tmpDir.resolve("output1")),
- PluginsTestHelper.toJsonPath(tmpDir.resolve("output2")));
+ """, JsonConfigHelper.toJsonPath(tmpDir.resolve("output1")),
+ JsonConfigHelper.toJsonPath(tmpDir.resolve("output2")));
Path configPath = tmpDir.resolve("config.json");
Files.writeString(configPath, configJson, StandardCharsets.UTF_8);
@@ -360,7 +361,7 @@ public class EmitterManagerTest {
"basePath": "%s",
"onExists": "REPLACE"
}
- """, PluginsTestHelper.toJsonPath(tmpDir.resolve("output2")));
+ """, JsonConfigHelper.toJsonPath(tmpDir.resolve("output2")));
ExtensionConfig newConfig = new ExtensionConfig("fse2",
"file-system-emitter", newConfigJson);
emitterManager.saveEmitter(newConfig);
@@ -390,7 +391,7 @@ public class EmitterManagerTest {
"basePath": "%s",
"onExists": "REPLACE"
}
- """, PluginsTestHelper.toJsonPath(tmpDir.resolve("output2")));
+ """, JsonConfigHelper.toJsonPath(tmpDir.resolve("output2")));
ExtensionConfig duplicateConfig = new ExtensionConfig("fse",
"file-system-emitter", newConfigJson);
TikaConfigException exception =
assertThrows(TikaConfigException.class, () -> {
@@ -450,7 +451,7 @@ public class EmitterManagerTest {
"basePath": "%s",
"onExists": "REPLACE"
}
- """, PluginsTestHelper.toJsonPath(tmpDir.resolve("output"
+ i)));
+ """, JsonConfigHelper.toJsonPath(tmpDir.resolve("output" +
i)));
ExtensionConfig config2 = new ExtensionConfig("fse" + i,
"file-system-emitter", configJson);
emitterManager.saveEmitter(config2);
}
@@ -484,7 +485,7 @@ public class EmitterManagerTest {
"basePath": "%s",
"onExists": "REPLACE"
}
- """, PluginsTestHelper.toJsonPath(tmpDir.resolve("output2")));
+ """, JsonConfigHelper.toJsonPath(tmpDir.resolve("output2")));
ExtensionConfig newConfig = new ExtensionConfig("fse2",
"file-system-emitter", newConfigJson);
TikaConfigException exception =
assertThrows(TikaConfigException.class, () -> {
@@ -510,7 +511,7 @@ public class EmitterManagerTest {
"basePath": "%s",
"onExists": "REPLACE"
}
- """, PluginsTestHelper.toJsonPath(tmpDir.resolve("output2")));
+ """, JsonConfigHelper.toJsonPath(tmpDir.resolve("output2")));
ExtensionConfig newConfig = new ExtensionConfig("fse2",
"file-system-emitter", newConfigJson);
TikaConfigException exception =
assertThrows(TikaConfigException.class, () -> {
diff --git
a/tika-pipes/tika-pipes-integration-tests/src/test/java/org/apache/tika/pipes/core/fetcher/FetcherManagerTest.java
b/tika-pipes/tika-pipes-integration-tests/src/test/java/org/apache/tika/pipes/core/fetcher/FetcherManagerTest.java
index b526775478..192646f0d8 100644
---
a/tika-pipes/tika-pipes-integration-tests/src/test/java/org/apache/tika/pipes/core/fetcher/FetcherManagerTest.java
+++
b/tika-pipes/tika-pipes-integration-tests/src/test/java/org/apache/tika/pipes/core/fetcher/FetcherManagerTest.java
@@ -37,6 +37,7 @@ import java.util.concurrent.TimeUnit;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
+import org.apache.tika.config.JsonConfigHelper;
import org.apache.tika.config.loader.TikaJsonConfig;
import org.apache.tika.exception.TikaConfigException;
import org.apache.tika.pipes.api.fetcher.Fetcher;
@@ -108,8 +109,8 @@ public class FetcherManagerTest {
},
"plugin-roots": "target/plugins"
}
- """, PluginsTestHelper.toJsonPath(tmpDir.resolve("path1")),
- PluginsTestHelper.toJsonPath(tmpDir.resolve("path2")));
+ """, JsonConfigHelper.toJsonPath(tmpDir.resolve("path1")),
+ JsonConfigHelper.toJsonPath(tmpDir.resolve("path2")));
Path configPath = tmpDir.resolve("config.json");
Files.writeString(configPath, configJson, StandardCharsets.UTF_8);
@@ -268,8 +269,8 @@ public class FetcherManagerTest {
},
"plugin-roots": "target/plugins"
}
- """, PluginsTestHelper.toJsonPath(tmpDir.resolve("path1")),
- PluginsTestHelper.toJsonPath(tmpDir.resolve("path2")));
+ """, JsonConfigHelper.toJsonPath(tmpDir.resolve("path1")),
+ JsonConfigHelper.toJsonPath(tmpDir.resolve("path2")));
Path configPath = tmpDir.resolve("config.json");
Files.writeString(configPath, configJson, StandardCharsets.UTF_8);
@@ -317,8 +318,8 @@ public class FetcherManagerTest {
},
"plugin-roots": "target/plugins"
}
- """, PluginsTestHelper.toJsonPath(tmpDir.resolve("path1")),
- PluginsTestHelper.toJsonPath(tmpDir.resolve("path2")));
+ """, JsonConfigHelper.toJsonPath(tmpDir.resolve("path1")),
+ JsonConfigHelper.toJsonPath(tmpDir.resolve("path2")));
Path configPath = tmpDir.resolve("config.json");
Files.writeString(configPath, configJson, StandardCharsets.UTF_8);
@@ -351,7 +352,7 @@ public class FetcherManagerTest {
// Dynamically add a new fetcher configuration
String newConfigJson = String.format(Locale.ROOT, """
{"basePath": "%s"}
- """, PluginsTestHelper.toJsonPath(tmpDir.resolve("path2")));
+ """, JsonConfigHelper.toJsonPath(tmpDir.resolve("path2")));
ExtensionConfig newConfig = new ExtensionConfig("fsf2",
"file-system-fetcher", newConfigJson);
fetcherManager.saveFetcher(newConfig);
@@ -378,7 +379,7 @@ public class FetcherManagerTest {
// Try to add a fetcher with the same ID as existing one
String newConfigJson = String.format(Locale.ROOT, """
{"basePath": "%s"}
- """, PluginsTestHelper.toJsonPath(tmpDir.resolve("path2")));
+ """, JsonConfigHelper.toJsonPath(tmpDir.resolve("path2")));
ExtensionConfig duplicateConfig = new ExtensionConfig("fsf",
"file-system-fetcher", newConfigJson);
TikaConfigException exception =
assertThrows(TikaConfigException.class, () -> {
@@ -435,7 +436,7 @@ public class FetcherManagerTest {
for (int i = 2; i <= 5; i++) {
String configJson = String.format(Locale.ROOT, """
{"basePath": "%s"}
- """, PluginsTestHelper.toJsonPath(tmpDir.resolve("path" +
i)));
+ """, JsonConfigHelper.toJsonPath(tmpDir.resolve("path" +
i)));
ExtensionConfig config2 = new ExtensionConfig("fsf" + i,
"file-system-fetcher", configJson);
fetcherManager.saveFetcher(config2);
}
@@ -466,7 +467,7 @@ public class FetcherManagerTest {
// Try to add a fetcher - should fail
String newConfigJson = String.format(Locale.ROOT, """
{"basePath": "%s"}
- """, PluginsTestHelper.toJsonPath(tmpDir.resolve("path2")));
+ """, JsonConfigHelper.toJsonPath(tmpDir.resolve("path2")));
ExtensionConfig newConfig = new ExtensionConfig("fsf2",
"file-system-fetcher", newConfigJson);
TikaConfigException exception =
assertThrows(TikaConfigException.class, () -> {
@@ -489,7 +490,7 @@ public class FetcherManagerTest {
// Try to add a fetcher - should fail
String newConfigJson = String.format(Locale.ROOT, """
{"basePath": "%s"}
- """, PluginsTestHelper.toJsonPath(tmpDir.resolve("path2")));
+ """, JsonConfigHelper.toJsonPath(tmpDir.resolve("path2")));
ExtensionConfig newConfig = new ExtensionConfig("fsf2",
"file-system-fetcher", newConfigJson);
TikaConfigException exception =
assertThrows(TikaConfigException.class, () -> {
diff --git
a/tika-pipes/tika-pipes-integration-tests/src/test/resources/configs/tika-config-basic.json
b/tika-pipes/tika-pipes-integration-tests/src/test/resources/configs/tika-config-basic.json
index 06a0f71d0d..8ce84ffe72 100644
---
a/tika-pipes/tika-pipes-integration-tests/src/test/resources/configs/tika-config-basic.json
+++
b/tika-pipes/tika-pipes-integration-tests/src/test/resources/configs/tika-config-basic.json
@@ -41,7 +41,7 @@
"pipes": {
"numClients": 4,
"timeoutMillis": 5000,
- "emitIntermediateResults": EMIT_INTERMEDIATE_RESULTS,
+ "emitIntermediateResults": "EMIT_INTERMEDIATE_RESULTS",
"forkedJvmArgs": ["-Xmx512m"],
"emitStrategy": {
"type": "DYNAMIC",
diff --git
a/tika-pipes/tika-pipes-integration-tests/src/test/resources/configs/tika-config-passback.json
b/tika-pipes/tika-pipes-integration-tests/src/test/resources/configs/tika-config-passback.json
index 2473aa5572..db019f51f8 100644
---
a/tika-pipes/tika-pipes-integration-tests/src/test/resources/configs/tika-config-passback.json
+++
b/tika-pipes/tika-pipes-integration-tests/src/test/resources/configs/tika-config-passback.json
@@ -41,7 +41,7 @@
"pipes": {
"numClients": 4,
"timeoutMillis": 5000,
- "emitIntermediateResults": EMIT_INTERMEDIATE_RESULTS,
+ "emitIntermediateResults": "EMIT_INTERMEDIATE_RESULTS",
"forkedJvmArgs": ["-Xmx512m"],
"emitStrategy": {
"type": "EMIT_ALL"
diff --git
a/tika-serialization/src/main/java/org/apache/tika/config/JsonConfigHelper.java
b/tika-serialization/src/main/java/org/apache/tika/config/JsonConfigHelper.java
new file mode 100644
index 0000000000..f73e920e1c
--- /dev/null
+++
b/tika-serialization/src/main/java/org/apache/tika/config/JsonConfigHelper.java
@@ -0,0 +1,288 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tika.config;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.fasterxml.jackson.databind.node.TextNode;
+
+/**
+ * Helper class for loading JSON config templates with placeholder replacement.
+ * <p>
+ * This provides a type-safe alternative to String.replace() for JSON configs,
+ * properly handling paths (converting backslashes to forward slashes on
Windows)
+ * and different value types (strings, integers, doubles, booleans).
+ * <p>
+ * Example template JSON:
+ * <pre>
+ * {
+ * "fetchers": {
+ * "fs": {
+ * "file-system-fetcher": {
+ * "basePath": "FETCHER_BASE_PATH"
+ * }
+ * }
+ * },
+ * "pipes": {
+ * "maxFiles": "MAX_FILES",
+ * "enabled": "ENABLED"
+ * }
+ * }
+ * </pre>
+ * <p>
+ * Usage:
+ * <pre>
+ * Map<String, Object> replacements = Map.of(
+ * "FETCHER_BASE_PATH", tmpDir.resolve("input"), // Path
+ * "MAX_FILES", 100, // Integer
+ * "ENABLED", true // Boolean
+ * );
+ * JsonNode config = JsonConfigHelper.load(templatePath, replacements);
+ * </pre>
+ */
+public class JsonConfigHelper {
+
+ private static final ObjectMapper MAPPER = new ObjectMapper();
+
+ /**
+ * Loads a JSON config template from a resource path and applies
replacements.
+ *
+ * @param resourcePath path to template resource (e.g.,
"/configs/template.json")
+ * @param clazz class to use for resource loading
+ * @param replacements map of placeholder names to replacement values
+ * @return the modified JsonNode tree
+ * @throws IOException if the template cannot be read or parsed
+ */
+ public static JsonNode loadFromResource(String resourcePath, Class<?>
clazz,
+ Map<String, Object> replacements)
throws IOException {
+ try (InputStream is = clazz.getResourceAsStream(resourcePath)) {
+ if (is == null) {
+ throw new IOException("Resource not found: " + resourcePath);
+ }
+ JsonNode root = MAPPER.readTree(is);
+ return applyReplacements(root, replacements);
+ }
+ }
+
+ /**
+ * Loads a JSON config template from a file path and applies replacements.
+ *
+ * @param templatePath path to the template file
+ * @param replacements map of placeholder names to replacement values
+ * @return the modified JsonNode tree
+ * @throws IOException if the template cannot be read or parsed
+ */
+ public static JsonNode load(Path templatePath, Map<String, Object>
replacements)
+ throws IOException {
+ JsonNode root = MAPPER.readTree(templatePath.toFile());
+ return applyReplacements(root, replacements);
+ }
+
+ /**
+ * Loads a JSON config template from a string and applies replacements.
+ *
+ * @param jsonTemplate the JSON template string
+ * @param replacements map of placeholder names to replacement values
+ * @return the modified JsonNode tree
+ * @throws IOException if the template cannot be parsed
+ */
+ public static JsonNode loadFromString(String jsonTemplate, Map<String,
Object> replacements)
+ throws IOException {
+ JsonNode root = MAPPER.readTree(jsonTemplate);
+ return applyReplacements(root, replacements);
+ }
+
+ /**
+ * Loads a template, applies replacements, and writes to an output file.
+ *
+ * @param templatePath path to the template file
+ * @param replacements map of placeholder names to replacement values
+ * @param outputPath path to write the result
+ * @return the output path
+ * @throws IOException if reading or writing fails
+ */
+ public static Path writeConfig(Path templatePath, Map<String, Object>
replacements,
+ Path outputPath) throws IOException {
+ JsonNode config = load(templatePath, replacements);
+ String json =
MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(config);
+ Files.writeString(outputPath, json, StandardCharsets.UTF_8);
+ return outputPath;
+ }
+
+ /**
+ * Loads a template from resources, applies replacements, and writes to an
output file.
+ *
+ * @param resourcePath path to template resource
+ * @param clazz class to use for resource loading
+ * @param replacements map of placeholder names to replacement values
+ * @param outputPath path to write the result
+ * @return the output path
+ * @throws IOException if reading or writing fails
+ */
+ public static Path writeConfigFromResource(String resourcePath, Class<?>
clazz,
+ Map<String, Object>
replacements,
+ Path outputPath) throws
IOException {
+ JsonNode config = loadFromResource(resourcePath, clazz, replacements);
+ String json =
MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(config);
+ Files.writeString(outputPath, json, StandardCharsets.UTF_8);
+ return outputPath;
+ }
+
+ /**
+ * Applies replacements to a JsonNode tree, modifying it in place.
+ *
+ * @param root the root node to modify
+ * @param replacements map of placeholder names to replacement values
+ * @return the modified root node
+ */
+ public static JsonNode applyReplacements(JsonNode root, Map<String,
Object> replacements) {
+ if (root.isObject()) {
+ applyToObject((ObjectNode) root, replacements);
+ } else if (root.isArray()) {
+ applyToArray((ArrayNode) root, replacements);
+ }
+ return root;
+ }
+
+ private static void applyToObject(ObjectNode node, Map<String, Object>
replacements) {
+ Iterator<String> fieldNames = node.fieldNames();
+ while (fieldNames.hasNext()) {
+ String fieldName = fieldNames.next();
+ JsonNode child = node.get(fieldName);
+
+ if (child.isTextual()) {
+ String text = child.asText();
+ if (replacements.containsKey(text)) {
+ node.set(fieldName, toJsonNode(replacements.get(text)));
+ }
+ } else if (child.isObject()) {
+ applyToObject((ObjectNode) child, replacements);
+ } else if (child.isArray()) {
+ applyToArray((ArrayNode) child, replacements);
+ }
+ }
+ }
+
+ private static void applyToArray(ArrayNode array, Map<String, Object>
replacements) {
+ for (int i = 0; i < array.size(); i++) {
+ JsonNode child = array.get(i);
+
+ if (child.isTextual()) {
+ String text = child.asText();
+ if (replacements.containsKey(text)) {
+ array.set(i, toJsonNode(replacements.get(text)));
+ }
+ } else if (child.isObject()) {
+ applyToObject((ObjectNode) child, replacements);
+ } else if (child.isArray()) {
+ applyToArray((ArrayNode) child, replacements);
+ }
+ }
+ }
+
+ /**
+ * Converts a Java object to the appropriate JsonNode type.
+ * <p>
+ * Supported types:
+ * <ul>
+ * <li>JsonNode - used directly (for complex objects or arrays)</li>
+ * <li>List - converted to ArrayNode</li>
+ * <li>Path - converted to forward-slash string (Windows compatible)</li>
+ * <li>String - TextNode</li>
+ * <li>Integer, Long - numeric node</li>
+ * <li>Float, Double - numeric node</li>
+ * <li>Boolean - boolean node</li>
+ * <li>null - null node</li>
+ * </ul>
+ *
+ * @param value the value to convert
+ * @return the appropriate JsonNode
+ */
+ private static JsonNode toJsonNode(Object value) {
+ if (value == null) {
+ return MAPPER.nullNode();
+ }
+ if (value instanceof JsonNode) {
+ // Already a JsonNode, use directly
+ return (JsonNode) value;
+ }
+ if (value instanceof List) {
+ // Convert List to ArrayNode
+ ArrayNode arrayNode = MAPPER.createArrayNode();
+ for (Object item : (List<?>) value) {
+ arrayNode.add(toJsonNode(item));
+ }
+ return arrayNode;
+ }
+ if (value instanceof Path) {
+ // Convert path to forward slashes for JSON (Windows compatibility)
+ return new TextNode(toJsonPath((Path) value));
+ }
+ if (value instanceof String) {
+ return new TextNode((String) value);
+ }
+ if (value instanceof Integer) {
+ return MAPPER.getNodeFactory().numberNode((Integer) value);
+ }
+ if (value instanceof Long) {
+ return MAPPER.getNodeFactory().numberNode((Long) value);
+ }
+ if (value instanceof Double) {
+ return MAPPER.getNodeFactory().numberNode((Double) value);
+ }
+ if (value instanceof Float) {
+ return MAPPER.getNodeFactory().numberNode((Float) value);
+ }
+ if (value instanceof Boolean) {
+ return MAPPER.getNodeFactory().booleanNode((Boolean) value);
+ }
+ // Fallback: convert to string
+ return new TextNode(value.toString());
+ }
+
+ /**
+ * Converts a Path to a JSON-safe string with forward slashes.
+ * This handles Windows paths correctly.
+ *
+ * @param path the path to convert
+ * @return the path string with forward slashes
+ */
+ public static String toJsonPath(Path path) {
+ return path.toAbsolutePath().toString().replace("\\", "/");
+ }
+
+ /**
+ * Returns the ObjectMapper used by this helper.
+ * Useful for additional JSON operations.
+ *
+ * @return the ObjectMapper instance
+ */
+ public static ObjectMapper getMapper() {
+ return MAPPER;
+ }
+}
diff --git
a/tika-serialization/src/test/java/org/apache/tika/config/JsonConfigHelperTest.java
b/tika-serialization/src/test/java/org/apache/tika/config/JsonConfigHelperTest.java
new file mode 100644
index 0000000000..338f9ce594
--- /dev/null
+++
b/tika-serialization/src/test/java/org/apache/tika/config/JsonConfigHelperTest.java
@@ -0,0 +1,336 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tika.config;
+
+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 java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Map;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+public class JsonConfigHelperTest {
+
+ @Test
+ public void testStringReplacement() throws Exception {
+ String template = """
+ {
+ "name": "COMPONENT_NAME",
+ "description": "A test component"
+ }
+ """;
+
+ JsonNode result = JsonConfigHelper.loadFromString(template,
+ Map.of("COMPONENT_NAME", "my-fetcher"));
+
+ assertEquals("my-fetcher", result.get("name").asText());
+ assertEquals("A test component", result.get("description").asText());
+ }
+
+ @Test
+ public void testIntegerReplacement() throws Exception {
+ String template = """
+ {
+ "maxFiles": "MAX_FILES",
+ "timeout": "TIMEOUT_MS"
+ }
+ """;
+
+ JsonNode result = JsonConfigHelper.loadFromString(template,
+ Map.of("MAX_FILES", 100, "TIMEOUT_MS", 5000L));
+
+ assertTrue(result.get("maxFiles").isNumber());
+ assertEquals(100, result.get("maxFiles").asInt());
+ assertTrue(result.get("timeout").isNumber());
+ assertEquals(5000L, result.get("timeout").asLong());
+ }
+
+ @Test
+ public void testDoubleReplacement() throws Exception {
+ String template = """
+ {
+ "threshold": "THRESHOLD",
+ "rate": "RATE"
+ }
+ """;
+
+ JsonNode result = JsonConfigHelper.loadFromString(template,
+ Map.of("THRESHOLD", 0.95, "RATE", 1.5f));
+
+ assertTrue(result.get("threshold").isNumber());
+ assertEquals(0.95, result.get("threshold").asDouble(), 0.001);
+ assertTrue(result.get("rate").isNumber());
+ assertEquals(1.5, result.get("rate").asDouble(), 0.001);
+ }
+
+ @Test
+ public void testBooleanReplacement() throws Exception {
+ String template = """
+ {
+ "enabled": "ENABLED",
+ "debug": "DEBUG_MODE"
+ }
+ """;
+
+ JsonNode result = JsonConfigHelper.loadFromString(template,
+ Map.of("ENABLED", true, "DEBUG_MODE", false));
+
+ assertTrue(result.get("enabled").isBoolean());
+ assertTrue(result.get("enabled").asBoolean());
+ assertTrue(result.get("debug").isBoolean());
+ assertFalse(result.get("debug").asBoolean());
+ }
+
+ @Test
+ public void testPathReplacement(@TempDir Path tmpDir) throws Exception {
+ String template = """
+ {
+ "basePath": "BASE_PATH",
+ "outputDir": "OUTPUT_DIR"
+ }
+ """;
+
+ Path inputPath = tmpDir.resolve("input");
+ Path outputPath = tmpDir.resolve("output");
+
+ JsonNode result = JsonConfigHelper.loadFromString(template,
+ Map.of("BASE_PATH", inputPath, "OUTPUT_DIR", outputPath));
+
+ // Should be strings with forward slashes (even on Windows)
+ assertTrue(result.get("basePath").isTextual());
+ assertFalse(result.get("basePath").asText().contains("\\"),
+ "Path should use forward slashes");
+ assertTrue(result.get("basePath").asText().endsWith("input"));
+
+ assertTrue(result.get("outputDir").isTextual());
+ assertFalse(result.get("outputDir").asText().contains("\\"),
+ "Path should use forward slashes");
+ assertTrue(result.get("outputDir").asText().endsWith("output"));
+ }
+
+ @Test
+ public void testNestedReplacement() throws Exception {
+ String template = """
+ {
+ "fetchers": {
+ "fs": {
+ "file-system-fetcher": {
+ "basePath": "FETCHER_PATH",
+ "maxSize": "MAX_SIZE"
+ }
+ }
+ },
+ "emitters": {
+ "out": {
+ "file-system-emitter": {
+ "basePath": "EMITTER_PATH"
+ }
+ }
+ }
+ }
+ """;
+
+ JsonNode result = JsonConfigHelper.loadFromString(template,
+ Map.of(
+ "FETCHER_PATH", "/tmp/input",
+ "EMITTER_PATH", "/tmp/output",
+ "MAX_SIZE", 1000
+ ));
+
+ assertEquals("/tmp/input",
+
result.at("/fetchers/fs/file-system-fetcher/basePath").asText());
+ assertEquals(1000,
+ result.at("/fetchers/fs/file-system-fetcher/maxSize").asInt());
+ assertEquals("/tmp/output",
+
result.at("/emitters/out/file-system-emitter/basePath").asText());
+ }
+
+ @Test
+ public void testArrayReplacement() throws Exception {
+ String template = """
+ {
+ "items": ["ITEM_1", "ITEM_2", "static-item"],
+ "counts": ["COUNT_1", "COUNT_2"]
+ }
+ """;
+
+ JsonNode result = JsonConfigHelper.loadFromString(template,
+ Map.of(
+ "ITEM_1", "first",
+ "ITEM_2", "second",
+ "COUNT_1", 10,
+ "COUNT_2", 20
+ ));
+
+ assertEquals("first", result.get("items").get(0).asText());
+ assertEquals("second", result.get("items").get(1).asText());
+ assertEquals("static-item", result.get("items").get(2).asText());
+ assertEquals(10, result.get("counts").get(0).asInt());
+ assertEquals(20, result.get("counts").get(1).asInt());
+ }
+
+ @Test
+ public void testUnmatchedPlaceholdersLeftAlone() throws Exception {
+ String template = """
+ {
+ "matched": "WILL_MATCH",
+ "unmatched": "NOT_IN_MAP"
+ }
+ """;
+
+ JsonNode result = JsonConfigHelper.loadFromString(template,
+ Map.of("WILL_MATCH", "replaced-value"));
+
+ assertEquals("replaced-value", result.get("matched").asText());
+ assertEquals("NOT_IN_MAP", result.get("unmatched").asText());
+ }
+
+ @Test
+ public void testWriteConfig(@TempDir Path tmpDir) throws Exception {
+ String template = """
+ {
+ "path": "THE_PATH",
+ "count": "THE_COUNT"
+ }
+ """;
+
+ Path templateFile = tmpDir.resolve("template.json");
+ Files.writeString(templateFile, template);
+
+ Path outputFile = tmpDir.resolve("output.json");
+ Path inputDir = tmpDir.resolve("input");
+
+ JsonConfigHelper.writeConfig(templateFile,
+ Map.of("THE_PATH", inputDir, "THE_COUNT", 42),
+ outputFile);
+
+ // Read back and verify
+ JsonNode result =
JsonConfigHelper.getMapper().readTree(outputFile.toFile());
+ assertTrue(result.get("path").asText().endsWith("input"));
+ assertFalse(result.get("path").asText().contains("\\"));
+ assertEquals(42, result.get("count").asInt());
+ }
+
+ @Test
+ public void testMixedTypes() throws Exception {
+ String template = """
+ {
+ "config": {
+ "stringVal": "STRING_VAL",
+ "intVal": "INT_VAL",
+ "longVal": "LONG_VAL",
+ "doubleVal": "DOUBLE_VAL",
+ "floatVal": "FLOAT_VAL",
+ "boolVal": "BOOL_VAL",
+ "pathVal": "PATH_VAL"
+ }
+ }
+ """;
+
+ JsonNode result = JsonConfigHelper.loadFromString(template,
+ Map.of(
+ "STRING_VAL", "hello",
+ "INT_VAL", 42,
+ "LONG_VAL", 9999999999L,
+ "DOUBLE_VAL", 3.14159,
+ "FLOAT_VAL", 2.5f,
+ "BOOL_VAL", true,
+ "PATH_VAL", Path.of("/tmp/test")
+ ));
+
+ JsonNode config = result.get("config");
+ assertEquals("hello", config.get("stringVal").asText());
+ assertEquals(42, config.get("intVal").asInt());
+ assertEquals(9999999999L, config.get("longVal").asLong());
+ assertEquals(3.14159, config.get("doubleVal").asDouble(), 0.00001);
+ assertEquals(2.5, config.get("floatVal").asDouble(), 0.01);
+ assertTrue(config.get("boolVal").asBoolean());
+ String pathVal = config.get("pathVal").asText();
+ assertTrue(pathVal.endsWith("tmp/test"), "Path should end with
tmp/test but was: " + pathVal);
+ assertFalse(pathVal.contains("\\"), "Path should use forward slashes");
+ }
+
+ @Test
+ public void testToJsonPath() {
+ // Test that backslashes are converted to forward slashes
+ Path path = Path.of("/some/path/to/file");
+ String jsonPath = JsonConfigHelper.toJsonPath(path);
+ assertFalse(jsonPath.contains("\\"), "Should not contain backslashes");
+ assertTrue(jsonPath.contains("/"), "Should contain forward slashes");
+ }
+
+ @Test
+ public void testLoadFromResource(@TempDir Path tmpDir) throws Exception {
+ Path fetcherPath = tmpDir.resolve("fetcher-base");
+ Path emitterPath = tmpDir.resolve("emitter-base");
+
+ JsonNode result = JsonConfigHelper.loadFromResource(
+ "/configs/template-test.json",
+ JsonConfigHelperTest.class,
+ Map.of(
+ "FETCHER_BASE_PATH", fetcherPath,
+ "EMITTER_BASE_PATH", emitterPath,
+ "MAX_FILES", 500,
+ "EMIT_INTERMEDIATE", true
+ ));
+
+ // Verify nested paths were replaced
+ String fetcherBasePath =
result.at("/fetchers/fs/file-system-fetcher/basePath").asText();
+ assertTrue(fetcherBasePath.endsWith("fetcher-base"));
+ assertFalse(fetcherBasePath.contains("\\"));
+
+ String emitterBasePath =
result.at("/emitters/out/file-system-emitter/basePath").asText();
+ assertTrue(emitterBasePath.endsWith("emitter-base"));
+ assertFalse(emitterBasePath.contains("\\"));
+
+ // Verify numeric and boolean replacements
+ assertEquals(500, result.at("/pipes/maxFilesWaitingInQueue").asInt());
+ assertTrue(result.at("/pipes/emitIntermediateResults").asBoolean());
+ }
+
+ @Test
+ public void testWriteConfigFromResource(@TempDir Path tmpDir) throws
Exception {
+ Path fetcherPath = tmpDir.resolve("input");
+ Path emitterPath = tmpDir.resolve("output");
+ Path outputFile = tmpDir.resolve("generated-config.json");
+
+ JsonConfigHelper.writeConfigFromResource(
+ "/configs/template-test.json",
+ JsonConfigHelperTest.class,
+ Map.of(
+ "FETCHER_BASE_PATH", fetcherPath,
+ "EMITTER_BASE_PATH", emitterPath,
+ "MAX_FILES", 1000,
+ "EMIT_INTERMEDIATE", false
+ ),
+ outputFile);
+
+ // Verify file was written
+ assertTrue(Files.exists(outputFile));
+
+ // Read back and verify
+ JsonNode result =
JsonConfigHelper.getMapper().readTree(outputFile.toFile());
+
assertTrue(result.at("/fetchers/fs/file-system-fetcher/basePath").asText().endsWith("input"));
+ assertEquals(1000, result.at("/pipes/maxFilesWaitingInQueue").asInt());
+ assertFalse(result.at("/pipes/emitIntermediateResults").asBoolean());
+ }
+}
diff --git a/tika-serialization/src/test/resources/configs/template-test.json
b/tika-serialization/src/test/resources/configs/template-test.json
new file mode 100644
index 0000000000..de81f5b040
--- /dev/null
+++ b/tika-serialization/src/test/resources/configs/template-test.json
@@ -0,0 +1,20 @@
+{
+ "fetchers": {
+ "fs": {
+ "file-system-fetcher": {
+ "basePath": "FETCHER_BASE_PATH"
+ }
+ }
+ },
+ "emitters": {
+ "out": {
+ "file-system-emitter": {
+ "basePath": "EMITTER_BASE_PATH"
+ }
+ }
+ },
+ "pipes": {
+ "maxFilesWaitingInQueue": "MAX_FILES",
+ "emitIntermediateResults": "EMIT_INTERMEDIATE"
+ }
+}
diff --git
a/tika-server/tika-server-core/src/test/java/org/apache/tika/server/core/CXFTestBase.java
b/tika-server/tika-server-core/src/test/java/org/apache/tika/server/core/CXFTestBase.java
index 0ecace00c0..7fc1588d0b 100644
---
a/tika-server/tika-server-core/src/test/java/org/apache/tika/server/core/CXFTestBase.java
+++
b/tika-server/tika-server-core/src/test/java/org/apache/tika/server/core/CXFTestBase.java
@@ -26,7 +26,6 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
@@ -36,6 +35,8 @@ import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.ArchiveInputStream;
@@ -43,7 +44,6 @@ import
org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipFile;
import org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream;
import org.apache.commons.io.IOUtils;
-import org.apache.commons.io.input.UnsynchronizedByteArrayInputStream;
import org.apache.cxf.binding.BindingFactoryManager;
import org.apache.cxf.endpoint.Server;
import org.apache.cxf.jaxrs.JAXRSBindingFactory;
@@ -55,6 +55,7 @@ import org.junit.jupiter.api.BeforeEach;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.apache.tika.config.JsonConfigHelper;
import org.apache.tika.config.loader.TikaLoader;
import org.apache.tika.server.core.resource.TikaResource;
import org.apache.tika.server.core.resource.UnpackerResource;
@@ -82,16 +83,8 @@ public abstract class CXFTestBase {
}
""";
- public final static String JSON_TEMPLATE;
-
- static {
- try {
- JSON_TEMPLATE = Files.readString(
-
Paths.get(CXFTestBase.class.getResource("/configs/cxf-test-base-template.json").toURI()),
UTF_8);
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
+ private static final String TEMPLATE_RESOURCE =
"/configs/cxf-test-base-template.json";
+ private static final ObjectMapper MAPPER = new ObjectMapper();
protected static final String endPoint = "http://localhost:" +
TikaServerConfig.DEFAULT_PORT;
protected final static int DIGESTER_READ_LIMIT = 20 * 1024 * 1024;
@@ -101,23 +94,21 @@ public abstract class CXFTestBase {
public static void createPluginsConfig(Path configPath, Path inputDir,
Path jsonOutputDir, Path bytesOutputDir, Long timeoutMillis) throws IOException
{
Path pluginsDir = Paths.get("target/plugins");
- if (! Files.isDirectory(pluginsDir)) {
+ if (!Files.isDirectory(pluginsDir)) {
LOG.warn("CAN'T FIND PLUGINS DIR. pwd={}",
Paths.get("").toAbsolutePath().toString());
}
- String json = CXFTestBase.JSON_TEMPLATE.replace("FETCHER_BASE_PATH",
inputDir.toAbsolutePath().toString())
- .replace("JSON_EMITTER_BASE_PATH",
jsonOutputDir.toAbsolutePath().toString())
- .replace("PLUGINS_PATHS",
pluginsDir.toAbsolutePath().toString());
+
+ Map<String, Object> replacements = new HashMap<>();
+ replacements.put("FETCHER_BASE_PATH", inputDir);
+ replacements.put("JSON_EMITTER_BASE_PATH", jsonOutputDir);
+ replacements.put("PLUGINS_PATHS", pluginsDir);
if (bytesOutputDir != null) {
- json = json.replace("BYTES_EMITTER_BASE_PATH",
bytesOutputDir.toAbsolutePath().toString());
- }
- json = json.replace("TIKA_CONFIG",
configPath.toAbsolutePath().toString());
- if (timeoutMillis != null) {
- json = json.replace("TIMEOUT_MILLIS", timeoutMillis.toString());
- } else {
- json = json.replace("TIMEOUT_MILLIS", "10000");
+ replacements.put("BYTES_EMITTER_BASE_PATH", bytesOutputDir);
}
- json = json.replace("\\", "/");
- Files.writeString(configPath, json, StandardCharsets.UTF_8);
+ replacements.put("TIMEOUT_MILLIS", timeoutMillis != null ?
timeoutMillis : 10000L);
+
+ JsonConfigHelper.writeConfigFromResource(TEMPLATE_RESOURCE,
+ CXFTestBase.class, replacements, configPath);
}
@@ -238,19 +229,16 @@ public abstract class CXFTestBase {
.toAbsolutePath()
.toString());
}
- String json = CXFTestBase.JSON_TEMPLATE
- .replace("FETCHER_BASE_PATH", getPipesInputPath())
- .replace("PLUGINS_PATHS", pluginsDir
- .toAbsolutePath()
- .toString())
- .replace("TIMEOUT_MILLIS", "10000");
-
- json = json.replace("\\", "/");
- return UnsynchronizedByteArrayInputStream
- .builder()
- .setByteArray(json.getBytes(UTF_8))
- .get();
+ Map<String, Object> replacements = new HashMap<>();
+ replacements.put("FETCHER_BASE_PATH", getPipesInputPath());
+ replacements.put("PLUGINS_PATHS", pluginsDir);
+ replacements.put("TIMEOUT_MILLIS", 10000L);
+
+ JsonNode config = JsonConfigHelper.loadFromResource(TEMPLATE_RESOURCE,
+ CXFTestBase.class, replacements);
+ String json = MAPPER.writeValueAsString(config);
+ return new ByteArrayInputStream(json.getBytes(UTF_8));
}
protected String getPipesInputPath() {
diff --git
a/tika-server/tika-server-core/src/test/java/org/apache/tika/server/core/TikaResourceFetcherTest.java
b/tika-server/tika-server-core/src/test/java/org/apache/tika/server/core/TikaResourceFetcherTest.java
index f76d14bb24..c4a631f978 100644
---
a/tika-server/tika-server-core/src/test/java/org/apache/tika/server/core/TikaResourceFetcherTest.java
+++
b/tika-server/tika-server-core/src/test/java/org/apache/tika/server/core/TikaResourceFetcherTest.java
@@ -24,8 +24,12 @@ import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.ws.rs.core.MultivaluedHashMap;
import jakarta.ws.rs.core.MultivaluedMap;
import jakarta.ws.rs.core.Response;
@@ -35,6 +39,7 @@ import
org.apache.cxf.jaxrs.lifecycle.SingletonResourceProvider;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
+import org.apache.tika.config.JsonConfigHelper;
import org.apache.tika.config.loader.TikaJsonConfig;
import org.apache.tika.exception.TikaConfigException;
import org.apache.tika.io.TikaInputStream;
@@ -62,20 +67,18 @@ public class TikaResourceFetcherTest extends CXFTestBase {
sf.setProviders(providers);
}
+ private static final ObjectMapper MAPPER = new ObjectMapper();
+
@Override
protected InputStream getTikaConfigInputStream() throws IOException {
- Path inputDir = null;
- try {
- inputDir = Paths.get(TikaResourceFetcherTest.class
- .getResource("/test-documents/")
- .toURI());
- } catch (URISyntaxException e) {
- throw new RuntimeException(e);
- }
- String configXML =
getStringFromInputStream(TikaResourceFetcherTest.class.getResourceAsStream("/configs/tika-config-server-fetcher-template.json"));
-
- configXML = configXML.replace("{PORT}", "9998");
- return new
ByteArrayInputStream(configXML.getBytes(StandardCharsets.UTF_8));
+ Map<String, Object> replacements = new HashMap<>();
+ replacements.put("PORT", 9998);
+
+ JsonNode config = JsonConfigHelper.loadFromResource(
+ "/configs/tika-config-server-fetcher-template.json",
+ TikaResourceFetcherTest.class, replacements);
+ String json = MAPPER.writeValueAsString(config);
+ return new ByteArrayInputStream(json.getBytes(StandardCharsets.UTF_8));
}
protected String getPipesInputPath() {
diff --git
a/tika-server/tika-server-core/src/test/resources/configs/cxf-test-base-template.json
b/tika-server/tika-server-core/src/test/resources/configs/cxf-test-base-template.json
index 0efff460bd..358c023e60 100644
---
a/tika-server/tika-server-core/src/test/resources/configs/cxf-test-base-template.json
+++
b/tika-server/tika-server-core/src/test/resources/configs/cxf-test-base-template.json
@@ -25,7 +25,7 @@
},
"server": {
"port": 9999,
- "taskTimeoutMillis": TIMEOUT_MILLIS,
+ "taskTimeoutMillis": "TIMEOUT_MILLIS",
"taskPulseMillis": 100,
"enableUnsecureFeatures": true,
"endpoints": [
@@ -37,7 +37,7 @@
},
"pipes": {
"numClients": 2,
- "timeoutMillis": TIMEOUT_MILLIS,
+ "timeoutMillis": "TIMEOUT_MILLIS",
"emitIntermediateResults": false,
"forkedJvmArgs": [
"-Xmx512m"
diff --git
a/tika-server/tika-server-core/src/test/resources/configs/tika-config-server-fetcher-template.json
b/tika-server/tika-server-core/src/test/resources/configs/tika-config-server-fetcher-template.json
index 4dd1b826a2..9647bb1a4c 100644
---
a/tika-server/tika-server-core/src/test/resources/configs/tika-config-server-fetcher-template.json
+++
b/tika-server/tika-server-core/src/test/resources/configs/tika-config-server-fetcher-template.json
@@ -1,6 +1,6 @@
{
"server": {
- "port": "{PORT}",
+ "port": "PORT",
"taskTimeoutMillis": 54321,
"enableUnsecureFeatures": true,
"taskPulseMillis": 100,
diff --git
a/tika-server/tika-server-standard/src/test/resources/configs/cxf-test-base-template.json
b/tika-server/tika-server-standard/src/test/resources/configs/cxf-test-base-template.json
index 0efff460bd..358c023e60 100644
---
a/tika-server/tika-server-standard/src/test/resources/configs/cxf-test-base-template.json
+++
b/tika-server/tika-server-standard/src/test/resources/configs/cxf-test-base-template.json
@@ -25,7 +25,7 @@
},
"server": {
"port": 9999,
- "taskTimeoutMillis": TIMEOUT_MILLIS,
+ "taskTimeoutMillis": "TIMEOUT_MILLIS",
"taskPulseMillis": 100,
"enableUnsecureFeatures": true,
"endpoints": [
@@ -37,7 +37,7 @@
},
"pipes": {
"numClients": 2,
- "timeoutMillis": TIMEOUT_MILLIS,
+ "timeoutMillis": "TIMEOUT_MILLIS",
"emitIntermediateResults": false,
"forkedJvmArgs": [
"-Xmx512m"