This is an automated email from the ASF dual-hosted git repository.
ndipiazza 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 70da6e034 TIKA-4581: Fix packaging issues and allow plugin-roots
override (#2486)
70da6e034 is described below
commit 70da6e03435812dc85c85c2948e8550595fc0794
Author: Nicholas DiPiazza <[email protected]>
AuthorDate: Sat Dec 27 11:53:24 2025 -0600
TIKA-4581: Fix packaging issues and allow plugin-roots override (#2486)
* TIKA-4581: Add --plugin-roots CLI parameter for tika-grpc
Adds --plugin-roots command-line parameter to override plugin-roots from
config file.
Problem:
Users had to include 'plugin-roots' in tika-config.json file, which made
Docker deployments less flexible. Different environments might need
different
plugin locations.
Solution:
- Added --plugin-roots CLI parameter to TikaGrpcServer
- Parameter accepts comma-separated list of plugin directories
- CLI parameter overrides config file if specified
- Falls back to config file if not specified
Changes:
- TikaGrpcServer: Added --plugin-roots parameter
- TikaGrpcServerImpl: Updated constructor to accept pluginRootsOverride
- TikaPluginManager: Added loadFromPaths() method for string-based paths
Usage:
java -jar tika-grpc.jar -c config.json --plugin-roots /tmp/tika-plugins
Or Docker:
docker run apache/tika-grpc:latest -c /config/config.json --plugin-roots
/tmp/tika-plugins
Benefits:
- No need to modify config files for different environments
- Simplifies Docker/Kubernetes deployments
- Backward compatible - config file still works if CLI not specified
* TIKA-4581: Copy all plugin ZIPs to tika-grpc/target/plugins
Adds all 13 plugin modules to the copy-plugins execution:
- tika-pipes-az-blob
- tika-pipes-csv
- tika-pipes-gcs
- tika-pipes-ignite
- tika-pipes-jdbc
- tika-pipes-json
- tika-pipes-kafka
- tika-pipes-microsoft-graph
- tika-pipes-opensearch
- tika-pipes-s3
- tika-pipes-solr
This ensures all plugins are available for Docker builds.
* TIKA-4581: Fix MANIFEST.MF extraction for az-blob, gcs, jdbc plugins
The assembly.xml was trying to include MANIFEST.MF from classes/ directory
but it only exists in the JAR file. Changed to use dependencySet with
unpack to properly extract MANIFEST.MF and extensions.idx from the
project artifact JAR into the plugin ZIP.
This fixes 'Cannot find the manifest path' errors for these 3 plugins.
* TIKA-4581: Fix GCS plugin class name in plugin.properties
The plugin.properties referenced the wrong class name:
Wrong: org.apache.tika.pipes.emitter.gcs.GCSEmitterPlugin
Correct: org.apache.tika.pipes.plugin.gcs.GCSPipesPlugin
This caused ClassNotFoundException when loading the GCS plugin.
---
tika-grpc/pom.xml | 77 +++++++++++++++++
.../org/apache/tika/pipes/grpc/TikaGrpcServer.java | 5 +-
.../apache/tika/pipes/grpc/TikaGrpcServerImpl.java | 12 ++-
.../src/main/assembly/assembly.xml | 97 +++++++++++++---------
.../tika-pipes-gcs/src/main/assembly/assembly.xml | 97 +++++++++++++---------
.../src/main/resources/plugin.properties | 2 +-
.../tika-pipes-jdbc/src/main/assembly/assembly.xml | 97 +++++++++++++---------
.../org/apache/tika/plugins/TikaPluginManager.java | 31 +++++++
8 files changed, 298 insertions(+), 120 deletions(-)
diff --git a/tika-grpc/pom.xml b/tika-grpc/pom.xml
index a30fb0c3f..88d919936 100644
--- a/tika-grpc/pom.xml
+++ b/tika-grpc/pom.xml
@@ -299,6 +299,83 @@
<type>zip</type>
<overWrite>true</overWrite>
</artifactItem>
+ <artifactItem>
+ <groupId>org.apache.tika</groupId>
+ <artifactId>tika-pipes-az-blob</artifactId>
+ <version>${project.version}</version>
+ <type>zip</type>
+ <overWrite>true</overWrite>
+ </artifactItem>
+ <artifactItem>
+ <groupId>org.apache.tika</groupId>
+ <artifactId>tika-pipes-csv</artifactId>
+ <version>${project.version}</version>
+ <type>zip</type>
+ <overWrite>true</overWrite>
+ </artifactItem>
+ <artifactItem>
+ <groupId>org.apache.tika</groupId>
+ <artifactId>tika-pipes-gcs</artifactId>
+ <version>${project.version}</version>
+ <type>zip</type>
+ <overWrite>true</overWrite>
+ </artifactItem>
+ <artifactItem>
+ <groupId>org.apache.tika</groupId>
+ <artifactId>tika-pipes-ignite</artifactId>
+ <version>${project.version}</version>
+ <type>zip</type>
+ <overWrite>true</overWrite>
+ </artifactItem>
+ <artifactItem>
+ <groupId>org.apache.tika</groupId>
+ <artifactId>tika-pipes-jdbc</artifactId>
+ <version>${project.version}</version>
+ <type>zip</type>
+ <overWrite>true</overWrite>
+ </artifactItem>
+ <artifactItem>
+ <groupId>org.apache.tika</groupId>
+ <artifactId>tika-pipes-json</artifactId>
+ <version>${project.version}</version>
+ <type>zip</type>
+ <overWrite>true</overWrite>
+ </artifactItem>
+ <artifactItem>
+ <groupId>org.apache.tika</groupId>
+ <artifactId>tika-pipes-kafka</artifactId>
+ <version>${project.version}</version>
+ <type>zip</type>
+ <overWrite>true</overWrite>
+ </artifactItem>
+ <artifactItem>
+ <groupId>org.apache.tika</groupId>
+ <artifactId>tika-pipes-microsoft-graph</artifactId>
+ <version>${project.version}</version>
+ <type>zip</type>
+ <overWrite>true</overWrite>
+ </artifactItem>
+ <artifactItem>
+ <groupId>org.apache.tika</groupId>
+ <artifactId>tika-pipes-opensearch</artifactId>
+ <version>${project.version}</version>
+ <type>zip</type>
+ <overWrite>true</overWrite>
+ </artifactItem>
+ <artifactItem>
+ <groupId>org.apache.tika</groupId>
+ <artifactId>tika-pipes-s3</artifactId>
+ <version>${project.version}</version>
+ <type>zip</type>
+ <overWrite>true</overWrite>
+ </artifactItem>
+ <artifactItem>
+ <groupId>org.apache.tika</groupId>
+ <artifactId>tika-pipes-solr</artifactId>
+ <version>${project.version}</version>
+ <type>zip</type>
+ <overWrite>true</overWrite>
+ </artifactItem>
</artifactItems>
</configuration>
</execution>
diff --git
a/tika-grpc/src/main/java/org/apache/tika/pipes/grpc/TikaGrpcServer.java
b/tika-grpc/src/main/java/org/apache/tika/pipes/grpc/TikaGrpcServer.java
index 2b350e382..810f58961 100644
--- a/tika-grpc/src/main/java/org/apache/tika/pipes/grpc/TikaGrpcServer.java
+++ b/tika-grpc/src/main/java/org/apache/tika/pipes/grpc/TikaGrpcServer.java
@@ -49,6 +49,9 @@ public class TikaGrpcServer {
@Parameter(names = {"-l", "--plugins"}, description = "The tika pipes
plugins config file", help = true)
private File tikaPlugins;
+ @Parameter(names = {"--plugin-roots"}, description = "Comma-separated list
of plugin root directories (overrides config file)", help = true)
+ private String pluginRoots;
+
@Parameter(names = {"-s", "--secure"}, description = "Enable credentials
required to access this grpc server")
private boolean secure;
@@ -93,7 +96,7 @@ public class TikaGrpcServer {
healthStatusManager.setStatus(TikaGrpcServer.class.getSimpleName(),
ServingStatus.SERVING);
server = Grpc
.newServerBuilderForPort(port, creds)
- .addService(new
TikaGrpcServerImpl(tikaConfigFile.getAbsolutePath()))
+ .addService(new
TikaGrpcServerImpl(tikaConfigFile.getAbsolutePath(), pluginRoots))
.addService(healthStatusManager.getHealthService())
.addService(ProtoReflectionServiceV1.newInstance())
.build()
diff --git
a/tika-grpc/src/main/java/org/apache/tika/pipes/grpc/TikaGrpcServerImpl.java
b/tika-grpc/src/main/java/org/apache/tika/pipes/grpc/TikaGrpcServerImpl.java
index de318e3fb..aa102a42a 100644
--- a/tika-grpc/src/main/java/org/apache/tika/pipes/grpc/TikaGrpcServerImpl.java
+++ b/tika-grpc/src/main/java/org/apache/tika/pipes/grpc/TikaGrpcServerImpl.java
@@ -83,6 +83,10 @@ class TikaGrpcServerImpl extends TikaGrpc.TikaImplBase {
PluginManager pluginManager;
TikaGrpcServerImpl(String tikaConfigPath) throws TikaConfigException,
IOException {
+ this(tikaConfigPath, null);
+ }
+
+ TikaGrpcServerImpl(String tikaConfigPath, String pluginRootsOverride)
throws TikaConfigException, IOException {
File tikaConfigFile = new File(tikaConfigPath);
if (!tikaConfigFile.exists()) {
throw new TikaConfigException("Tika config file does not exist: "
+ tikaConfigPath);
@@ -102,7 +106,13 @@ class TikaGrpcServerImpl extends TikaGrpc.TikaImplBase {
pipesClient = new PipesClient(pipesConfig, configPath);
try {
- pluginManager = TikaPluginManager.load(tikaJsonConfig);
+ if (pluginRootsOverride != null &&
!pluginRootsOverride.trim().isEmpty()) {
+ // Use command-line plugin roots
+ pluginManager =
TikaPluginManager.loadFromPaths(pluginRootsOverride);
+ } else {
+ // Use plugin roots from config file
+ pluginManager = TikaPluginManager.load(tikaJsonConfig);
+ }
pluginManager.loadPlugins();
pluginManager.startPlugins();
} catch (TikaConfigException e) {
diff --git
a/tika-pipes/tika-pipes-plugins/tika-pipes-az-blob/src/main/assembly/assembly.xml
b/tika-pipes/tika-pipes-plugins/tika-pipes-az-blob/src/main/assembly/assembly.xml
index 0b8fe6e79..35755f0d1 100644
---
a/tika-pipes/tika-pipes-plugins/tika-pipes-az-blob/src/main/assembly/assembly.xml
+++
b/tika-pipes/tika-pipes-plugins/tika-pipes-az-blob/src/main/assembly/assembly.xml
@@ -1,45 +1,64 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
- 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
+ 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
+ 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.
+ 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.
-->
-<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.2.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.2.0
http://maven.apache.org/xsd/assembly-2.2.0.xsd">
- <id>plugin</id>
- <formats>
- <format>zip</format>
- </formats>
- <includeBaseDirectory>true</includeBaseDirectory>
- <baseDirectory>${project.artifactId}-${project.version}</baseDirectory>
- <fileSets>
- <fileSet>
- <directory>${project.build.directory}</directory>
- <outputDirectory>/</outputDirectory>
- <includes>
- <include>${project.artifactId}-${project.version}.jar</include>
- </includes>
- </fileSet>
- <fileSet>
- <directory>${project.build.directory}/lib</directory>
- <outputDirectory>/lib</outputDirectory>
- <includes>
- <include>*.jar</include>
- </includes>
- </fileSet>
- </fileSets>
+<assembly xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns="http://maven.apache.org/ASSEMBLY/2.0.0"
+ xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.0.0
+ http://maven.apache.org/xsd/assembly-2.0.0.xsd">
+ <id>dependencies-zip</id>
+ <formats>
+ <format>zip</format>
+ </formats>
+ <includeBaseDirectory>false</includeBaseDirectory>
+ <dependencySets>
+ <dependencySet>
+ <outputDirectory>/</outputDirectory>
+ <useProjectArtifact>true</useProjectArtifact>
+ <unpack>true</unpack>
+ <scope>runtime</scope>
+ <includes>
+ <include>${project.groupId}:${project.artifactId}</include>
+ </includes>
+ <unpackOptions>
+ <includes>
+ <include>META-INF/MANIFEST.MF</include>
+ <include>META-INF/extensions.idx</include>
+ </includes>
+ </unpackOptions>
+ </dependencySet>
+ </dependencySets>
+ <fileSets>
+ <fileSet>
+ <directory>${project.build.directory}/lib</directory>
+ <outputDirectory>/lib</outputDirectory>
+ </fileSet>
+ <fileSet>
+ <directory>${project.build.directory}</directory>
+ <outputDirectory>/lib</outputDirectory>
+ <includes>
+ <include>${project.artifactId}-${project.version}.jar</include>
+ </includes>
+ </fileSet>
+ <fileSet>
+ <directory>${project.basedir}/src/main/resources</directory>
+ <outputDirectory>/</outputDirectory>
+ <includes>
+ <include>plugin.properties</include>
+ </includes>
+ </fileSet>
+ </fileSets>
</assembly>
diff --git
a/tika-pipes/tika-pipes-plugins/tika-pipes-gcs/src/main/assembly/assembly.xml
b/tika-pipes/tika-pipes-plugins/tika-pipes-gcs/src/main/assembly/assembly.xml
index 0b8fe6e79..35755f0d1 100644
---
a/tika-pipes/tika-pipes-plugins/tika-pipes-gcs/src/main/assembly/assembly.xml
+++
b/tika-pipes/tika-pipes-plugins/tika-pipes-gcs/src/main/assembly/assembly.xml
@@ -1,45 +1,64 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
- 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
+ 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
+ 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.
+ 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.
-->
-<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.2.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.2.0
http://maven.apache.org/xsd/assembly-2.2.0.xsd">
- <id>plugin</id>
- <formats>
- <format>zip</format>
- </formats>
- <includeBaseDirectory>true</includeBaseDirectory>
- <baseDirectory>${project.artifactId}-${project.version}</baseDirectory>
- <fileSets>
- <fileSet>
- <directory>${project.build.directory}</directory>
- <outputDirectory>/</outputDirectory>
- <includes>
- <include>${project.artifactId}-${project.version}.jar</include>
- </includes>
- </fileSet>
- <fileSet>
- <directory>${project.build.directory}/lib</directory>
- <outputDirectory>/lib</outputDirectory>
- <includes>
- <include>*.jar</include>
- </includes>
- </fileSet>
- </fileSets>
+<assembly xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns="http://maven.apache.org/ASSEMBLY/2.0.0"
+ xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.0.0
+ http://maven.apache.org/xsd/assembly-2.0.0.xsd">
+ <id>dependencies-zip</id>
+ <formats>
+ <format>zip</format>
+ </formats>
+ <includeBaseDirectory>false</includeBaseDirectory>
+ <dependencySets>
+ <dependencySet>
+ <outputDirectory>/</outputDirectory>
+ <useProjectArtifact>true</useProjectArtifact>
+ <unpack>true</unpack>
+ <scope>runtime</scope>
+ <includes>
+ <include>${project.groupId}:${project.artifactId}</include>
+ </includes>
+ <unpackOptions>
+ <includes>
+ <include>META-INF/MANIFEST.MF</include>
+ <include>META-INF/extensions.idx</include>
+ </includes>
+ </unpackOptions>
+ </dependencySet>
+ </dependencySets>
+ <fileSets>
+ <fileSet>
+ <directory>${project.build.directory}/lib</directory>
+ <outputDirectory>/lib</outputDirectory>
+ </fileSet>
+ <fileSet>
+ <directory>${project.build.directory}</directory>
+ <outputDirectory>/lib</outputDirectory>
+ <includes>
+ <include>${project.artifactId}-${project.version}.jar</include>
+ </includes>
+ </fileSet>
+ <fileSet>
+ <directory>${project.basedir}/src/main/resources</directory>
+ <outputDirectory>/</outputDirectory>
+ <includes>
+ <include>plugin.properties</include>
+ </includes>
+ </fileSet>
+ </fileSets>
</assembly>
diff --git
a/tika-pipes/tika-pipes-plugins/tika-pipes-gcs/src/main/resources/plugin.properties
b/tika-pipes/tika-pipes-plugins/tika-pipes-gcs/src/main/resources/plugin.properties
index fa83efcfb..0102ccbe2 100644
---
a/tika-pipes/tika-pipes-plugins/tika-pipes-gcs/src/main/resources/plugin.properties
+++
b/tika-pipes/tika-pipes-plugins/tika-pipes-gcs/src/main/resources/plugin.properties
@@ -15,7 +15,7 @@
# limitations under the License.
plugin.id=tika-pipes-gcs-plugin
-plugin.class=org.apache.tika.pipes.emitter.gcs.GCSEmitterPlugin
+plugin.class=org.apache.tika.pipes.plugin.gcs.GCSPipesPlugin
plugin.version=4.0.0-SNAPSHOT
plugin.provider=Apache Tika
plugin.description=Pipes for the Google Cloud Storage
diff --git
a/tika-pipes/tika-pipes-plugins/tika-pipes-jdbc/src/main/assembly/assembly.xml
b/tika-pipes/tika-pipes-plugins/tika-pipes-jdbc/src/main/assembly/assembly.xml
index 0b8fe6e79..35755f0d1 100644
---
a/tika-pipes/tika-pipes-plugins/tika-pipes-jdbc/src/main/assembly/assembly.xml
+++
b/tika-pipes/tika-pipes-plugins/tika-pipes-jdbc/src/main/assembly/assembly.xml
@@ -1,45 +1,64 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
- 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
+ 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
+ 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.
+ 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.
-->
-<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.2.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.2.0
http://maven.apache.org/xsd/assembly-2.2.0.xsd">
- <id>plugin</id>
- <formats>
- <format>zip</format>
- </formats>
- <includeBaseDirectory>true</includeBaseDirectory>
- <baseDirectory>${project.artifactId}-${project.version}</baseDirectory>
- <fileSets>
- <fileSet>
- <directory>${project.build.directory}</directory>
- <outputDirectory>/</outputDirectory>
- <includes>
- <include>${project.artifactId}-${project.version}.jar</include>
- </includes>
- </fileSet>
- <fileSet>
- <directory>${project.build.directory}/lib</directory>
- <outputDirectory>/lib</outputDirectory>
- <includes>
- <include>*.jar</include>
- </includes>
- </fileSet>
- </fileSets>
+<assembly xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns="http://maven.apache.org/ASSEMBLY/2.0.0"
+ xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.0.0
+ http://maven.apache.org/xsd/assembly-2.0.0.xsd">
+ <id>dependencies-zip</id>
+ <formats>
+ <format>zip</format>
+ </formats>
+ <includeBaseDirectory>false</includeBaseDirectory>
+ <dependencySets>
+ <dependencySet>
+ <outputDirectory>/</outputDirectory>
+ <useProjectArtifact>true</useProjectArtifact>
+ <unpack>true</unpack>
+ <scope>runtime</scope>
+ <includes>
+ <include>${project.groupId}:${project.artifactId}</include>
+ </includes>
+ <unpackOptions>
+ <includes>
+ <include>META-INF/MANIFEST.MF</include>
+ <include>META-INF/extensions.idx</include>
+ </includes>
+ </unpackOptions>
+ </dependencySet>
+ </dependencySets>
+ <fileSets>
+ <fileSet>
+ <directory>${project.build.directory}/lib</directory>
+ <outputDirectory>/lib</outputDirectory>
+ </fileSet>
+ <fileSet>
+ <directory>${project.build.directory}</directory>
+ <outputDirectory>/lib</outputDirectory>
+ <includes>
+ <include>${project.artifactId}-${project.version}.jar</include>
+ </includes>
+ </fileSet>
+ <fileSet>
+ <directory>${project.basedir}/src/main/resources</directory>
+ <outputDirectory>/</outputDirectory>
+ <includes>
+ <include>plugin.properties</include>
+ </includes>
+ </fileSet>
+ </fileSets>
</assembly>
diff --git
a/tika-plugins-core/src/main/java/org/apache/tika/plugins/TikaPluginManager.java
b/tika-plugins-core/src/main/java/org/apache/tika/plugins/TikaPluginManager.java
index 638ed5b59..423b84b97 100644
---
a/tika-plugins-core/src/main/java/org/apache/tika/plugins/TikaPluginManager.java
+++
b/tika-plugins-core/src/main/java/org/apache/tika/plugins/TikaPluginManager.java
@@ -134,6 +134,37 @@ public class TikaPluginManager extends
DefaultPluginManager {
return new TikaPluginManager(roots);
}
+ /**
+ * Loads plugin manager from a comma-separated string of paths.
+ *
+ * @param pathsString comma-separated list of plugin root directories
+ * @return the plugin manager
+ * @throws TikaConfigException if configuration is invalid
+ * @throws IOException if reading or plugin initialization fails
+ */
+ public static TikaPluginManager loadFromPaths(String pathsString)
+ throws TikaConfigException, IOException {
+ if (pathsString == null || pathsString.trim().isEmpty()) {
+ throw new TikaConfigException("plugin-roots must not be empty");
+ }
+
+ configurePf4jRuntimeMode();
+
+ List<Path> roots = new java.util.ArrayList<>();
+ for (String path : pathsString.split(",")) {
+ String trimmed = path.trim();
+ if (!trimmed.isEmpty()) {
+ roots.add(java.nio.file.Paths.get(trimmed));
+ }
+ }
+
+ if (roots.isEmpty()) {
+ throw new TikaConfigException("plugin-roots must not be empty");
+ }
+
+ return new TikaPluginManager(roots);
+ }
+
/**
* Loads plugin manager from a configuration file.
*