This is an automated email from the ASF dual-hosted git repository.
rzo1 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/opennlp.git
The following commit(s) were added to refs/heads/main by this push:
new 1b6ef868 OPENNLP-1567 - OpenNLP Models: Provide a Finder / Loader
Implementation (#606)
1b6ef868 is described below
commit 1b6ef8683af30df10bc937802fa2389f5094a878
Author: Richard Zowalla <[email protected]>
AuthorDate: Tue Jun 18 08:57:39 2024 +0200
OPENNLP-1567 - OpenNLP Models: Provide a Finder / Loader Implementation
(#606)
* OPENNLP-1567 - OpenNLP Models: Provide a Finder / Loader Implementation
---
README.md | 1 +
opennlp-tools-models/pom.xml | 105 +++++++++
.../tools/models/AbstractClassPathModelFinder.java | 123 +++++++++++
.../java/opennlp/tools/models/ClassPathModel.java | 35 +++
.../opennlp/tools/models/ClassPathModelEntry.java | 24 +++
.../opennlp/tools/models/ClassPathModelFinder.java | 32 +++
.../opennlp/tools/models/ClassPathModelLoader.java | 56 +++++
.../models/classgraph/ClassgraphModelFinder.java | 75 +++++++
.../models/simple/SimpleClassPathModelFinder.java | 236 +++++++++++++++++++++
.../tools/models/AbstractClassPathFinderTest.java | 56 +++++
.../tools/models/AbstractClassPathModelTest.java | 57 +++++
.../tools/models/AbstractModelLoaderTest.java | 38 ++++
.../tools/models/AbstractModelUsageTest.java | 61 ++++++
.../classgraph/ClassgraphModelFinderTest.java | 33 +++
.../classgraph/ClassgraphModelLoaderTest.java | 33 +++
.../classgraph/ClassgraphModelUsageTest.java | 33 +++
.../simple/SimpleClassPathModelFinderTest.java | 34 +++
.../tools/models/simple/SimpleModelLoaderTest.java | 33 +++
.../tools/models/simple/SimpleModelUsageTest.java | 33 +++
pom.xml | 5 +-
20 files changed, 1102 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 9177023b..79e69a1a 100644
--- a/README.md
+++ b/README.md
@@ -64,6 +64,7 @@ You can also follow our [mailing
lists](http://opennlp.apache.org/mailing-lists.
Currently, the library has different packages:
* `opennlp-tools` : The core toolkit.
+* `opennlp-tools-models` : A set of classes to load [OpenNLP
models](https://github.com/apache/opennlp-models) from the classpath.
* `opennlp-uima` : A set of [Apache UIMA](https://uima.apache.org) annotators.
* `opennlp-brat-annotator` : A set of annotators for
[BRAT](http://brat.nlplab.org/)
* `opennlp-morfologik-addon` : An addon for Morfologik
diff --git a/opennlp-tools-models/pom.xml b/opennlp-tools-models/pom.xml
new file mode 100644
index 00000000..79b4b5f3
--- /dev/null
+++ b/opennlp-tools-models/pom.xml
@@ -0,0 +1,105 @@
+<?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
+
+ 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.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.opennlp</groupId>
+ <artifactId>opennlp</artifactId>
+ <version>2.3.4-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>opennlp-tools-models</artifactId>
+ <packaging>jar</packaging>
+ <name>Apache OpenNLP Tools Models</name>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.opennlp</groupId>
+ <artifactId>opennlp-tools</artifactId>
+ <version>${project.version}</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>io.github.classgraph</groupId>
+ <artifactId>classgraph</artifactId>
+ <version>${classgraph.version}</version>
+ <optional>true</optional>
+ </dependency>
+
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.junit.jupiter</groupId>
+ <artifactId>junit-jupiter-api</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.junit.jupiter</groupId>
+ <artifactId>junit-jupiter-engine</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-simple</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ <!-- models -->
+ <dependency>
+ <groupId>org.apache.opennlp</groupId>
+ <artifactId>opennlp-models-sentdetect-en</artifactId>
+ <version>${opennlp.models.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.opennlp</groupId>
+ <artifactId>opennlp-models-langdetect</artifactId>
+ <version>${opennlp.models.version}</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>${maven.surefire.plugin}</version>
+ <configuration>
+ <argLine>-Xmx2048m
-Dorg.slf4j.simpleLogger.defaultLogLevel=off --add-opens
java.base/jdk.internal.loader=ALL-UNNAMED</argLine>
+ <forkCount>${opennlp.forkCount}</forkCount>
+ <useSystemClassLoader>false</useSystemClassLoader>
+ <failIfNoSpecifiedTests>false</failIfNoSpecifiedTests>
+ </configuration>
+ </plugin>
+
+ </plugins>
+ </build>
+</project>
diff --git
a/opennlp-tools-models/src/main/java/opennlp/tools/models/AbstractClassPathModelFinder.java
b/opennlp-tools-models/src/main/java/opennlp/tools/models/AbstractClassPathModelFinder.java
new file mode 100644
index 00000000..eeaa43d9
--- /dev/null
+++
b/opennlp-tools-models/src/main/java/opennlp/tools/models/AbstractClassPathModelFinder.java
@@ -0,0 +1,123 @@
+/*
+ * 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 opennlp.tools.models;
+
+import java.net.URI;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+
+/**
+ * Enables the detection of OpenNLP models in the classpath. By default, this
class will search
+ * for JAR files starting with "opennlp-models-*". This wildcard pattern can
be adjusted by
+ * using the alternative constructor of this class.
+ */
+public abstract class AbstractClassPathModelFinder implements
ClassPathModelFinder {
+
+ protected static final String JAR = "jar";
+
+ private final String jarModelPrefix;
+ private Set<ClassPathModelEntry> models;
+
+ /**
+ * By default, it scans for "opennlp-models-*.jar".
+ */
+ public AbstractClassPathModelFinder() {
+ this(OPENNLP_MODEL_JAR_PREFIX);
+ }
+
+ /**
+ * @param jarModelPrefix The leafnames of the jars that should be canned
(e.g. "opennlp.jar").
+ * May contain a wildcard glob ("opennlp-*.jar"). It
must not be {@code null}.
+ */
+ public AbstractClassPathModelFinder(String jarModelPrefix) {
+ Objects.requireNonNull(jarModelPrefix, "modelJarPrefix must not be null");
+ this.jarModelPrefix = jarModelPrefix;
+ }
+
+ @Override
+ public Set<ClassPathModelEntry> findModels(boolean reloadCache) {
+
+ if (this.models == null || reloadCache) {
+ final List<URI> classpathModels = getMatchingURIs("*.bin", getContext());
+ final List<URI> classPathProperties =
getMatchingURIs("model.properties", getContext());
+
+ this.models = new HashSet<>();
+
+ for (URI model : classpathModels) {
+ URI m = null;
+ for (URI prop : classPathProperties) {
+ if (jarPathsMatch(model, prop)) {
+ m = prop;
+ break;
+ }
+ }
+ this.models.add(new ClassPathModelEntry(model,
Optional.ofNullable(m)));
+
+ }
+ }
+ return this.models;
+ }
+
+ /**
+ * Subclasses can implement this method to provide additional context to
+ * {@link AbstractClassPathModelFinder#getMatchingURIs(String, Object)}.
+ *
+ * @return a context information. May be {@code null}.
+ */
+ protected abstract Object getContext();
+
+ /**
+ * Return matching classpath URIs for the given pattern.
+ *
+ * @param wildcardPattern the pattern. Must not be {@code null}.
+ * @param context an object holding context information. It might be
{@code null}.
+ * @return a list of matching classpath URIs.
+ */
+ protected abstract List<URI> getMatchingURIs(String wildcardPattern, Object
context);
+
+ protected boolean jarPathsMatch(URI uri1, URI uri2) {
+ final String[] parts1 = parseJarURI(uri1);
+ final String[] parts2 = parseJarURI(uri2);
+
+ if (parts1 == null || parts2 == null) {
+ return false;
+ }
+
+ return parts1[0].equals(parts2[0]);
+ }
+
+ protected String[] parseJarURI(URI uri) {
+ if (JAR.equals(uri.getScheme())) {
+ final String ssp = uri.getSchemeSpecificPart();
+ final int separatorIndex = ssp.indexOf("!/");
+ if (separatorIndex > 0) {
+ final String jarFileUri = ssp.substring(0, separatorIndex);
+ final String entryPath = ssp.substring(separatorIndex + 2);
+ return new String[] {jarFileUri, entryPath};
+ }
+ }
+ return null;
+ }
+
+ protected String getJarModelPrefix() {
+ return jarModelPrefix;
+ }
+
+}
diff --git
a/opennlp-tools-models/src/main/java/opennlp/tools/models/ClassPathModel.java
b/opennlp-tools-models/src/main/java/opennlp/tools/models/ClassPathModel.java
new file mode 100644
index 00000000..e89f310a
--- /dev/null
+++
b/opennlp-tools-models/src/main/java/opennlp/tools/models/ClassPathModel.java
@@ -0,0 +1,35 @@
+/*
+ * 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 opennlp.tools.models;
+
+import java.util.Properties;
+
+public record ClassPathModel(Properties properties, byte[] model) {
+
+ public String getModelVersion() {
+ return properties != null ? properties.getProperty("model.version",
"unknown") : "unknown";
+ }
+
+ public String getModelName() {
+ return properties != null ? properties.getProperty("model.name",
"unknown") : "unknown";
+ }
+
+ public String getModelSHA256() {
+ return properties != null ? properties.getProperty("model.sha256",
"unknown") : "unknown";
+ }
+
+}
diff --git
a/opennlp-tools-models/src/main/java/opennlp/tools/models/ClassPathModelEntry.java
b/opennlp-tools-models/src/main/java/opennlp/tools/models/ClassPathModelEntry.java
new file mode 100644
index 00000000..ef09f414
--- /dev/null
+++
b/opennlp-tools-models/src/main/java/opennlp/tools/models/ClassPathModelEntry.java
@@ -0,0 +1,24 @@
+/*
+ * 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 opennlp.tools.models;
+
+import java.net.URI;
+import java.util.Optional;
+
+public record ClassPathModelEntry(URI model, Optional<URI> properties) {
+
+}
diff --git
a/opennlp-tools-models/src/main/java/opennlp/tools/models/ClassPathModelFinder.java
b/opennlp-tools-models/src/main/java/opennlp/tools/models/ClassPathModelFinder.java
new file mode 100644
index 00000000..5603d325
--- /dev/null
+++
b/opennlp-tools-models/src/main/java/opennlp/tools/models/ClassPathModelFinder.java
@@ -0,0 +1,32 @@
+/*
+ * 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 opennlp.tools.models;
+
+import java.util.Set;
+
+public interface ClassPathModelFinder {
+
+ String OPENNLP_MODEL_JAR_PREFIX = "opennlp-models-*.jar";
+
+ /**
+ * Finds OpenNLP models within the classpath.
+ *
+ * @param reloadCache {@code true}, if the internal cache should explicitly
be reloaded
+ * @return A Set of {@link ClassPathModelEntry ClassPathModelEntries}. It
might be empty.
+ */
+ Set<ClassPathModelEntry> findModels(boolean reloadCache);
+}
diff --git
a/opennlp-tools-models/src/main/java/opennlp/tools/models/ClassPathModelLoader.java
b/opennlp-tools-models/src/main/java/opennlp/tools/models/ClassPathModelLoader.java
new file mode 100644
index 00000000..a236fa34
--- /dev/null
+++
b/opennlp-tools-models/src/main/java/opennlp/tools/models/ClassPathModelLoader.java
@@ -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.
+ */
+package opennlp.tools.models;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Objects;
+import java.util.Properties;
+
+/**
+ * Responsible for loading OpenNLP models from the classpath.
+ */
+public class ClassPathModelLoader {
+
+ /**
+ * Loads a {@link ClassPathModel} from a {@link ClassPathModelEntry}
+ *
+ * @param entry must not be {@code null}.
+ * @return a {@link ClassPathModel} containing the model resources.
+ * @throws IOException thrown if something went wrong during reading
resources from the classpath.
+ */
+ public ClassPathModel load(ClassPathModelEntry entry) throws IOException {
+ Objects.requireNonNull(entry, "entry must not be null");
+ Objects.requireNonNull(entry.properties(), "entry.properties() must not be
null");
+ Objects.requireNonNull(entry.model(), "entry.model() must not be null");
+
+ final Properties properties = new Properties();
+
+ if (entry.properties().isPresent()) {
+ try (InputStream inputStream =
entry.properties().get().toURL().openStream()) {
+ properties.load(inputStream);
+ }
+ }
+
+ final byte[] model;
+ try (InputStream inputStream = entry.model().toURL().openStream()) {
+ model = inputStream.readAllBytes();
+ }
+
+ return new ClassPathModel(properties, model);
+ }
+}
diff --git
a/opennlp-tools-models/src/main/java/opennlp/tools/models/classgraph/ClassgraphModelFinder.java
b/opennlp-tools-models/src/main/java/opennlp/tools/models/classgraph/ClassgraphModelFinder.java
new file mode 100644
index 00000000..642dc20b
--- /dev/null
+++
b/opennlp-tools-models/src/main/java/opennlp/tools/models/classgraph/ClassgraphModelFinder.java
@@ -0,0 +1,75 @@
+/*
+ * 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 opennlp.tools.models.classgraph;
+
+import java.net.URI;
+import java.util.Collections;
+import java.util.List;
+
+import io.github.classgraph.ClassGraph;
+import io.github.classgraph.ResourceList;
+import io.github.classgraph.ScanResult;
+
+import opennlp.tools.models.AbstractClassPathModelFinder;
+import opennlp.tools.models.ClassPathModelFinder;
+
+/**
+ * Enables the detection of OpenNLP models in the classpath via classgraph.
+ * By default, this class will search for JAR files starting with
"opennlp-models-*".
+ * This wildcard pattern can be adjusted by using the alternative constructor
of this class.
+ */
+public class ClassgraphModelFinder extends AbstractClassPathModelFinder
implements ClassPathModelFinder {
+
+ /**
+ * By default, it scans for "opennlp-models-*.jar".
+ */
+ public ClassgraphModelFinder() {
+ this(OPENNLP_MODEL_JAR_PREFIX);
+ }
+
+ /**
+ * @param modelJarPrefix The leafnames of the jars that should be canned
(e.g. "opennlp.jar").
+ * May contain a wildcard glob ("opennlp-*.jar"). It
must not be {@code null}.
+ */
+ public ClassgraphModelFinder(String modelJarPrefix) {
+ super(modelJarPrefix);
+ }
+
+ /**
+ * @return a {@link ScanResult} ready for consumption. Caller is responsible
for closing it.
+ */
+ @Override
+ protected Object getContext() {
+ return new
ClassGraph().acceptJars(getJarModelPrefix()).disableDirScanning().scan();
+ }
+
+ /**
+ * @param wildcardPattern the pattern. Must not be {@code null}.
+ * @param context an object holding context information. It might be
{@code null}.
+ * @return a list of matching classpath uris.
+ */
+ @Override
+ protected List<URI> getMatchingURIs(String wildcardPattern, Object context) {
+ if (context instanceof ScanResult sr) {
+ try (sr; final ResourceList resources =
sr.getResourcesMatchingWildcard(wildcardPattern)) {
+ return resources.getURIs();
+ }
+ }
+ return Collections.emptyList();
+ }
+
+}
diff --git
a/opennlp-tools-models/src/main/java/opennlp/tools/models/simple/SimpleClassPathModelFinder.java
b/opennlp-tools-models/src/main/java/opennlp/tools/models/simple/SimpleClassPathModelFinder.java
new file mode 100644
index 00000000..0d00f385
--- /dev/null
+++
b/opennlp-tools-models/src/main/java/opennlp/tools/models/simple/SimpleClassPathModelFinder.java
@@ -0,0 +1,236 @@
+/*
+ * 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 opennlp.tools.models.simple;
+
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.net.JarURLConnection;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Locale;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import opennlp.tools.models.AbstractClassPathModelFinder;
+import opennlp.tools.models.ClassPathModelFinder;
+
+/**
+ * Enables the detection of OpenNLP models in the classpath via JDK classes
+ * By default, this class will search for JAR files starting with
"opennlp-models-*".
+ * This wildcard pattern can be adjusted by using the alternative constructor
of this class.
+ * <p>
+ * It is a rather simple implementation of scanning the classpath by trying to
obtain {@link URL urls}
+ * from the actual classpath via a chain of possible options. It might not
work for every use-case
+ * since it relies on JDK internals only and doesn't account for classloader
hierarchies or edge-cases.
+ * <p>
+ * It will
+ * (1) Try to see if we have a {@link URLClassLoader} available in the current
thread.
+ * (2) Try to obtain URLs via the build in classloader via reflections
+ * (requires {@code --add-opens java.base/jdk.internal.loader=ALL-UNNAMED} as
JVM argument)
+ * (3) Try to use the bootstrap classpath via {@code java.class.path}.
+ * <p>
+ * If you need a more sophisticated solution,
+ * use {@link opennlp.tools.models.classgraph.ClassgraphModelFinder}.
+ */
+public class SimpleClassPathModelFinder extends AbstractClassPathModelFinder
implements ClassPathModelFinder {
+
+ private static final Logger logger =
LoggerFactory.getLogger(SimpleClassPathModelFinder.class);
+ private static final String FILE_PREFIX = "file";
+ private static final Pattern CLASSPATH_SEPARATOR_PATTERN =
Pattern.compile("[;:]");
+ // ; for Windows, : for Linux/OSX
+
+ /**
+ * By default, it scans for "opennlp-models-*.jar".
+ */
+ public SimpleClassPathModelFinder() {
+ this(OPENNLP_MODEL_JAR_PREFIX);
+ }
+
+ /**
+ * @param modelJarPrefix The leafnames of the jars that should be canned
(e.g. "opennlp.jar").
+ * May contain a wildcard glob ("opennlp-*.jar"). It
must not be {@code null}.
+ */
+ public SimpleClassPathModelFinder(String modelJarPrefix) {
+ super(modelJarPrefix);
+ }
+
+ /**
+ * @return always {@code NULL} as it is not needed for the simple case.
+ */
+ @Override
+ protected Object getContext() {
+ return null; //not needed for the simple case. Just return NULL.
+ }
+
+ /**
+ * @param wildcardPattern the pattern. Must not be {@code null}.
+ * @param context an object holding context information.
+ * It is unused within this implementation.
+ * @return a list of matching classpath uris.
+ */
+ @Override
+ protected List<URI> getMatchingURIs(String wildcardPattern, Object context) {
+ if (wildcardPattern == null) {
+ return Collections.emptyList();
+ }
+
+ final boolean isWindows = isWindows();
+ final List<URL> cp = getClassPathElements();
+ final List<URI> cpu = new ArrayList<>();
+ final Pattern jarPattern = Pattern.compile(asRegex("*" +
getJarModelPrefix()));
+ final Pattern filePattern = Pattern.compile(asRegex("*" +
wildcardPattern));
+
+ for (URL url : cp) {
+ if (matchesPattern(url, jarPattern)) {
+ try {
+ for (URI u : getURIsFromJar(url, isWindows)) {
+ if (matchesPattern(u.toURL(), filePattern)) {
+ cpu.add(u);
+ }
+ }
+ } catch (IOException e) {
+ logger.warn("Cannot read content of {}.", url, e);
+ }
+ }
+ }
+
+ return cpu;
+ }
+
+ /**
+ * Escapes a wildcard expressions for usage as a Java regular expression.
+ *
+ * @param wildcard must not be {@code null}.
+ * @return the escaped regex.
+ */
+ private String asRegex(String wildcard) {
+ return wildcard
+ .replace(".", "\\.")
+ .replace("*", ".*")
+ .replace("?", ".");
+ }
+
+ private boolean matchesPattern(URL url, Pattern pattern) {
+ return pattern.matcher(url.getFile()).matches();
+ }
+
+ private List<URI> getURIsFromJar(URL fileUrl, boolean isWindows) throws
IOException {
+ final List<URI> uris = new ArrayList<>();
+ final URL jarUrl = new URL(JAR + ":" +
+ (isWindows
+ ? fileUrl.toString().replace("\\", "/")
+ : fileUrl.toString())
+ + "!/");
+ final JarURLConnection jarConnection = (JarURLConnection)
jarUrl.openConnection();
+ try (JarFile jarFile = jarConnection.getJarFile()) {
+ final Enumeration<JarEntry> entries = jarFile.entries();
+ while (entries.hasMoreElements()) {
+ final JarEntry entry = entries.nextElement();
+ if (!entry.isDirectory()) {
+ final URL entryUrl = new URL(jarUrl + entry.getName());
+ try {
+ uris.add(entryUrl.toURI());
+ } catch (URISyntaxException ignored) {
+ //if we cannot convert to URI here, we ignore that entry.
+ }
+ }
+ }
+ }
+
+ return uris;
+ }
+
+ private boolean isWindows() {
+ return System.getProperty("os.name",
"unknown").toLowerCase(Locale.ROOT).contains("win");
+ }
+
+ /**
+ * Try to obtain URLs from the classpath in the following order:
+ * <p>
+ * (1) Try to see if we have a {@link URLClassLoader}.
+ * (2) Try to obtain URLs via the build in classloader via reflections
(requires an add opens JVM argument)
+ * (3) Try to use the bootstrap classpath via {@code java.class.path}.
+ *
+ * @return a list of URLs within the classpath.
+ */
+ private List<URL> getClassPathElements() {
+ final ClassLoader cl = Thread.currentThread().getContextClassLoader();
+
+ if (cl instanceof URLClassLoader ucl) {
+ return Arrays.asList(ucl.getURLs());
+ } else {
+ final URL[] fromUcp = getURLs(cl);
+ if (fromUcp != null && fromUcp.length > 0) {
+ return Arrays.asList(fromUcp);
+ } else {
+ final String cp = System.getProperty("java.class.path", "");
+ final Matcher matcher = CLASSPATH_SEPARATOR_PATTERN.matcher(cp);
+ final List<URL> jarUrls = new ArrayList<>();
+ while (matcher.find()) {
+ try {
+ jarUrls.add(new URL(FILE_PREFIX, "", matcher.group()));
+ } catch (MalformedURLException ignored) {
+ //if we cannot parse a URL from the system property, just ignore
it...
+ //we couldn't load it anyway
+ }
+ }
+ return jarUrls;
+ }
+ }
+ }
+
+ /*
+ * Java 9+ Bridge to obtain URLs from classpath.
+ * This requires "--add-opens java.base/jdk.internal.loader=ALL-UNNAMED" as
JVM argument
+ */
+ private URL[] getURLs(ClassLoader classLoader) {
+ try {
+ final Class<?> builtinClazzLoader =
Class.forName("jdk.internal.loader.BuiltinClassLoader");
+
+ final Field ucpField = builtinClazzLoader.getDeclaredField("ucp");
+ ucpField.setAccessible(true);
+
+ final Object ucpObject = ucpField.get(classLoader);
+ final Class<?> clazz = Class.forName("jdk.internal.loader.URLClassPath");
+
+ if (ucpObject != null) {
+ final Method getURLs = clazz.getMethod("getURLs");
+
+ return (URL[]) getURLs.invoke(ucpObject);
+ }
+
+ } catch (Exception ignored) {
+ //ok here because we still have a fallback and this is just one step in
the chain of possible
+ //options to obtain URLs from the classpath
+ }
+ return new URL[0];
+ }
+}
diff --git
a/opennlp-tools-models/src/test/java/opennlp/tools/models/AbstractClassPathFinderTest.java
b/opennlp-tools-models/src/test/java/opennlp/tools/models/AbstractClassPathFinderTest.java
new file mode 100644
index 00000000..e03f08ce
--- /dev/null
+++
b/opennlp-tools-models/src/test/java/opennlp/tools/models/AbstractClassPathFinderTest.java
@@ -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.
+ */
+package opennlp.tools.models;
+
+import java.util.Set;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+public abstract class AbstractClassPathFinderTest extends
AbstractClassPathModelTest {
+
+
+ @Test
+ public void testFindOpenNLPModels() {
+ final ClassPathModelFinder finder = getModelFinder();
+
+ final Set<ClassPathModelEntry> models = finder.findModels(false);
+ assertNotNull(models);
+ assertEquals(2, models.size());
+
+ for (ClassPathModelEntry entry : models) {
+ assertNotNull(entry.model());
+ assertNotNull(entry.properties());
+ assertFalse(entry.properties().isEmpty());
+ }
+
+ //call it twice, yields same results
+ final Set<ClassPathModelEntry> reloadedModels = finder.findModels(false);
+ assertNotNull(reloadedModels);
+ assertEquals(models, reloadedModels);
+
+ //call it with reload cache, yields same results
+ final Set<ClassPathModelEntry> cacheReloadedModels =
finder.findModels(true);
+ assertNotNull(cacheReloadedModels);
+ assertEquals(models, cacheReloadedModels);
+ assertEquals(reloadedModels, cacheReloadedModels);
+ }
+
+}
diff --git
a/opennlp-tools-models/src/test/java/opennlp/tools/models/AbstractClassPathModelTest.java
b/opennlp-tools-models/src/test/java/opennlp/tools/models/AbstractClassPathModelTest.java
new file mode 100644
index 00000000..478cd46b
--- /dev/null
+++
b/opennlp-tools-models/src/test/java/opennlp/tools/models/AbstractClassPathModelTest.java
@@ -0,0 +1,57 @@
+/*
+ * 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 opennlp.tools.models;
+
+import java.io.IOException;
+import java.util.Set;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+public abstract class AbstractClassPathModelTest {
+
+ protected ClassPathModel getClassPathModel(String modelJarPrefix) throws
IOException {
+ return getClassPathModel(modelJarPrefix, false);
+ }
+
+ protected ClassPathModel getClassPathModel(String modelJarPrefix, boolean
expectNotFound)
+ throws IOException {
+ final ClassPathModelFinder finder = getModelFinder(modelJarPrefix);
+
+ final Set<ClassPathModelEntry> models = finder.findModels(false);
+ assertNotNull(models);
+ if (expectNotFound) {
+ assertEquals(0, models.size());
+ return null;
+ } else {
+ assertFalse(models.isEmpty());
+ final ClassPathModelEntry entry = models.iterator().next();
+ assertNotNull(entry);
+ final ClassPathModelLoader loader = new ClassPathModelLoader();
+ final ClassPathModel model = loader.load(entry);
+ assertNotNull(model);
+ assertNotNull(model.model());
+ assertNotNull(model.properties());
+ return model;
+ }
+ }
+
+ protected abstract ClassPathModelFinder getModelFinder();
+
+ protected abstract ClassPathModelFinder getModelFinder(String pattern);
+}
diff --git
a/opennlp-tools-models/src/test/java/opennlp/tools/models/AbstractModelLoaderTest.java
b/opennlp-tools-models/src/test/java/opennlp/tools/models/AbstractModelLoaderTest.java
new file mode 100644
index 00000000..7850c934
--- /dev/null
+++
b/opennlp-tools-models/src/test/java/opennlp/tools/models/AbstractModelLoaderTest.java
@@ -0,0 +1,38 @@
+/*
+ * 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 opennlp.tools.models;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+public abstract class AbstractModelLoaderTest extends
AbstractClassPathModelTest {
+
+ @Test
+ public void testLoadOpenNLPModel() throws Exception {
+ final ClassPathModel model =
getClassPathModel("opennlp-models-langdetect-*.jar");
+ assertNotNull(model);
+ assertNotNull(model.model());
+ assertNotNull(model.properties());
+
assertEquals("2ddf585fac2e02a9dcfb9a4a9cc9417562eaac351be2efb506a2eaa87f19e9d4",
+ model.getModelSHA256());
+ assertEquals("langdetect-183.bin", model.getModelName());
+ assertEquals("1.8.3", model.getModelVersion());
+ }
+
+}
diff --git
a/opennlp-tools-models/src/test/java/opennlp/tools/models/AbstractModelUsageTest.java
b/opennlp-tools-models/src/test/java/opennlp/tools/models/AbstractModelUsageTest.java
new file mode 100644
index 00000000..bab564d5
--- /dev/null
+++
b/opennlp-tools-models/src/test/java/opennlp/tools/models/AbstractModelUsageTest.java
@@ -0,0 +1,61 @@
+/*
+ * 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 opennlp.tools.models;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+
+import org.junit.jupiter.api.Test;
+
+import opennlp.tools.langdetect.LanguageDetector;
+import opennlp.tools.langdetect.LanguageDetectorME;
+import opennlp.tools.langdetect.LanguageDetectorModel;
+import opennlp.tools.sentdetect.SentenceDetector;
+import opennlp.tools.sentdetect.SentenceDetectorME;
+import opennlp.tools.sentdetect.SentenceModel;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+public abstract class AbstractModelUsageTest extends
AbstractClassPathModelTest {
+
+ @Test
+ public void testLanguageDetection() throws IOException {
+ final ClassPathModel model =
getClassPathModel("opennlp-models-langdetect-*.jar");
+ final LanguageDetectorModel ldModel = new LanguageDetectorModel(new
ByteArrayInputStream(model.model()));
+ assertNotNull(ldModel);
+ final LanguageDetector languageDetector = new LanguageDetectorME(ldModel);
+ assertNotNull(languageDetector);
+
+ assertEquals("eng",
+ languageDetector.predictLanguage("The English language is pretty
impressive.").getLang());
+
+ }
+
+ @Test
+ public void testSentenceDetector() throws IOException {
+ final ClassPathModel model =
getClassPathModel("opennlp-models-sentdetect-*.jar");
+ final SentenceModel sentenceModel = new SentenceModel(new
ByteArrayInputStream(model.model()));
+ assertNotNull(sentenceModel);
+ final SentenceDetector sentenceDetector = new
SentenceDetectorME(sentenceModel);
+ assertNotNull(sentenceDetector);
+
+ assertEquals(2, sentenceDetector.sentDetect("Pretty impressive stuff. I
like it!").length);
+
+ }
+
+}
diff --git
a/opennlp-tools-models/src/test/java/opennlp/tools/models/classgraph/ClassgraphModelFinderTest.java
b/opennlp-tools-models/src/test/java/opennlp/tools/models/classgraph/ClassgraphModelFinderTest.java
new file mode 100644
index 00000000..f5751f98
--- /dev/null
+++
b/opennlp-tools-models/src/test/java/opennlp/tools/models/classgraph/ClassgraphModelFinderTest.java
@@ -0,0 +1,33 @@
+/*
+ * 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 opennlp.tools.models.classgraph;
+
+import opennlp.tools.models.AbstractClassPathFinderTest;
+import opennlp.tools.models.ClassPathModelFinder;
+
+public class ClassgraphModelFinderTest extends AbstractClassPathFinderTest {
+
+ @Override
+ protected ClassPathModelFinder getModelFinder() {
+ return new ClassgraphModelFinder();
+ }
+
+ @Override
+ protected ClassgraphModelFinder getModelFinder(String pattern) {
+ return new ClassgraphModelFinder(pattern);
+ }
+}
diff --git
a/opennlp-tools-models/src/test/java/opennlp/tools/models/classgraph/ClassgraphModelLoaderTest.java
b/opennlp-tools-models/src/test/java/opennlp/tools/models/classgraph/ClassgraphModelLoaderTest.java
new file mode 100644
index 00000000..c7ef5308
--- /dev/null
+++
b/opennlp-tools-models/src/test/java/opennlp/tools/models/classgraph/ClassgraphModelLoaderTest.java
@@ -0,0 +1,33 @@
+/*
+ * 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 opennlp.tools.models.classgraph;
+
+import opennlp.tools.models.AbstractModelLoaderTest;
+import opennlp.tools.models.ClassPathModelFinder;
+
+public class ClassgraphModelLoaderTest extends AbstractModelLoaderTest {
+
+ @Override
+ protected ClassPathModelFinder getModelFinder() {
+ return new ClassgraphModelFinder();
+ }
+
+ @Override
+ protected ClassPathModelFinder getModelFinder(String pattern) {
+ return new ClassgraphModelFinder(pattern);
+ }
+}
diff --git
a/opennlp-tools-models/src/test/java/opennlp/tools/models/classgraph/ClassgraphModelUsageTest.java
b/opennlp-tools-models/src/test/java/opennlp/tools/models/classgraph/ClassgraphModelUsageTest.java
new file mode 100644
index 00000000..3ab61506
--- /dev/null
+++
b/opennlp-tools-models/src/test/java/opennlp/tools/models/classgraph/ClassgraphModelUsageTest.java
@@ -0,0 +1,33 @@
+/*
+ * 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 opennlp.tools.models.classgraph;
+
+import opennlp.tools.models.AbstractModelUsageTest;
+import opennlp.tools.models.ClassPathModelFinder;
+
+public class ClassgraphModelUsageTest extends AbstractModelUsageTest {
+
+ @Override
+ protected ClassPathModelFinder getModelFinder() {
+ return new ClassgraphModelFinder();
+ }
+
+ @Override
+ protected ClassPathModelFinder getModelFinder(String pattern) {
+ return new ClassgraphModelFinder(pattern);
+ }
+}
diff --git
a/opennlp-tools-models/src/test/java/opennlp/tools/models/simple/SimpleClassPathModelFinderTest.java
b/opennlp-tools-models/src/test/java/opennlp/tools/models/simple/SimpleClassPathModelFinderTest.java
new file mode 100644
index 00000000..faab41d7
--- /dev/null
+++
b/opennlp-tools-models/src/test/java/opennlp/tools/models/simple/SimpleClassPathModelFinderTest.java
@@ -0,0 +1,34 @@
+/*
+ * 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 opennlp.tools.models.simple;
+
+import opennlp.tools.models.AbstractClassPathFinderTest;
+import opennlp.tools.models.ClassPathModelFinder;
+
+public class SimpleClassPathModelFinderTest extends
AbstractClassPathFinderTest {
+
+
+ @Override
+ protected ClassPathModelFinder getModelFinder() {
+ return new SimpleClassPathModelFinder();
+ }
+
+ @Override
+ protected ClassPathModelFinder getModelFinder(String pattern) {
+ return new SimpleClassPathModelFinder(pattern);
+ }
+}
diff --git
a/opennlp-tools-models/src/test/java/opennlp/tools/models/simple/SimpleModelLoaderTest.java
b/opennlp-tools-models/src/test/java/opennlp/tools/models/simple/SimpleModelLoaderTest.java
new file mode 100644
index 00000000..83d7caf1
--- /dev/null
+++
b/opennlp-tools-models/src/test/java/opennlp/tools/models/simple/SimpleModelLoaderTest.java
@@ -0,0 +1,33 @@
+/*
+ * 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 opennlp.tools.models.simple;
+
+import opennlp.tools.models.AbstractModelLoaderTest;
+import opennlp.tools.models.ClassPathModelFinder;
+
+public class SimpleModelLoaderTest extends AbstractModelLoaderTest {
+
+ @Override
+ protected ClassPathModelFinder getModelFinder() {
+ return new SimpleClassPathModelFinder();
+ }
+
+ @Override
+ protected ClassPathModelFinder getModelFinder(String pattern) {
+ return new SimpleClassPathModelFinder(pattern);
+ }
+}
diff --git
a/opennlp-tools-models/src/test/java/opennlp/tools/models/simple/SimpleModelUsageTest.java
b/opennlp-tools-models/src/test/java/opennlp/tools/models/simple/SimpleModelUsageTest.java
new file mode 100644
index 00000000..65ea5a83
--- /dev/null
+++
b/opennlp-tools-models/src/test/java/opennlp/tools/models/simple/SimpleModelUsageTest.java
@@ -0,0 +1,33 @@
+/*
+ * 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 opennlp.tools.models.simple;
+
+import opennlp.tools.models.AbstractModelUsageTest;
+import opennlp.tools.models.ClassPathModelFinder;
+
+public class SimpleModelUsageTest extends AbstractModelUsageTest {
+
+ @Override
+ protected ClassPathModelFinder getModelFinder() {
+ return new SimpleClassPathModelFinder();
+ }
+
+ @Override
+ protected ClassPathModelFinder getModelFinder(String pattern) {
+ return new SimpleClassPathModelFinder(pattern);
+ }
+}
diff --git a/pom.xml b/pom.xml
index a406164e..4c8ae881 100644
--- a/pom.xml
+++ b/pom.xml
@@ -177,6 +177,8 @@
<slf4j.version>1.7.36</slf4j.version>
<log4j2.version>2.23.1</log4j2.version>
<jmh.version>1.37</jmh.version>
+ <classgraph.version>4.8.173</classgraph.version>
+ <opennlp.models.version>1.0.0-SNAPSHOT</opennlp.models.version>
<opennlp.forkCount>1.0C</opennlp.forkCount>
<coveralls.maven.plugin>4.3.0</coveralls.maven.plugin>
<jacoco.maven.plugin>0.8.11</jacoco.maven.plugin>
@@ -555,6 +557,7 @@
<module>opennlp-distr</module>
<module>opennlp-dl</module>
<module>opennlp-dl-gpu</module>
- </modules>
+ <module>opennlp-tools-models</module>
+ </modules>
</project>