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