Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#245 - Utility method for loading type systems in SPI providers #246

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 26 additions & 1 deletion uima-doc-v3-users-guide/src/docs/asciidoc/uv3.spi.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@
// specific language governing permissions and limitations
// under the License.

[[_uv3.custom_java_objects]]
[[_uv3.spi]]
= Type discovery via SPI

== JCas class discovery

JCas types and associated type system descriptions can be made discoverable by UIMA using Java's
SPI mechanism.

Expand Down Expand Up @@ -50,3 +52,26 @@ public class MyJCasClassProvider implements JCasClassProvider {

More elaborate implementations might e.g. use uimaFIT to auto-detect types and if there is a JCas
class for any of these types, announce them.

== Type system description discovery

The core UIMA framework defines the `TypeSystemDescriptionProvider` interface to also enable
type system discovery via SPI. However, note that currently only uimaFIT actually implements
the type system discovery.

Here is an example of how to implement a type system description provider for use with
uimaFIT:


[source]
----
import org.apache.uima.util.TypeSystemUtil;

public class MyTypeSystemDescriptionProvider implements TypeSystemDescriptionProvider {
@Override}
public List<TypeSystemDescription> listTypeSystemDescriptions() {
return TypeSystemUtil.loadTypeSystemDescriptionsFromClasspath(getClass(), "TypeSystem1.xml",
"TypeSystem2.xml");
}
}
----
61 changes: 61 additions & 0 deletions uimaj-core/src/main/java/org/apache/uima/util/TypeSystemUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@

package org.apache.uima.util;

import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
Expand All @@ -30,13 +32,72 @@
import org.apache.uima.cas.Type;
import org.apache.uima.cas.TypeSystem;
import org.apache.uima.cas.impl.LowLevelTypeSystem;
import org.apache.uima.resource.ResourceManager;
import org.apache.uima.resource.impl.ResourceManager_impl;
import org.apache.uima.resource.metadata.AllowedValue;
import org.apache.uima.resource.metadata.FeatureDescription;
import org.apache.uima.resource.metadata.TypeDescription;
import org.apache.uima.resource.metadata.TypeSystemDescription;
import org.apache.uima.spi.TypeSystemDescriptionProvider;

public class TypeSystemUtil {

/**
* Loads type system descriptions and resolves their imports. For example when you place a
* {@link TypeSystemDescriptionProvider} implementation and place the type system descriptions it
* should provide in the same package, you can use this method to conveniently load them simply by
* name in the provider implementation.
*
* <pre>
* public class MyTypeSystemDescriptionProvider implements TypeSystemDescriptionProvider {
* {@code @Override}
* {@code public List<TypeSystemDescription> listTypeSystemDescriptions()} {
* return TypeSystemUtil.loadTypeSystemDescriptionsFromClasspath(getClass(), "TypeSystem1.xml",
* "TypeSystem2.xml");
* }
* }
* </pre>
*
*
* @param aContext
* a context class. If the locations are not absolute, then they are looked up relative
* to this context class as per {@link Class#getResource(String)}.
* @param typeSystemDescriptionLocations
* type system description locations to load.
* @return list of the loaded and resolved descriptions.
*/
public static List<TypeSystemDescription> loadTypeSystemDescriptionsFromClasspath(
Class<?> aContext, String... typeSystemDescriptionLocations) {

ResourceManager resMgr = new ResourceManager_impl(aContext.getClassLoader());
try {
List<TypeSystemDescription> typeSystemDescriptions = new ArrayList<>();

for (String typeSystem : typeSystemDescriptionLocations) {
URL resource = aContext.getResource(typeSystem);
if (resource == null) {
UIMAFramework.getLogger()
.error("Unable to locate type system description as a resource [{}]", typeSystem);
continue;
}

try {
TypeSystemDescription tsd = UIMAFramework.getXMLParser()
.parseTypeSystemDescription(new XMLInputSource(resource));
tsd.resolveImports(resMgr);
typeSystemDescriptions.add(tsd);
} catch (InvalidXMLException | IOException e) {
UIMAFramework.getLogger().error("Error loading type system description [{}] from [{}]",
typeSystem, resource, e);
}
}

return typeSystemDescriptions;
} finally {
resMgr.destroy();
}
}

/**
* Convert a {@link TypeSystem} to an equivalent {@link TypeSystemDescription}.
*
Expand Down