This is an automated email from the ASF dual-hosted git repository. rec pushed a commit to branch feature/372-Allow-adding-URLs-to-the-datapath in repository https://gitbox.apache.org/repos/asf/uima-uimaj.git
commit 3907318d7920c7b9189f12d243f6b6329478caea Author: Richard Eckart de Castilho <[email protected]> AuthorDate: Wed Aug 14 18:33:03 2024 +0200 #372 - Allow adding URLs to the datapath - Added methods to set the datapath using URLs - Added support for URLs to the setDataPathElements(String...) method - Deprecated methods that return the datapath in a way that is not URLs - Added more unit tests - Cleaning up code a bit --- .../apache/uima/internal/util/UIMAClassLoader.java | 4 +- .../apache/uima/resource/RelativePathResolver.java | 71 +++++-- .../org/apache/uima/resource/ResourceManager.java | 95 ++++++---- .../impl/ConfigurableDataResource_impl.java | 22 +-- .../uima/resource/impl/DataResource_impl.java | 31 +-- .../resource/impl/RelativePathResolver_impl.java | 211 +++++++++++++++------ .../uima/resource/impl/ResourceManager_impl.java | 162 ++++------------ .../metadata/ResourceManagerConfiguration.java | 5 +- .../org/apache/uima/util/impl/Settings_impl.java | 2 +- .../impl/RelativePathResolver_implTest.java | 188 +++++++++++++----- 10 files changed, 487 insertions(+), 304 deletions(-) diff --git a/uimaj-core/src/main/java/org/apache/uima/internal/util/UIMAClassLoader.java b/uimaj-core/src/main/java/org/apache/uima/internal/util/UIMAClassLoader.java index 026351463..81b71cf59 100644 --- a/uimaj-core/src/main/java/org/apache/uima/internal/util/UIMAClassLoader.java +++ b/uimaj-core/src/main/java/org/apache/uima/internal/util/UIMAClassLoader.java @@ -90,11 +90,11 @@ public class UIMAClassLoader extends URLClassLoader { /** * Transforms the string classpath to a URL array based classpath. * - * The classpath string must be separated with the filesystem path separator. + * The classpath string must be separated with the file system path separator. * * @param classpath * a classpath string - * @return URL[] array of wellformed URL's + * @return URL[] array of well-formed URL's * @throws MalformedURLException * if a malformed URL has occurred in the classpath string. */ diff --git a/uimaj-core/src/main/java/org/apache/uima/resource/RelativePathResolver.java b/uimaj-core/src/main/java/org/apache/uima/resource/RelativePathResolver.java index b6c925dac..fde854326 100644 --- a/uimaj-core/src/main/java/org/apache/uima/resource/RelativePathResolver.java +++ b/uimaj-core/src/main/java/org/apache/uima/resource/RelativePathResolver.java @@ -26,8 +26,6 @@ import java.util.List; /** * Used by the resource manager to resolve relative URLs to absolute URLs. - * - * */ public interface RelativePathResolver { @@ -37,21 +35,39 @@ public interface RelativePathResolver { * Gets the data path used to resolve relative paths. More than one directory may be specified by * separating them with the System <code>path.separator</code> character (; on windows, : on * UNIX). Elements of this path may be absolute or relative file paths. + * <p> + * <b>Note:</b> This method will only return file paths. If any non-file URLs have been added to + * the data path e.g via {@link #setDataPathElements(URL...)}, these will not be included. Use + * {@link #getDataPathUrls()} to get a full list. * * @return the data path * @deprecated Use {@link #getDataPathElements} instead. */ - @Deprecated + @Deprecated(since = "3.3.0") String getDataPath(); /** * Gets the data path used to resolve relative paths. Elements of this path may be absolute or * relative file paths. + * <p> + * <b>Note:</b> This method will only return file paths. If any non-file URLs have been added to + * the data path e.g via {@link #setDataPathElements(URL...)}, these will not be included. Use + * {@link #getDataPathUrls()} to get a full list. * * @return the data path + * @deprecated Use {@link #getDataPathUrls()} instead. */ + @Deprecated(since = "3.6.0") List<String> getDataPathElements(); + /** + * Gets the data path used to resolve relative paths. Elements of this path may be absolute or + * relative URLs. + * + * @return the data path + */ + List<URL> getDataPathUrls(); + /** * Sets the data path used to resolve relative paths. More than one directory may be specified by * separating them with the System <code>path.separator</code> character (; on windows, : on @@ -64,12 +80,12 @@ public interface RelativePathResolver { * if a file path could not be converted to a URL * @deprecated Use {@link #setDataPathElements} instead. */ - @Deprecated + @Deprecated(since = "3.3.0") void setDataPath(String aPath) throws MalformedURLException; /** - * Sets the data path elements used to resolve relative paths. Elements of this path may be - * absolute or relative file paths. + * Sets the data path elements used to resolve relative paths. Elements of this path may be URLs + * or absolute or relative file paths. * * @param aElements * the data path elements @@ -92,19 +108,48 @@ public interface RelativePathResolver { void setDataPathElements(File... aElements) throws MalformedURLException; /** - * Resolves a relative URL to an absolute URL. This will attempt to resolve the URL relative to - * each element of the data path, sequentially starting with the first element. If this results in - * an absolute URL at which a file actually exists, that absolute URL is returned. If no file - * could be found, <code>null</code> is returned. + * Sets the data path elements used to resolve relative paths. Elements of this path may be + * absolute or relative URLs. + * + * @param aURLs + * the data path aURLs + */ + void setDataPathElements(URL... aURLs); + + /** + * Resolves an URLrelative to each element of the data path, sequentially starting with the first + * element. If this results in an absolute URL at which a file actually exists, that absolute URL + * is returned. If no file could be found, <code>null</code> is returned. + * + * @param aUrl + * the URL to be resolved (if an absolute URL is specified, it will be returned + * unmodified if a file actually exists at the URL; otherwise <code>null</code> will be + * returned). + * + * @return the absolute URL at which the file exists, <code>null</code> it none could be found. + * @deprecated Use {@link #resolveRelativePath(String)} instead. + */ + @Deprecated + URL resolveRelativePath(URL aUrl); + + /** + * Resolves a path relative to each element of the data path, sequentially starting with the first + * element. If this results in an absolute URL at which a file actually exists, that absolute URL + * is returned. If no file could be found, <code>null</code> is returned. + * <p> + * <b>Note:</b> For backwards compatibility, it is still allowed to specify relative URLs here + * such as {@code file:foo/foo.txt} and this will effectively work as if {@code foo/foo.txt} had + * been specified. The protocol is simply discarded. Future versions will no longer accept a + * protocol in relative paths. * - * @param aRelativeUrl - * the relative URL to be resolved (if an absolute URL is specified, it will be returned + * @param aPathOrUrl + * the path/URL to be resolved (if an absolute URL is specified, it will be returned * unmodified if a file actually exists at the URL; otherwise <code>null</code> will be * returned). * * @return the absolute URL at which the file exists, <code>null</code> it none could be found. */ - URL resolveRelativePath(URL aRelativeUrl); + URL resolveRelativePath(String aPathOrUrl); /** * Sets the ClassLoader that should be used to resolve the resources. diff --git a/uimaj-core/src/main/java/org/apache/uima/resource/ResourceManager.java b/uimaj-core/src/main/java/org/apache/uima/resource/ResourceManager.java index e59ed195f..950d03e9b 100644 --- a/uimaj-core/src/main/java/org/apache/uima/resource/ResourceManager.java +++ b/uimaj-core/src/main/java/org/apache/uima/resource/ResourceManager.java @@ -33,8 +33,6 @@ import org.apache.uima.util.XMLizable; /** * A <code>ResourceManager</code> holds a collection of {@link org.apache.uima.resource.Resource} * objects, each registered under a specified key. - * - * */ public interface ResourceManager { @@ -42,21 +40,38 @@ public interface ResourceManager { * Gets the data path used to resolve relative paths. More than one directory may be specified by * separating them with the System <code>path.separator</code> character (; on windows, : on * UNIX). + * <p> + * <b>Note:</b> This method will only return file paths. If any non-file URLs have been added to + * the data path e.g via {@link #setDataPathUrls(URL...)}, these will not be included. Use + * {@link #getDataPathUrls()} to get a full list. * * @return the data path * * @deprecated Use {@link #getDataPathElements()} instead. */ - @Deprecated + @Deprecated(since = "3.3.0") String getDataPath(); /** * Gets the data path elements used to resolve relative paths. - * + * <p> + * <b>Note:</b> This method will only return file paths. If any non-file URLs have been added to + * the data path e.g via {@link #setDataPathUrls(URL...)}, these will not be included. Use + * {@link #getDataPathUrls()} to get a full list. + * * @return the data path elements + * @deprecated Use {@link #getDataPathUrls()} */ + @Deprecated(since = "3.6.0") List<String> getDataPathElements(); + /** + * Gets the data path URLs used to resolve relative paths. + * + * @return the data path elements + */ + List<URL> getDataPathUrls(); + /** * Sets the data path used to resolve relative paths. More than one directory may be specified by * separating them with the System <code>path.separator</code> character (; on windows, : on @@ -69,18 +84,18 @@ public interface ResourceManager { * if an element of the path is neither a valid URL or a valid file path * @deprecated Use {@link #setDataPathElements} instead. */ - @Deprecated + @Deprecated(since = "3.3.0") void setDataPath(String aPath) throws MalformedURLException; /** - * Sets the data path elements used to resolve relative paths. Elements of this path may be - * absolute or relative file paths. + * Sets the data path elements used to resolve relative paths. Elements of this path may be URLs + * or absolute or relative file paths. * * @param aElements - * the data path + * the data path elements * * @throws MalformedURLException - * if an element of the path is neither a valid URL or a valid file path + * if a file path could not be converted to a URL */ void setDataPathElements(String... aElements) throws MalformedURLException; @@ -96,6 +111,15 @@ public interface ResourceManager { */ void setDataPathElements(File... aElements) throws MalformedURLException; + /** + * Sets the data path elements used to resolve relative paths. Elements of this path may be + * absolute or relative URLs. + * + * @param aUrls + * the data path aURLs + */ + void setDataPathUrls(URL... aUrls); + /** * Attempts to resolve a relative path to an absolute path using the same mechanism that the * ResourceManager uses to find resources -- a lookup in the datapath followed by a lookup in the @@ -130,23 +154,23 @@ public interface ResourceManager { */ Object getResource(String aName) throws ResourceAccessException; -//@formatter:off /** * Returns one of two kinds of objects (or null): - * - an instance of the implementation object for a resource, that has - * been loaded with a DataResource resource produced by the resource given the aParms - * - * - (if there is no implementation defined for this resource) - * returns an instance of the DataResource, itself, produced by the resource given the aParms - * - * An example of a parameterized Resource is a - * dictionary whose data depend on a specified language identifier. - * - * If the implementation object class exists, but no instance has been - * created (yet) for the particular data resource corresponding to the parameters, - * then this method will create and register a new instance and call its - * load() api using the data resource corresponding to the parameters, and - * return that. + * <ul> + * <li>an instance of the implementation object for a resource, that has been loaded with a + * DataResource resource produced by the resource given the aParms + * + * <li>(if there is no implementation defined for this resource) returns an instance of the + * DataResource, itself, produced by the resource given the aParms + * </ul> + * <p> + * An example of a parameterized Resource is a dictionary whose data depend on a specified + * language identifier. + * <p> + * If the implementation object class exists, but no instance has been created (yet) for the + * particular data resource corresponding to the parameters, then this method will create and + * register a new instance and call its load() api using the data resource corresponding to the + * parameters, and return that. * * @param aName * the name of the parameterized resource to retrieve @@ -171,7 +195,6 @@ public interface ResourceManager { * if there is a resource registered under <code>aName</code> but it could not be * instantiated for the specified parameters. */ -//@formatter:on Object getResource(String aName, String[] aParams) throws ResourceAccessException; /** @@ -308,20 +331,20 @@ public interface ResourceManager { String aQualifiedContextName, Map<String, Object> aAdditionalParams) throws ResourceInitializationException; -//@formatter:off /** * Resolves a component's external resource dependencies (bindings) using this resource manager. - * + * <p> * The default implementation has special defaulting logic: + * <p> + * If a binding specifies a non-existing resource, an attempt is made to interpret the key as a + * file name, looked up using the current context for relative path resolution. + * <ul> + * <li>If successfully found, a FileResourceSpecifier is created using the file and used as the + * implementing class. * - * If a binding specifies a non-existing resource, - * an attempt is made to interpret the key as a file name, looked up - * using the current context for relative path resolution. - * - If successfully found, a FileResourceSpecifier is created using the file - * and used as the implementing class. - * - * If no resource can be found at all, then unless the dependency is marked "optional", an + * <li>If no resource can be found at all, then unless the dependency is marked "optional", an * ResourceInitializationException is thrown. + * </ul> * * Multi-threading: may be called on multiple threads, repeatedly for the same set of resources. * Implementations should recognize this and skip repeated resolutions. @@ -335,7 +358,6 @@ public interface ResourceManager { * @throws ResourceInitializationException * if a required dependency is not satisfied */ -//@formatter:on void resolveAndValidateResourceDependencies(ExternalResourceDependency[] aDependencies, String aQualifiedContextName) throws ResourceInitializationException; @@ -423,7 +445,7 @@ public interface ResourceManager { * @return A map from absolute URL to the XMLizable object that was parsed from that URL * @deprecated Intended just for internal use. */ - @Deprecated + @Deprecated(since = "3.3.0") Map<String, XMLizable> getImportCache(); /** @@ -465,7 +487,6 @@ public interface ResourceManager { void destroy(); /** - * * @return a List of External Shared Resource instances instantiated by this Resource Manager. For * parameterized resources, those which have been asked for (having unique parameter sets) * are included. diff --git a/uimaj-core/src/main/java/org/apache/uima/resource/impl/ConfigurableDataResource_impl.java b/uimaj-core/src/main/java/org/apache/uima/resource/impl/ConfigurableDataResource_impl.java index c88e88e1a..15c3d7432 100644 --- a/uimaj-core/src/main/java/org/apache/uima/resource/impl/ConfigurableDataResource_impl.java +++ b/uimaj-core/src/main/java/org/apache/uima/resource/impl/ConfigurableDataResource_impl.java @@ -94,13 +94,8 @@ public class ConfigurableDataResource_impl extends Resource_ImplBase implements relPathResolver = new RelativePathResolver_impl(); } - // Get the file URL, resolving relative path as necessary - try { - mFileUrl = relPathResolver.resolveRelativePath(new URL(mUri.toString())); - } catch (IOException e) { - // this is OK. The URI may not be a valid URL (e.g. it may use a non-standard protocol). - // in this case getUrl returns null but getUri can still be used to access the URI - } + mFileUrl = relPathResolver.resolveRelativePath(mUri.toString()); + return true; } @@ -153,18 +148,22 @@ public class ConfigurableDataResource_impl extends Resource_ImplBase implements @Override public boolean equals(Object obj) { // obj must be a DataResource_impl - if (!(obj instanceof ConfigurableDataResource_impl)) + if (!(obj instanceof ConfigurableDataResource_impl)) { return false; + } // URIs must be the same URI uri = ((ConfigurableDataResource_impl) obj).getUri(); - if (uri == null || !uri.equals(getUri())) + if (uri == null || !uri.equals(getUri())) { return false; + } // Local Cache Files must be the same File localCache = ((ConfigurableDataResource_impl) obj).getLocalCache(); - if ((localCache == null && getLocalCache() != null) || (localCache != null && !localCache.equals(getLocalCache()))) + if ((localCache == null && getLocalCache() != null) + || (localCache != null && !localCache.equals(getLocalCache()))) { return false; + } return true; } @@ -176,8 +175,9 @@ public class ConfigurableDataResource_impl extends Resource_ImplBase implements public int hashCode() { // add hash codes of member variables int hashCode = 0; - if (mUri != null) + if (mUri != null) { hashCode += mUri.hashCode(); + } return hashCode; } diff --git a/uimaj-core/src/main/java/org/apache/uima/resource/impl/DataResource_impl.java b/uimaj-core/src/main/java/org/apache/uima/resource/impl/DataResource_impl.java index b2ada38da..608f7661a 100644 --- a/uimaj-core/src/main/java/org/apache/uima/resource/impl/DataResource_impl.java +++ b/uimaj-core/src/main/java/org/apache/uima/resource/impl/DataResource_impl.java @@ -70,8 +70,9 @@ public class DataResource_impl extends Resource_ImplBase implements DataResource public boolean initialize(ResourceSpecifier aSpecifier, Map<String, Object> aAdditionalParams) throws ResourceInitializationException { // aSpecifier must be a FileResourceSpecifier - if (!(aSpecifier instanceof FileResourceSpecifier)) + if (!(aSpecifier instanceof FileResourceSpecifier)) { return false; + } // If we get here, aSpecifier is supported by this implementation. FileResourceSpecifier spec = (FileResourceSpecifier) aSpecifier; @@ -85,22 +86,22 @@ public class DataResource_impl extends Resource_ImplBase implements DataResource // Get the file URL from the specifier. If the user has passed a file path // (e.g. c:\Program Files\...) instead of a URL, be lenient and convert it to // a URL - URL relativeUrl; + String relativeUrl; try { - relativeUrl = new URL(spec.getFileUrl()); + relativeUrl = new URL(spec.getFileUrl()).toString(); } catch (MalformedURLException e) { // try to treat the URL as a file name. - File file = new File(spec.getFileUrl()); + var file = new File(spec.getFileUrl()); if (file.isAbsolute()) { // for absolute paths, use File.toURL(), which handles // windows absolute paths correctly - relativeUrl = file.toURL(); + relativeUrl = file.toURL().toString(); } else { // for relative paths, we can' use File.toURL() because it always // produces an absolute URL. Instead we do the following, which // won't work for windows absolute paths (but that's OK, since we // know we're working with a relative path) - relativeUrl = new URL("file", "", spec.getFileUrl()); + relativeUrl = spec.getFileUrl(); } } @@ -176,18 +177,22 @@ public class DataResource_impl extends Resource_ImplBase implements DataResource @Override public boolean equals(Object obj) { // obj must be a DataResource_impl - if (!(obj instanceof DataResource_impl)) + if (!(obj instanceof DataResource_impl)) { return false; + } // URLs must be the same (but don't use URL.equals(), which does DNS resolution!) URL url = ((DataResource_impl) obj).getUrl(); - if (url == null || !url.toString().equals(getUrl().toString())) + if (url == null || !url.toString().equals(getUrl().toString())) { return false; + } // Local Cache Files must be the same File localCache = ((DataResource_impl) obj).getLocalCache(); - if ((localCache == null && getLocalCache() != null) || (localCache != null && !localCache.equals(getLocalCache()))) + if ((localCache == null && getLocalCache() != null) + || (localCache != null && !localCache.equals(getLocalCache()))) { return false; + } return true; } @@ -199,11 +204,13 @@ public class DataResource_impl extends Resource_ImplBase implements DataResource public int hashCode() { // add hash codes of member variables int hashCode = 0; - if (mFileUrl != null) + if (mFileUrl != null) { hashCode += mFileUrl.toString().hashCode(); // don't use URL.hashCode(), which does DNS - // resolution - if (mLocalCache != null) + } + // resolution + if (mLocalCache != null) { hashCode += mLocalCache.hashCode(); + } return hashCode; } diff --git a/uimaj-core/src/main/java/org/apache/uima/resource/impl/RelativePathResolver_impl.java b/uimaj-core/src/main/java/org/apache/uima/resource/impl/RelativePathResolver_impl.java index 098a9d4b4..0127e832d 100644 --- a/uimaj-core/src/main/java/org/apache/uima/resource/impl/RelativePathResolver_impl.java +++ b/uimaj-core/src/main/java/org/apache/uima/resource/impl/RelativePathResolver_impl.java @@ -19,23 +19,24 @@ package org.apache.uima.resource.impl; +import static java.nio.charset.StandardCharsets.UTF_8; +import static java.util.Arrays.asList; +import static java.util.Arrays.stream; import static java.util.Collections.emptyList; import static java.util.Collections.unmodifiableList; import static java.util.stream.Collectors.joining; -import static java.util.stream.Collectors.toList; import java.io.File; import java.io.IOException; -import java.io.InputStream; +import java.lang.invoke.MethodHandles; import java.net.MalformedURLException; import java.net.URL; +import java.net.URLDecoder; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.StringTokenizer; import org.apache.uima.resource.RelativePathResolver; -import org.apache.uima.util.impl.Constants; /** * Reference implementation of {@link RelativePathResolver}. @@ -43,18 +44,17 @@ import org.apache.uima.util.impl.Constants; public class RelativePathResolver_impl implements RelativePathResolver { /** Data path as a string. */ + @Deprecated(since = "3.6.0") private List<String> mDataPath; /** Array of base URLs parsed from the data path. */ - private URL[] mBaseUrls; + private List<URL> mBaseUrls; /** ClassLoader to fall back on if resource not in data path. */ private ClassLoader mClassLoader; public RelativePathResolver_impl() { - this(null); - mClassLoader = getClass().getClassLoader(); // default value, maybe overridden by - // setPathResolverClassLoader + this(MethodHandles.lookup().lookupClass().getClassLoader()); } public RelativePathResolver_impl(ClassLoader aClassLoader) { @@ -84,95 +84,199 @@ public class RelativePathResolver_impl implements RelativePathResolver { setDataPath(dataPath); } catch (MalformedURLException e) { // initialize to empty path - mDataPath = emptyList(); - mBaseUrls = Constants.EMPTY_URL_ARRAY; + mDataPath = null; + mBaseUrls = null; } + mClassLoader = aClassLoader; } @Override @Deprecated public String getDataPath() { - String pathSepChar = System.getProperty("path.separator"); + if (mDataPath == null) { + return ""; + } + + var pathSepChar = System.getProperty("path.separator"); return mDataPath.stream().collect(joining(pathSepChar)); } + @Deprecated @Override public List<String> getDataPathElements() { - return mDataPath; + if (mDataPath == null) { + return emptyList(); + } + + return unmodifiableList(mDataPath); } @Override - public void setDataPathElements(File... aPaths) throws MalformedURLException { - if (aPaths == null) { - mDataPath = emptyList(); - mBaseUrls = Constants.EMPTY_URL_ARRAY; + public List<URL> getDataPathUrls() { + if (mBaseUrls == null) { + return emptyList(); + } + + return unmodifiableList(mBaseUrls); + } + + @SuppressWarnings("deprecation") + @Override + public void setDataPathElements(File... aElements) throws MalformedURLException { + if (aElements == null) { + mDataPath = null; + mBaseUrls = null; return; } - mDataPath = unmodifiableList(Arrays.stream(aPaths) // - .map(File::getPath) // - .map(s -> s.replace(File.separator, "/")) // - .collect(toList())); - mBaseUrls = new URL[aPaths.length]; - for (int i = 0; i < aPaths.length; i++) { + var baseUrls = new ArrayList<URL>(aElements.length); + for (var path : aElements) { // Note, this URL can contain space characters if there were spaces in the // datapath. This may not be ideal but we're keeping that behavior for // backwards compatibility. Some components relied on this (e.g. by calling // URL.getFile() and expecting it to be a valid file name). - mBaseUrls[i] = aPaths[i].toURL(); + baseUrls.add(path.toURL()); } + + mDataPath = stream(aElements) // + .map(File::getPath) // + .map(s -> s.replace(File.separator, "/")) // + .toList(); + mBaseUrls = baseUrls; } + @SuppressWarnings("deprecation") @Override - public void setDataPathElements(String... aPaths) throws MalformedURLException { - if (aPaths == null) { + public void setDataPathElements(String... aElements) throws MalformedURLException { + if (aElements == null) { mDataPath = null; mBaseUrls = null; return; } - mDataPath = unmodifiableList(Arrays.stream(aPaths).collect(toList())); - mBaseUrls = new URL[aPaths.length]; - for (int i = 0; i < aPaths.length; i++) { - // Note, this URL can contain space characters if there were spaces in the - // datapath. This may not be ideal but we're keeping that behavior for - // backwards compatibility. Some components relied on this (e.g. by calling - // URL.getFile() and expecting it to be a valid file name). - mBaseUrls[i] = new File(aPaths[i]).toURL(); + var dataPath = new ArrayList<String>(aElements.length); + + var baseUrls = new ArrayList<URL>(aElements.length); + for (var element : aElements) { + try { + var url = new URL(element); + baseUrls.add(url); + var protocol = url.getProtocol(); + if ((protocol != null) && protocol.equalsIgnoreCase("file")) { + dataPath.add(new File(URLDecoder.decode(url.getPath(), UTF_8)).getPath()); + } + } catch (MalformedURLException e) { + // Note, this URL can contain space characters if there were spaces in the + // datapath. This may not be ideal but we're keeping that behavior for + // backwards compatibility. Some components relied on this (e.g. by calling + // URL.getFile() and expecting it to be a valid file name). + baseUrls.add(new File(element).toURL()); + dataPath.add(element); + } + } + + mDataPath = dataPath; + mBaseUrls = baseUrls; + } + + @Override + public void setDataPathElements(URL... aElements) { + if (aElements == null) { + mDataPath = null; + mBaseUrls = null; + return; + } + + var dataPath = new ArrayList<String>(aElements.length); + for (var url : aElements) { + var protocol = url.getProtocol(); + if ((protocol == null) || !protocol.equalsIgnoreCase("file")) { + continue; + } + dataPath.add(new File(URLDecoder.decode(url.getPath(), UTF_8)).getPath()); } + + mDataPath = dataPath; + mBaseUrls = asList(aElements); } @Override @Deprecated public void setDataPath(String aPath) throws MalformedURLException { - List<URL> urls = new ArrayList<>(); - List<String> paths = new ArrayList<>(); + var urls = new ArrayList<URL>(); + var paths = new ArrayList<String>(); // tokenize based on path.separator system property - String pathSepChar = System.getProperty("path.separator"); - StringTokenizer tokenizer = new StringTokenizer(aPath, pathSepChar); + var pathSepChar = System.getProperty("path.separator"); + var tokenizer = new StringTokenizer(aPath, pathSepChar); while (tokenizer.hasMoreTokens()) { - String tok = tokenizer.nextToken(); + var tok = tokenizer.nextToken(); paths.add(tok); - URL url = new File(tok).toURL(); - urls.add(url); // Note, this URL can contain space characters if there were spaces in the // datapath. This may not be ideal but we're keeping that behavior for // backwards compatibility. Some components relied on this (e.g. by calling // URL.getFile() and expecting it to be a valid file name). + urls.add(new File(tok).toURL()); + } + + mDataPath = paths; + mBaseUrls = urls; + } + + @Override + public URL resolveRelativePath(String aPathOrUrl) { + // check if an URL was passed in - if so, we fall back to the old logic which is a bit odd + // because for relative URLs, it basically discards the protocol. This is behavior we may + // want to change on the next major release... e.g. to require that relative paths are + // always specified without a protocol. + try { + var url = new URL(aPathOrUrl); + return resolveRelativePath(url); + } catch (MalformedURLException e) { + // ignore and move on + } + + // try each base URL + for (var baseUrl : mBaseUrls) { + try { + var absUrl = new URL(baseUrl, aPathOrUrl); + // if file exists here, return this URL + if (fileExistsAtUrl(absUrl)) { + return absUrl; + } + } catch (MalformedURLException e) { + // ignore and move on to next base URL + } + } + + // fallback on classloader + URL absURL = null; + if (mClassLoader != null) { + absURL = mClassLoader.getResource(aPathOrUrl); } - mBaseUrls = urls.toArray(new URL[urls.size()]); - mDataPath = unmodifiableList(paths); + + // fallback on TCCL + if (absURL == null) { + var tccl = Thread.currentThread().getContextClassLoader(); + absURL = tccl.getResource(aPathOrUrl); + } + + // if no ClassLoader specified (could be the bootstrap classloader), try the system classloader + if (absURL == null && mClassLoader == null) { + absURL = ClassLoader.getSystemClassLoader().getResource(aPathOrUrl); + } + + return absURL; } + @Deprecated @Override - public URL resolveRelativePath(URL aRelativeUrl) { + public URL resolveRelativePath(URL aUrl) { // try each base URL - URL[] baseUrls = getBaseUrls(); - for (int i = 0; i < baseUrls.length; i++) { + for (var baseUrl : mBaseUrls) { try { - URL absUrl = new URL(baseUrls[i], aRelativeUrl.toString()); + var absUrl = new URL(baseUrl, aUrl.toString()); // if file exists here, return this URL if (fileExistsAtUrl(absUrl)) { return absUrl; @@ -183,12 +287,12 @@ public class RelativePathResolver_impl implements RelativePathResolver { } // check if an absolute URL was passed in - if (aRelativeUrl.getPath().startsWith("/") && fileExistsAtUrl(aRelativeUrl)) { - return aRelativeUrl; + if (aUrl.getPath().startsWith("/") && fileExistsAtUrl(aUrl)) { + return aUrl; } // fallback on classloader - String f = aRelativeUrl.getFile(); + var f = aUrl.getFile(); URL absURL = null; if (mClassLoader != null) { absURL = mClassLoader.getResource(f); @@ -196,7 +300,7 @@ public class RelativePathResolver_impl implements RelativePathResolver { // fallback on TCCL if (absURL == null) { - ClassLoader tccl = Thread.currentThread().getContextClassLoader(); + var tccl = Thread.currentThread().getContextClassLoader(); absURL = tccl.getResource(f); } @@ -213,7 +317,6 @@ public class RelativePathResolver_impl implements RelativePathResolver { */ @Override public void setPathResolverClassLoader(ClassLoader aClassLoader) { - // set ClassLoader mClassLoader = aClassLoader; } @@ -221,7 +324,7 @@ public class RelativePathResolver_impl implements RelativePathResolver { * Utility method that checks to see if a file exists at the specified URL. */ protected boolean fileExistsAtUrl(URL aUrl) { - try (InputStream testStream = aUrl.openStream()) { + try (var testStream = aUrl.openStream()) { return true; } catch (IOException e) { return false; @@ -230,8 +333,10 @@ public class RelativePathResolver_impl implements RelativePathResolver { /** * @return the base URLs that were parsed from the data path. + * @deprecated Use {@link #getDataPathUrls()} instead. */ + @Deprecated protected URL[] getBaseUrls() { - return mBaseUrls; + return mBaseUrls.toArray(URL[]::new); } } diff --git a/uimaj-core/src/main/java/org/apache/uima/resource/impl/ResourceManager_impl.java b/uimaj-core/src/main/java/org/apache/uima/resource/impl/ResourceManager_impl.java index 3a07103b7..0b7dca33d 100644 --- a/uimaj-core/src/main/java/org/apache/uima/resource/impl/ResourceManager_impl.java +++ b/uimaj-core/src/main/java/org/apache/uima/resource/impl/ResourceManager_impl.java @@ -46,7 +46,6 @@ import org.apache.uima.resource.CasManager; import org.apache.uima.resource.DataResource; import org.apache.uima.resource.ExternalResourceDependency; import org.apache.uima.resource.ExternalResourceDescription; -import org.apache.uima.resource.FileResourceSpecifier; import org.apache.uima.resource.ParameterizedDataResource; import org.apache.uima.resource.RelativePathResolver; import org.apache.uima.resource.Resource; @@ -62,28 +61,25 @@ import org.apache.uima.util.XMLizable; /** * Reference implementation of {@link org.apache.uima.resource.ResourceManager}. - * - * */ public class ResourceManager_impl implements ResourceManager { private static final AtomicInteger IMPORT_URL_CACHE_WARNING_THROTTLE = new AtomicInteger(); - // @formatter:off /** * Ties an External Resource instance to - * - its description - * -- name - * -- textual description - * -- a ResourceSpecifier describing how to create it - * -- (optional) the String name of the Java class that implements the resource) - * - its defining UIMA Context - * - * These are used to validate multiple declarations, and to get - * a resource to tie it to a binding - */ - // @formatter:on - static protected class ResourceRegistration { // make protected - // https://issues.apache.org/jira/browse/UIMA-2102 + * <ul> + * <li>its description + * <ul> + * <li>name + * <li>textual description + * <li>a ResourceSpecifier describing how to create it + * <li>(optional) the String name of the Java class that implements the resource) + * </ul> + * <li>its defining UIMA Context + * </ul> + * These are used to validate multiple declarations, and to get a resource to tie it to a binding + */ + static protected class ResourceRegistration { /** * For ParameterizedDataResources or DataResources, is the implementation object, which is an * arbitrary Java class implementing SharedDataResource (which has the "load" method) @@ -97,11 +93,11 @@ public class ResourceManager_impl implements ResourceManager { String definingContext; - public ResourceRegistration(Object resourceOrImplementation, - ExternalResourceDescription description, String definingContext) { - resource = resourceOrImplementation; - this.description = description; - this.definingContext = definingContext; + public ResourceRegistration(Object aResource, ExternalResourceDescription aDescription, + String aDefiningContext) { + resource = aResource; + description = aDescription; + definingContext = aDefiningContext; } } @@ -279,8 +275,7 @@ public class ResourceManager_impl implements ResourceManager { public ResourceManager_impl copy() { ResourceManager_impl rm = new ResourceManager_impl(mResourceMap, mInternalResourceRegistrationMap, mParameterizedResourceImplClassMap, - mInternalParameterizedResourceImplClassMap, - mParameterizedResourceInstanceMap); + mInternalParameterizedResourceImplClassMap, mParameterizedResourceInstanceMap); // non-final fields init rm.uimaCL = uimaCL; rm.importCache = importCache; @@ -307,12 +302,6 @@ public class ResourceManager_impl implements ResourceManager { } } - /** - * - * /** - * - * @see org.apache.uima.resource.ResourceManager#setExtensionClassPath(java.lang.String, boolean) - */ @Override public synchronized void setExtensionClassPath(String classpath, boolean resolveResource) throws MalformedURLException { @@ -325,10 +314,6 @@ public class ResourceManager_impl implements ResourceManager { } } - /** - * @see org.apache.uima.resource.ResourceManager#setExtensionClassPath(ClassLoader,java.lang.String, - * boolean) - */ @Override public synchronized void setExtensionClassPath(ClassLoader parent, String classpath, boolean resolveResource) throws MalformedURLException { @@ -354,30 +339,29 @@ public class ResourceManager_impl implements ResourceManager { } } - /** - * @see org.apache.uima.resource.ResourceManager#getExtensionClassLoader() - */ @Override public ClassLoader getExtensionClassLoader() { return uimaCL; } - /** - * @see org.apache.uima.resource.ResourceManager#getDataPath() - */ + @Deprecated(since = "3.3.0") @Override public String getDataPath() { return getRelativePathResolver().getDataPath(); } + @Deprecated(since = "3.6.0") @Override public List<String> getDataPathElements() { return getRelativePathResolver().getDataPathElements(); } - /** - * @see org.apache.uima.resource.ResourceManager#setDataPath(String) - */ + @Override + public List<URL> getDataPathUrls() { + return getRelativePathResolver().getDataPathUrls(); + } + + @Deprecated(since = "3.6.0") @Override public void setDataPath(String aPath) throws MalformedURLException { getRelativePathResolver().setDataPath(aPath); @@ -393,20 +377,14 @@ public class ResourceManager_impl implements ResourceManager { getRelativePathResolver().setDataPathElements(aElements); } - /* - * (non-Javadoc) - * - * @see org.apache.uima.resource.ResourceManager#resolveRelativePath(java.lang.String) - */ + @Override + public void setDataPathUrls(URL... aUrls) { + getRelativePathResolver().setDataPathElements(aUrls); + } + @Override public URL resolveRelativePath(String aRelativePath) throws MalformedURLException { - URL relativeUrl; - try { - relativeUrl = new URL(aRelativePath); - } catch (MalformedURLException e) { - relativeUrl = new URL("file", "", aRelativePath); - } - return getRelativePathResolver().resolveRelativePath(relativeUrl); + return getRelativePathResolver().resolveRelativePath(aRelativePath); } private void checkDestroyed() { @@ -415,9 +393,6 @@ public class ResourceManager_impl implements ResourceManager { } } - /** - * @see org.apache.uima.resource.ResourceManager#getResource(String) - */ @Override public Object getResource(String aName) throws ResourceAccessException { checkDestroyed(); @@ -430,9 +405,6 @@ public class ResourceManager_impl implements ResourceManager { return r; } - /** - * @see org.apache.uima.resource.ResourceManager#getResource(java.lang.String, java.lang.String[]) - */ @Override public Object getResource(String aName, String[] aParams) throws ResourceAccessException { // @formatter:off @@ -503,9 +475,6 @@ public class ResourceManager_impl implements ResourceManager { } } - /** - * @see org.apache.uima.resource.ResourceManager#getResourceClass(java.lang.String) - */ @Override @SuppressWarnings("unchecked") public Class<?> getResourceClass(String aName) { @@ -531,23 +500,12 @@ public class ResourceManager_impl implements ResourceManager { } } - /* - * (non-Javadoc) - * - * @see org.apache.uima.resource.ResourceManager#getResourceAsStream(java.lang.String, - * java.lang.String[]) - */ @Override public InputStream getResourceAsStream(String aKey, String[] aParams) throws ResourceAccessException { return getResourceAsStreamCommon(getResource(aKey, aParams)); } - /* - * (non-Javadoc) - * - * @see org.apache.uima.resource.ResourceManager#getResourceAsStream(java.lang.String) - */ @Override public InputStream getResourceAsStream(String aKey) throws ResourceAccessException { return getResourceAsStreamCommon(getResource(aKey)); @@ -574,22 +532,11 @@ public class ResourceManager_impl implements ResourceManager { } } - /* - * (non-Javadoc) - * - * @see org.apache.uima.resource.ResourceManager#getResourceURL(java.lang.String, - * java.lang.String[]) - */ @Override public URL getResourceURL(String aKey, String[] aParams) throws ResourceAccessException { return getResourceAsStreamCommonUrl(getResource(aKey, aParams)); } - /* - * (non-Javadoc) - * - * @see org.apache.uima.resource.ResourceManager#getResourceURL(java.lang.String) - */ @Override public URL getResourceURL(String aKey) throws ResourceAccessException { return getResourceAsStreamCommonUrl(getResource(aKey)); @@ -697,22 +644,16 @@ public class ResourceManager_impl implements ResourceManager { for (int i = 0; i < aDependencies.length; i++) { // get resource String qname = aQualifiedContextName + aDependencies[i].getKey(); - Object resourceImpl = mResourceMap.get(qname); // may or may not implement Resource, may - // implement SharedResourceObject + // may or may not implement Resource, may implement SharedResourceObject + Object resourceImpl = mResourceMap.get(qname); if (resourceImpl == null) { - // no resource found - // try to look up in classpath/datapath - URL relativeUrl; - try { - relativeUrl = new URL("file", "", aDependencies[i].getKey()); - } catch (MalformedURLException e) { - throw new ResourceInitializationException(e); - } - URL absUrl = getRelativePathResolver().resolveRelativePath(relativeUrl); + // no resource found - try to look up in classpath/datapath + var relativeUrl = aDependencies[i].getKey(); + var absUrl = getRelativePathResolver().resolveRelativePath(relativeUrl); if (absUrl != null) { // found - create a DataResource object and store it in the mResourceMap - FileResourceSpecifier spec = new FileResourceSpecifier_impl(); + var spec = new FileResourceSpecifier_impl(); spec.setFileUrl(absUrl.toString()); // produces an instance of DataResourceImpl resourceImpl = UIMAFramework.produceResource(spec, null); @@ -839,11 +780,6 @@ public class ResourceManager_impl implements ResourceManager { mInternalResourceRegistrationMap.put(aName, registration); } - /* - * (non-Javadoc) - * - * @see org.apache.uima.resource.ResourceManager#getCasManager() - */ @Override public CasManager getCasManager() { // Optimization for case where mCasManager already created @@ -859,12 +795,6 @@ public class ResourceManager_impl implements ResourceManager { } } - /* - * (non-Javadoc) - * - * @see - * org.apache.uima.resource.ResourceManager#setCasManager(org.apache.uima.resource.CasManager) - */ @Override public void setCasManager(CasManager aCasManager) { synchronized (casManagerMonitor) { @@ -882,6 +812,7 @@ public class ResourceManager_impl implements ResourceManager { return mRelativePathResolver; } + @Deprecated(since = "3.3.0") @Override public Map<String, XMLizable> getImportCache() { return importCache; @@ -894,7 +825,7 @@ public class ResourceManager_impl implements ResourceManager { * * @deprecated No longer used. Scheduled for removal in UIMA 4.0. */ - @Deprecated + @Deprecated(since = "3.3.0") public Map<String, Set<String>> getImportUrlsCache() { Misc.decreasingWithTrace(IMPORT_URL_CACHE_WARNING_THROTTLE, "ResourceManager_impl.getImportUrlsCache() should not be called. It is no longer " @@ -924,11 +855,6 @@ public class ResourceManager_impl implements ResourceManager { } } - /* - * (non-Javadoc) - * - * @see org.apache.uima.resource.ResourceManager#destroy() - */ @Override public void destroy() { boolean alreadyDestroyed = isDestroyed.getAndSet(true); @@ -980,11 +906,6 @@ public class ResourceManager_impl implements ResourceManager { } - /* - * (non-Javadoc) - * - * @see org.apache.uima.resource.ResourceManager#getExternalResources() - */ @Override public List<Object> getExternalResources() { @@ -1001,5 +922,4 @@ public class ResourceManager_impl implements ResourceManager { return rs; } - } diff --git a/uimaj-core/src/main/java/org/apache/uima/resource/metadata/ResourceManagerConfiguration.java b/uimaj-core/src/main/java/org/apache/uima/resource/metadata/ResourceManagerConfiguration.java index 11b485aa8..664b5992d 100644 --- a/uimaj-core/src/main/java/org/apache/uima/resource/metadata/ResourceManagerConfiguration.java +++ b/uimaj-core/src/main/java/org/apache/uima/resource/metadata/ResourceManagerConfiguration.java @@ -143,7 +143,7 @@ public interface ResourceManagerConfiguration extends MetaDataObject { * @deprecated Use {@link #getImports()} instead. There may be many imports; this method only * returns the first. */ - @Deprecated + @Deprecated(since = "3.3.0") Import getImport(); /** @@ -154,7 +154,7 @@ public interface ResourceManagerConfiguration extends MetaDataObject { * manager configuration. Null indicates that there is no import. * @deprecated Use {@link #setImports(Import[])} instead. */ - @Deprecated + @Deprecated(since = "3.3.0") void setImport(Import aImport); /** @@ -292,5 +292,4 @@ public interface ResourceManagerConfiguration extends MetaDataObject { */ void resolveImports(Collection<String> aAlreadyImportedURLs, ResourceManager aResourceManager) throws InvalidXMLException; - } diff --git a/uimaj-core/src/main/java/org/apache/uima/util/impl/Settings_impl.java b/uimaj-core/src/main/java/org/apache/uima/util/impl/Settings_impl.java index 7928f4487..79fc5451e 100644 --- a/uimaj-core/src/main/java/org/apache/uima/util/impl/Settings_impl.java +++ b/uimaj-core/src/main/java/org/apache/uima/util/impl/Settings_impl.java @@ -168,7 +168,7 @@ public class Settings_impl implements Settings { if (fname.startsWith("path:")) { // Convert to a url and search the datapath & classpath URL relativeUrl = new URL("file", "", fname.substring(5).replace('.', '/') + ".settings"); - URL relPath = relativePathResolver.resolveRelativePath(relativeUrl); + URL relPath = relativePathResolver.resolveRelativePath(relativeUrl.toString()); if (relPath != null) { is = relPath.openStream(); } else { diff --git a/uimaj-core/src/test/java/org/apache/uima/resource/impl/RelativePathResolver_implTest.java b/uimaj-core/src/test/java/org/apache/uima/resource/impl/RelativePathResolver_implTest.java index f94f33afe..162577d0e 100644 --- a/uimaj-core/src/test/java/org/apache/uima/resource/impl/RelativePathResolver_implTest.java +++ b/uimaj-core/src/test/java/org/apache/uima/resource/impl/RelativePathResolver_implTest.java @@ -19,78 +19,164 @@ package org.apache.uima.resource.impl; +import static java.lang.String.join; +import static java.lang.System.getProperty; +import static java.nio.charset.StandardCharsets.UTF_8; +import static java.nio.file.Files.createDirectories; +import static java.nio.file.Files.newOutputStream; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import java.io.File; +import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; +import java.nio.file.Path; import java.util.stream.Stream; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; import org.apache.uima.test.junit_extension.JUnitExtension; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; -public class RelativePathResolver_implTest { +class RelativePathResolver_implTest { - private final static String PATH_SEP = System.getProperty("path.separator"); - private RelativePathResolver_impl sut; + private final static String PATH_SEP = getProperty("path.separator"); - private final static String element1 = "/this/is/a/test"; - private final static String element2 = "/another/test"; - private final static String[] expectedElements = { element1, element2 }; - private final static String expectedPath = String.join(PATH_SEP, expectedElements); + private RelativePathResolver_impl sut; @BeforeEach - public void setup() { + void setup() { sut = new RelativePathResolver_impl(); } - @Test - public void thatPathElementsAreNotModifiable() throws Exception { - sut.setDataPathElements(expectedPath); + @Nested + class UrlBasedTests { - assertThatExceptionOfType(UnsupportedOperationException.class) - .as("Path elements should not be modifiable") - .isThrownBy(() -> sut.getDataPathElements().add("blah")); - } + @Test + void thatPathUrlsAreNotModifiable() throws Exception { + sut.setDataPathElements(new URL("file:foo"), new URL("file:bar")); - @SuppressWarnings("deprecation") - @Test - public void testSetDataPath() throws Exception { - sut.setDataPath(expectedPath); + assertThatExceptionOfType(UnsupportedOperationException.class) + .as("Path elements should not be modifiable") + .isThrownBy(() -> sut.getDataPathUrls().add(new URL("file:blah"))); + } - assertThatGettersReturnTheRightValues(sut); - } + @SuppressWarnings("deprecation") + @Test + void setSetDataPathUrls(@TempDir Path temp) throws Exception { + var zipFile = temp.resolve("test.zip"); + createZipWithTextFiles(zipFile, "bar/bar.txt"); - @Test - public void testSetDataPathElements() throws Exception { - sut.setDataPathElements(expectedElements); + var zipBaseUrl = new URL("jar:" + zipFile.toUri() + "!/"); + var expected = new URL[] { new URL("file:foo"), zipBaseUrl }; + sut.setDataPathElements(expected); + + assertThat(sut.getDataPathElements()) // + .containsExactly("foo"); + + assertThat(sut.getDataPath()) // + .isEqualTo("foo"); + + assertThat(sut.getDataPathUrls()).containsExactly(expected); + + assertThat(sut.resolveRelativePath("bar/bar.txt")) + .isEqualTo(new URL(zipBaseUrl, "bar/bar.txt")); + assertThat(sut.resolveRelativePath("foo/bar.txt")).isNull(); + } - assertThatGettersReturnTheRightValues(sut); + public static void createZipWithTextFiles(Path aZipPath, String... aFileNames) + throws IOException { + createDirectories(aZipPath.getParent()); + + try (var zipOut = new ZipOutputStream(newOutputStream(aZipPath))) { + for (var fileName : aFileNames) { + zipOut.putNextEntry(new ZipEntry(fileName)); + zipOut.write(("This is the content of " + fileName).getBytes(UTF_8)); + zipOut.closeEntry(); + } + } + } } - @Test - public void testSetDataPathElementsAsFiles() throws Exception { - File[] expectedElementFiles = Stream.of(expectedElements).map(File::new).toArray(File[]::new); + @Nested + class FileBasedTests { + final String element1 = "/this/is/a/test"; + final String element2 = "/another/test"; + final String[] expectedElements = { element1, element2 }; + final String expectedPath = join(PATH_SEP, expectedElements); + + @SuppressWarnings("deprecation") + @Test + void testSetDataPath() throws Exception { + sut.setDataPath(expectedPath); + + assertThatGettersReturnTheRightValues(sut); + } + + @Test + void testSetDataPathElements() throws Exception { + sut.setDataPathElements(expectedElements); + + assertThatGettersReturnTheRightValues(sut); + } + + @Test + void testSetDataPathElementsAsFiles() throws Exception { + var expectedElementFiles = Stream.of(expectedElements).map(File::new).toArray(File[]::new); + + sut.setDataPathElements(expectedElementFiles); + + assertThatGettersReturnTheRightValues(sut); + } - sut.setDataPathElements(expectedElementFiles); + @Deprecated(since = "3.6.0") + @Test + void thatPathElementsAreNotModifiable() throws Exception { + sut.setDataPathElements("foo", "bar"); - assertThatGettersReturnTheRightValues(sut); + assertThatExceptionOfType(UnsupportedOperationException.class) + .as("Path elements should not be modifiable") + .isThrownBy(() -> sut.getDataPathElements().add("blah")); + } + + @SuppressWarnings("deprecation") + void assertThatGettersReturnTheRightValues(RelativePathResolver_impl aResolver) { + + assertThat(aResolver.getDataPathElements()) // + .containsExactly(expectedElements); + + assertThat(aResolver.getDataPath()) // + .isEqualTo(expectedPath); + + assertThat(aResolver.getDataPathUrls()) + .containsExactlyElementsOf(Stream.of(expectedElements).map(this::toUrl).toList()); + } + + @SuppressWarnings("deprecation") + URL toUrl(String path) { + try { + return new File(path).toURL(); + } catch (MalformedURLException e) { + throw new IllegalArgumentException(e); + } + } } @Test - public void testResolveRelativePath() throws Exception { - // file should not be found - assertThat(sut.resolveRelativePath(new URL("file:test/relativePathTest.dat"))) // + void testResolveRelativePathUsingString() throws Exception { + assertThat(sut.resolveRelativePath("file:test/relativePathTest.dat")) // .as("File should not be found") // .isNull(); // specify path - String path = JUnitExtension.getFile("ResourceTest/subdir").getAbsolutePath(); + var path = JUnitExtension.getFile("ResourceTest/subdir").getAbsolutePath(); sut.setDataPathElements(path); - URL absUrl = sut.resolveRelativePath(new URL("file:test/relativePathTest.dat")); + var absUrl = sut.resolveRelativePath("file:test/relativePathTest.dat"); assertThat(absUrl) // .as("now file should be found") // .isNotNull(); @@ -98,28 +184,28 @@ public class RelativePathResolver_implTest { // try resolving an absolute path even with no data path sut.setDataPathElements(""); - assertThat(sut.resolveRelativePath(absUrl)).isEqualTo(absUrl); + assertThat(sut.resolveRelativePath(absUrl.toString())).isEqualTo(absUrl); } @SuppressWarnings("deprecation") - private void assertThatGettersReturnTheRightValues(RelativePathResolver_impl aResolver) { + @Test + void testResolveRelativePathUsingUrl() throws Exception { + assertThat(sut.resolveRelativePath(new URL("file:test/relativePathTest.dat"))) // + .as("File should not be found") // + .isNull(); - assertThat(aResolver.getDataPathElements()) // - .containsExactly(expectedElements); + // specify path + var path = JUnitExtension.getFile("ResourceTest/subdir").getAbsolutePath(); + sut.setDataPathElements(path); - assertThat(aResolver.getDataPath()) // - .isEqualTo(expectedPath); + var absUrl = sut.resolveRelativePath(new URL("file:test/relativePathTest.dat")); + assertThat(absUrl) // + .as("now file should be found") // + .isNotNull(); - assertThat(aResolver.getBaseUrls()) - .containsExactly(Stream.of(expectedElements).map(this::toUrl).toArray(URL[]::new)); - } + // try resolving an absolute path even with no data path + sut.setDataPathElements(""); - @SuppressWarnings("deprecation") - private URL toUrl(String path) { - try { - return new File(path).toURL(); - } catch (MalformedURLException e) { - throw new IllegalArgumentException(e); - } + assertThat(sut.resolveRelativePath(absUrl)).isEqualTo(absUrl); } }
