diff --git a/.gitignore b/.gitignore
index 3a62d2cae..4f5c78a4f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -12,3 +12,4 @@ issuesFixed
.idea
*.iml
.tycho-consumer-pom.xml
+dependency-reduced-pom.xml
diff --git a/PearPackagingMavenPlugin/pom.xml b/PearPackagingMavenPlugin/pom.xml
index 7c972f4d2..d538f526c 100644
--- a/PearPackagingMavenPlugin/pom.xml
+++ b/PearPackagingMavenPlugin/pom.xml
@@ -31,7 +31,7 @@
PearPackagingMavenPlugin
maven-plugin
- Apache UIMA Maven: ${project.artifactId}
+ Apache UIMA Tools: ${project.artifactId}
This is a maven plugin that produces a pear artifact.
${uimaWebsiteUrl}
diff --git a/aggregate-uimaj/pom.xml b/aggregate-uimaj/pom.xml
index 92936832e..6c4f31ecc 100644
--- a/aggregate-uimaj/pom.xml
+++ b/aggregate-uimaj/pom.xml
@@ -49,6 +49,7 @@
../PearPackagingMavenPlugin
../jcasgen-maven-plugin
../uimaj-v3migration-jcas
+ ../uima-bnd-plugin
../uimafit-core
../uimafit-junit
diff --git a/jcasgen-maven-plugin/pom.xml b/jcasgen-maven-plugin/pom.xml
index 56ef36e7e..e6914575b 100644
--- a/jcasgen-maven-plugin/pom.xml
+++ b/jcasgen-maven-plugin/pom.xml
@@ -32,7 +32,7 @@
jcasgen-maven-plugin
maven-plugin
- Apache UIMA Maven: ${project.artifactId}
+ Apache UIMA Tools: ${project.artifactId}
A Maven Plugin for using JCasGen to generate Java classes from
XML type system descriptions
diff --git a/pom.xml b/pom.xml
index 6b7d31136..9bfe2eded 100644
--- a/pom.xml
+++ b/pom.xml
@@ -315,6 +315,7 @@
jcasgen-maven-plugin/**
uimaj-adapter-*/**
uimaj-bom/**
+ uima-bnd-plugin/**
uimaj-component-test-util/**
uimaj-core/**
uimaj-cpe/**
diff --git a/uima-bnd-plugin/pom.xml b/uima-bnd-plugin/pom.xml
new file mode 100644
index 000000000..34d185247
--- /dev/null
+++ b/uima-bnd-plugin/pom.xml
@@ -0,0 +1,97 @@
+
+
+
+ 4.0.0
+
+
+ org.apache.uima
+ uimaj-parent
+ 3.6.0-SNAPSHOT
+ ../uimaj-parent/pom.xml
+
+
+ uima-bnd-plugin
+
+ Apache UIMA Tools: UIMA Plugin for BND
+
+
+
+ org.apache.uima
+ uimaj-core
+ ${project.version}
+
+
+
+
+ biz.aQute.bnd
+ biz.aQute.bndlib
+ provided
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-shade-plugin
+
+
+ package
+
+ shade
+
+
+
+
+
+
+
+
+
+ biz.aQute.bnd:bndlib
+
+
+
+
+ org.osgi
+
+
+ org/osgi/resource
+ org/osgi/service/component/annotations
+ org/osgi/service/metatype/annotations
+ org/osgi/service/repository
+
+
+
+
+
+
+
+
+
+
diff --git a/uima-bnd-plugin/src/main/java/org/apache/uima/tools/bnd/UimaBndPlugin.java b/uima-bnd-plugin/src/main/java/org/apache/uima/tools/bnd/UimaBndPlugin.java
new file mode 100644
index 000000000..3caf4f3b3
--- /dev/null
+++ b/uima-bnd-plugin/src/main/java/org/apache/uima/tools/bnd/UimaBndPlugin.java
@@ -0,0 +1,197 @@
+/*
+ * 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.uima.tools.bnd;
+
+import static java.util.Collections.emptyList;
+
+import java.lang.invoke.MethodHandles;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.regex.Pattern;
+
+import org.apache.uima.UIMAFramework;
+import org.apache.uima.analysis_engine.AnalysisEngineDescription;
+import org.apache.uima.resource.metadata.FsIndexCollection;
+import org.apache.uima.resource.metadata.Import;
+import org.apache.uima.resource.metadata.TypePriorities;
+import org.apache.uima.resource.metadata.TypeSystemDescription;
+import org.apache.uima.util.InvalidXMLException;
+import org.apache.uima.util.XMLInputSource;
+import org.apache.uima.util.XMLParser;
+import org.apache.uima.util.XMLizable;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import aQute.bnd.annotation.plugin.BndPlugin;
+import aQute.bnd.header.Attrs;
+import aQute.bnd.osgi.Analyzer;
+import aQute.bnd.osgi.Resource;
+import aQute.bnd.service.AnalyzerPlugin;
+
+@BndPlugin(name = "UIMA")
+public class UimaBndPlugin
+ implements AnalyzerPlugin
+{
+
+ private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+
+ private static final Pattern XML_FILE = Pattern.compile(".*\\.xml");
+ private static final Pattern QN = Pattern
+ .compile("[_A-Za-z$][_A-Za-z0-9$]*(\\.[_A-Za-z$][_A-Za-z0-9$]*)*");
+
+ private final static XMLParser PARSER = UIMAFramework.getXMLParser();
+
+ @Override
+ public boolean analyzeJar(Analyzer analyzer) throws Exception
+ {
+ var jar = analyzer.getJar();
+ var resources = jar.getResources();
+
+ var importsProcessed = 0;
+ if (resources != null) {
+ for (var entry : resources.entrySet()) {
+ var path = entry.getKey();
+ var resource = entry.getValue();
+
+ try {
+ if (XML_FILE.matcher(path).matches()) {
+ importsProcessed += analyzeXmlFile(analyzer, path, resource);
+ }
+ }
+ catch (Exception e) {
+ analyzer.error("Unexpected exception in processing resource (%s): %s", path, e);
+ }
+ }
+ }
+
+ LOG.info("UIMA bnd plugin processed {} imports", importsProcessed);
+
+ return false;
+ }
+
+ private int analyzeXmlFile(Analyzer analyzer, String path, Resource resource) throws Exception
+ {
+ var desc = readUimaDescriptor(resource);
+ if (desc == null) {
+ return 0;
+ }
+
+ LOG.debug("Found {}: {}", desc.getClass().getSimpleName(), path);
+ var imports = getImportsFromDescriptor(desc);
+
+ var importsProcessed = 0;
+ for (var imp : imports) {
+ if (imp.getName() != null) {
+ handleImportByName(analyzer, path, imp);
+ importsProcessed++;
+ continue;
+ }
+
+ if (imp.getLocation() != null) {
+ handleImportByLocation(imp);
+ continue;
+ }
+
+ LOG.warn(
+ "Found UIMA type system import without name and location - ignoring, please fix your type system description");
+ }
+
+ return importsProcessed;
+ }
+
+ private void handleImportByLocation(Import imp)
+ {
+ LOG.warn(
+ "Found UIMA type system import by location: {} - ignoring, please only use import-by-name",
+ imp.getLocation());
+ }
+
+ private void handleImportByName(Analyzer analyzer, String path, Import imp)
+ {
+ var tsdPackage = imp.getName();
+ int lastSeparatorPosition = tsdPackage.lastIndexOf('.');
+ if (lastSeparatorPosition >= 0) {
+ // Cut the name of the XML file and keep only the package
+ tsdPackage = tsdPackage.substring(0, lastSeparatorPosition);
+ }
+
+ LOG.debug("Found UIMA type system import by name: {}", tsdPackage);
+
+ var pack = analyzer.getPackageRef(tsdPackage);
+ if (!QN.matcher(pack.getFQN()).matches()) {
+ analyzer.warning("Type system import does not seem to refer to a package (%s): %s",
+ path, pack);
+ }
+
+ if (!analyzer.getReferred().containsKey(pack)) {
+ var attrs = new Attrs();
+ analyzer.getReferred().put(pack, attrs);
+ }
+ }
+
+ private List getImportsFromDescriptor(XMLizable desc)
+ {
+ if (desc instanceof TypeSystemDescription tsd) {
+ return asList(tsd.getImports());
+ }
+
+ if (desc instanceof TypePriorities prio) {
+ return asList(prio.getImports());
+ }
+
+ if (desc instanceof FsIndexCollection idxc) {
+ return asList(idxc.getImports());
+ }
+
+ if (desc instanceof AnalysisEngineDescription aed) {
+ var imports = new ArrayList();
+ imports.addAll(
+ getImportsFromDescriptor(aed.getAnalysisEngineMetaData().getTypeSystem()));
+ imports.addAll(
+ getImportsFromDescriptor(aed.getAnalysisEngineMetaData().getTypePriorities()));
+ imports.addAll(getImportsFromDescriptor(
+ aed.getAnalysisEngineMetaData().getFsIndexCollection()));
+ return imports;
+ }
+
+ return emptyList();
+ }
+
+ private XMLizable readUimaDescriptor(Resource resource) throws Exception
+ {
+ try (var in = resource.openInputStream()) {
+ return PARSER.parse(new XMLInputSource(in));
+ }
+ catch (InvalidXMLException e) {
+ // Probably not a type system description - ignore
+ }
+
+ return null;
+ }
+
+ private static List asList(T[] aList)
+ {
+ if (aList == null) {
+ return emptyList();
+ }
+
+ return Arrays.asList(aList);
+ }
+}
\ No newline at end of file
diff --git a/uimaj-bom/pom.xml b/uimaj-bom/pom.xml
index f78600923..741960f06 100644
--- a/uimaj-bom/pom.xml
+++ b/uimaj-bom/pom.xml
@@ -20,18 +20,12 @@
4.0.0
-
- org.apache.uima
- parent-pom
-
- 18-SNAPSHOT
-
-
+ org.apache.uima
uimaj-bom
3.6.0-SNAPSHOT
pom
- Apache UIMA Base: ${project.artifactId}
+ Apache UIMA - BOM
diff --git a/uimaj-documentation/src/docs/asciidoc/tools.adoc b/uimaj-documentation/src/docs/asciidoc/tools.adoc
index 4f2639ed9..2dd8738aa 100644
--- a/uimaj-documentation/src/docs/asciidoc/tools.adoc
+++ b/uimaj-documentation/src/docs/asciidoc/tools.adoc
@@ -37,6 +37,8 @@ include::tools/tools.caseditor.adoc[leveloffset=+1]
include::tools/tools.jcasgen.adoc[leveloffset=+1]
+include::tools/tools.bnd.adoc[leveloffset=+1]
+
include::tools/tools.pear.packager.adoc[leveloffset=+1]
include::tools/tools.pear.packager.maven.adoc[leveloffset=+1]
diff --git a/uimaj-documentation/src/docs/asciidoc/tools/tools.bnd.adoc b/uimaj-documentation/src/docs/asciidoc/tools/tools.bnd.adoc
new file mode 100644
index 000000000..ca9654170
--- /dev/null
+++ b/uimaj-documentation/src/docs/asciidoc/tools/tools.bnd.adoc
@@ -0,0 +1,56 @@
+// 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.
+
+[[ugr.tools.bnd]]
+= UIMA Plugin for bnd
+
+link:https://bndtools.org[Bnd] is a tooling suite for building OSGi bundles.
+Its primary function is generating OSGi meta data by analyzing Java classes.
+However, when using UIMA, it may be necessary to add package imports for packages that contain importable XML files such as UIMA type system descriptions to the OSGi metadata.
+The UIMA plugin for bnd contributes an analyzer that checks for by-name imports in UIMA XML files and adds the necessary package imports.
+
+To use the this plugin, specify it in the POM as follows:
+
+[source,xml,subs="+attributes"]
+----
+
+ biz.aQute.bnd
+ bnd-maven-plugin
+
+
+
+ -plugin.uima: org.apache.uima.tools.bnd.UimaBndPlugin
+
+
+
+
+
+ org.apache.uima
+ uima-bnd-plugin
+ {revnumber}
+
+
+
+----
+
+If the plugin is active during a build, it will log a message like
+
+----
+[INFO] UIMA bnd plugin processed 5 imports
+----
+
+If you need more detailed logging, run the Maven build with the `-X` option.
diff --git a/uimaj-parent/pom.xml b/uimaj-parent/pom.xml
index 041ec4a98..2b514c265 100644
--- a/uimaj-parent/pom.xml
+++ b/uimaj-parent/pom.xml
@@ -31,7 +31,7 @@
org.apache.uima
parent-pom
- 18-SNAPSHOT
+ 18
@@ -153,6 +153,7 @@
2.5.10
2.3.9
3.24.2
+ 7.0.0
1.10.0
2.15.0
3.13.0
@@ -367,6 +368,12 @@
javassist
3.29.2-GA
+
+
+ biz.aQute.bnd
+ biz.aQute.bndlib
+ ${bnd-version}
+
${eclipseP2RepoId}
@@ -666,6 +673,7 @@
+ **/dependency-reduced-pom.xml
**/.asciidoctorconfig.adoc
**/run_configuration/*.launch