Move FileID from deploy to util
+ Move static methods from other places to FileID or URIUtil - MultiReleaseJarFile - Resource - MetaInfConfiguration + Improve testing of URIUtil and FileID
This commit is contained in:
parent
3006994b14
commit
dd7dda2c53
|
@ -20,9 +20,9 @@ import java.util.HashMap;
|
|||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.eclipse.jetty.deploy.util.FileID;
|
||||
import org.eclipse.jetty.ee.Deployable;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.util.FileID;
|
||||
|
||||
/**
|
||||
* The information about an App that is managed by the {@link DeploymentManager}.
|
||||
|
|
|
@ -30,10 +30,10 @@ import java.util.function.Supplier;
|
|||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jetty.deploy.App;
|
||||
import org.eclipse.jetty.deploy.util.FileID;
|
||||
import org.eclipse.jetty.ee.Deployable;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.util.FileID;
|
||||
import org.eclipse.jetty.util.Loader;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
|
|
|
@ -29,8 +29,8 @@ import java.util.stream.Collectors;
|
|||
import org.eclipse.jetty.deploy.App;
|
||||
import org.eclipse.jetty.deploy.AppProvider;
|
||||
import org.eclipse.jetty.deploy.DeploymentManager;
|
||||
import org.eclipse.jetty.deploy.util.FileID;
|
||||
import org.eclipse.jetty.ee.Deployable;
|
||||
import org.eclipse.jetty.util.FileID;
|
||||
import org.eclipse.jetty.util.Scanner;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.annotation.ManagedAttribute;
|
||||
|
|
|
@ -1,89 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
|
||||
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.deploy.util;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Simple, yet surprisingly common utility methods for identifying various file types commonly seen and worked with in a
|
||||
* deployment scenario.
|
||||
*/
|
||||
public class FileID
|
||||
{
|
||||
/**
|
||||
* Is the path a Web Archive File (not directory)
|
||||
*
|
||||
* @param file the path to test.
|
||||
* @return True if a .war or .jar file.
|
||||
*/
|
||||
public static boolean isWebArchive(File file)
|
||||
{
|
||||
return isWebArchive(file.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the path a Web Archive File (not directory)
|
||||
*
|
||||
* @param path the path to test.
|
||||
* @return True if a .war or .jar file.
|
||||
*/
|
||||
public static boolean isWebArchive(Path path)
|
||||
{
|
||||
return isWebArchive(path.getFileName().toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the filename a WAR file.
|
||||
*
|
||||
* @param filename the filename to test.
|
||||
* @return True if a .war or .jar file.
|
||||
*/
|
||||
public static boolean isWebArchive(String filename)
|
||||
{
|
||||
String name = filename.toLowerCase(Locale.ENGLISH);
|
||||
return (name.endsWith(".war"));
|
||||
}
|
||||
|
||||
public static boolean isXml(File path)
|
||||
{
|
||||
return isXml(path.getName());
|
||||
}
|
||||
|
||||
public static boolean isXml(Path path)
|
||||
{
|
||||
return isXml(path.getFileName().toString());
|
||||
}
|
||||
|
||||
public static boolean isXml(String filename)
|
||||
{
|
||||
return filename.toLowerCase(Locale.ENGLISH).endsWith(".xml");
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the basename of a path. This is the name of the
|
||||
* last segment of the path, with any dot suffix (e.g. ".war") removed
|
||||
* @param path The string path
|
||||
* @return The last segment of the path without any dot suffix
|
||||
*/
|
||||
public static String getBasename(Path path)
|
||||
{
|
||||
String basename = path.getFileName().toString();
|
||||
int dot = basename.lastIndexOf('.');
|
||||
if (dot >= 0)
|
||||
basename = basename.substring(0, dot);
|
||||
return basename;
|
||||
}
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
|
||||
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
/**
|
||||
* Jetty Deploy : Utilities
|
||||
*/
|
||||
package org.eclipse.jetty.deploy.util;
|
||||
|
|
@ -16,9 +16,9 @@ package org.eclipse.jetty.deploy;
|
|||
import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import org.eclipse.jetty.deploy.util.FileID;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.eclipse.jetty.util.FileID;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
import org.eclipse.jetty.util.component.AbstractLifeCycle;
|
||||
import org.eclipse.jetty.util.component.Environment;
|
||||
|
@ -60,9 +60,9 @@ public class MockAppProvider extends AbstractLifeCycle implements AppProvider
|
|||
|
||||
String name = app.getPath().toString();
|
||||
name = name.substring(name.lastIndexOf("-") + 1);
|
||||
File war = new File(webappsDir, name);
|
||||
Path war = new File(webappsDir, name).toPath();
|
||||
|
||||
String path = war.getName();
|
||||
String path = war.toString();
|
||||
|
||||
if (FileID.isWebArchive(war))
|
||||
{
|
||||
|
|
|
@ -27,6 +27,7 @@ import org.eclipse.jetty.toolchain.test.FS;
|
|||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
|
@ -69,7 +70,7 @@ public class RangeWriterTest
|
|||
{
|
||||
Path exampleJar = MavenTestingUtils.getTestResourcePathFile("example.jar");
|
||||
|
||||
URI jarFileUri = Resource.toJarFileUri(exampleJar.toUri());
|
||||
URI jarFileUri = URIUtil.toJarFileUri(exampleJar.toUri());
|
||||
|
||||
// close prior one (if it exists)
|
||||
IO.close(zipfs);
|
||||
|
|
|
@ -0,0 +1,382 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
|
||||
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.util;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Simple, yet surprisingly common utility methods for identifying various file types commonly seen and worked with in a
|
||||
* deployment scenario.
|
||||
*/
|
||||
public class FileID
|
||||
{
|
||||
/**
|
||||
* Does the provided path have a directory segment with
|
||||
* the configured name.
|
||||
*
|
||||
* @param path the path to search
|
||||
* @param directoryName the directory name to look for (case insensitive lookup)
|
||||
* @return true if the directory name exists in path, false if otherwise
|
||||
*/
|
||||
public static boolean containsDirectory(Path path, String directoryName)
|
||||
{
|
||||
if (path == null)
|
||||
return false;
|
||||
int segmentCount = path.getNameCount();
|
||||
for (int i = segmentCount - 1; i > 0; i--)
|
||||
{
|
||||
Path segment = path.getName(i);
|
||||
if (segment.getFileName().toString().equalsIgnoreCase(directoryName))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the basename of a path. This is the name of the
|
||||
* last segment of the path, with any dot suffix (e.g. ".war") removed
|
||||
*
|
||||
* @param path The string path
|
||||
* @return The last segment of the path without any dot suffix
|
||||
*/
|
||||
public static String getBasename(Path path)
|
||||
{
|
||||
String basename = path.getFileName().toString();
|
||||
int dot = basename.lastIndexOf('.');
|
||||
if (dot >= 0)
|
||||
basename = basename.substring(0, dot);
|
||||
return basename;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the extension of a file path (not a directory).
|
||||
* This is the name of the last segment of the file path with a substring
|
||||
* for the extension (if any), including the dot, lower-cased.
|
||||
*
|
||||
* @param path The string path
|
||||
* @return The last segment extension, or null if not a file, or null if there is no extension present
|
||||
*/
|
||||
public static String getExtension(Path path)
|
||||
{
|
||||
if (path == null)
|
||||
return null; // no path
|
||||
|
||||
if (!Files.isRegularFile(path))
|
||||
return null; // not a file
|
||||
|
||||
return getExtension(path.getFileName().toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the extension of a file path (not a directory).
|
||||
* This is the extension of filename of the last segment of the file path with a substring
|
||||
* for the extension (if any), including the dot, lower-cased.
|
||||
*
|
||||
* @param filename The string path
|
||||
* @return The last segment extension, or null if not a file, or null if there is no extension present
|
||||
*/
|
||||
public static String getExtension(String filename)
|
||||
{
|
||||
if (filename == null)
|
||||
return null; // no filename
|
||||
if (filename.endsWith("/") || filename.endsWith("\\"))
|
||||
return null; // not a filename
|
||||
int lastSlash = filename.lastIndexOf(File.separator);
|
||||
if (lastSlash >= 0)
|
||||
filename = filename.substring(lastSlash + 1);
|
||||
int lastDot = filename.lastIndexOf('.');
|
||||
if (lastDot < 0)
|
||||
return null; // no extension
|
||||
return filename.substring(lastDot).toLowerCase(Locale.ENGLISH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if Path is any supported Java Archive type (ends in {@code .jar}, {@code .war}, or {@code .zip}).
|
||||
*
|
||||
* @param path the path to test
|
||||
* @return true if path is a file, and an extension of {@code .jar}, {@code .war}, or {@code .zip}
|
||||
* @see #getExtension(Path)
|
||||
*/
|
||||
public static boolean isArchive(Path path)
|
||||
{
|
||||
String ext = getExtension(path);
|
||||
if (ext == null)
|
||||
return false;
|
||||
return (ext.equals(".jar") || ext.equals(".war") || ext.equals(".zip"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if filename is any supported Java Archive type (ends in {@code .jar}, {@code .war}, or {@code .zip}).
|
||||
*
|
||||
* @param filename the filename to test
|
||||
* @return true if path is a file and name ends with {@code .jar}, {@code .war}, or {@code .zip}
|
||||
* @see #getExtension(String)
|
||||
*/
|
||||
public static boolean isArchive(String filename)
|
||||
{
|
||||
String ext = getExtension(filename);
|
||||
if (ext == null)
|
||||
return false;
|
||||
return (ext.equals(".jar") || ext.equals(".war") || ext.equals(".zip"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if URI is any supported Java Archive type.
|
||||
*
|
||||
* @param uri the URI to test
|
||||
* @return true if the URI has a path that seems to point to a ({@code .jar}, {@code .war}, or {@code .zip}).
|
||||
* @see #isArchive(String)
|
||||
*/
|
||||
public static boolean isArchive(URI uri)
|
||||
{
|
||||
if (uri == null)
|
||||
return false;
|
||||
if (uri.getScheme() == null)
|
||||
return false;
|
||||
if (uri.getScheme().equalsIgnoreCase("jar"))
|
||||
{
|
||||
URI sspUri = URI.create(uri.getRawSchemeSpecificPart());
|
||||
if (!sspUri.getScheme().equalsIgnoreCase("file"))
|
||||
{
|
||||
return false; // not a `jar:file:` based URI
|
||||
}
|
||||
|
||||
String path = sspUri.getPath();
|
||||
|
||||
int jarEnd = path.indexOf("!/");
|
||||
if (jarEnd >= 0)
|
||||
{
|
||||
return isArchive(path.substring(0, jarEnd));
|
||||
}
|
||||
return isArchive(path);
|
||||
}
|
||||
String path = uri.getPath();
|
||||
// look for `!/` split
|
||||
int jarEnd = path.indexOf("!/");
|
||||
if (jarEnd >= 0)
|
||||
{
|
||||
return isArchive(path.substring(0, jarEnd));
|
||||
}
|
||||
return isArchive(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Predicate to select all class files
|
||||
*
|
||||
* @param path the path to test
|
||||
* @return true if the filename ends with {@code .class}
|
||||
*/
|
||||
public static boolean isClassFile(Path path)
|
||||
{
|
||||
String filename = path.getFileName().toString();
|
||||
// has to end in ".class"
|
||||
if (!filename.toLowerCase(Locale.ENGLISH).endsWith(".class"))
|
||||
return false;
|
||||
// is it a valid class filename?
|
||||
int start = 0;
|
||||
int end = filename.length() - 6; // drop ".class"
|
||||
if (end <= start) // if the filename is only ".class"
|
||||
return false;
|
||||
// Test first character
|
||||
if (!Character.isJavaIdentifierStart(filename.charAt(0)))
|
||||
return false;
|
||||
// Test rest
|
||||
for (int i = start + 1; i < end; i++)
|
||||
{
|
||||
if (!Character.isJavaIdentifierPart(filename.codePointAt(i)))
|
||||
{
|
||||
// not a java identifier
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Predicate useful for {@code Stream<Path>} to exclude hidden paths following
|
||||
* filesystem rules for hidden directories and files.
|
||||
*
|
||||
* @param base the base path to search from (anything above this path is not evaluated)
|
||||
* @param path the path to evaluate
|
||||
* @return true if hidden by FileSystem rules, false if not
|
||||
* @see Files#isHidden(Path)
|
||||
*/
|
||||
public static boolean isHidden(Path base, Path path)
|
||||
{
|
||||
// Work with the path in relative form, from the base onwards to the path
|
||||
Path relative = base.relativize(path);
|
||||
|
||||
int count = relative.getNameCount();
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Files.isHidden(relative.getName(i)))
|
||||
return true;
|
||||
}
|
||||
catch (IOException ignore)
|
||||
{
|
||||
// ignore, if filesystem gives us an error, we cannot make the call on hidden status
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the path a Java Archive (JAR) File (not directory)
|
||||
*
|
||||
* @param path the path to test.
|
||||
* @return True if a .jar file.
|
||||
*/
|
||||
public static boolean isJavaArchive(Path path)
|
||||
{
|
||||
return ".jar".equals(getExtension(path));
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the filename a JAR file.
|
||||
*
|
||||
* @param filename the filename to test.
|
||||
* @return True if a .jar file.
|
||||
*/
|
||||
public static boolean isJavaArchive(String filename)
|
||||
{
|
||||
return ".jar".equals(getExtension(filename));
|
||||
}
|
||||
|
||||
/**
|
||||
* Predicate to filter on {@code META-INF/versions/*} tree in walk/stream results.
|
||||
*
|
||||
* <p>
|
||||
* This only works with a zipfs based FileSystem
|
||||
* </p>
|
||||
*
|
||||
* @param path the path to test
|
||||
* @return true if path is in {@code META-INF/versions/*} tree
|
||||
*/
|
||||
public static boolean isMetaInfVersions(Path path)
|
||||
{
|
||||
if (path.getNameCount() < 3)
|
||||
return false;
|
||||
|
||||
Path path0 = path.getName(0);
|
||||
Path path1 = path.getName(1);
|
||||
Path path2 = path.getName(2);
|
||||
|
||||
return (path0.toString().equals("META-INF") &&
|
||||
path1.toString().equals("versions") &&
|
||||
path2.getFileName().toString().matches("[0-9]+"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the path a TLD File
|
||||
*
|
||||
* @param path the path to test.
|
||||
* @return True if a .war file.
|
||||
*/
|
||||
public static boolean isTldFile(Path path)
|
||||
{
|
||||
if (path == null)
|
||||
return false;
|
||||
if (path.getNameCount() < 2)
|
||||
return false;
|
||||
if (!".tld".equals(getExtension(path)))
|
||||
return false;
|
||||
return containsDirectory(path, "META-INF");
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the path a Web Archive File (not directory)
|
||||
*
|
||||
* @param path the path to test.
|
||||
* @return True if a .war file.
|
||||
*/
|
||||
public static boolean isWebArchive(Path path)
|
||||
{
|
||||
return ".war".equals(getExtension(path));
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the filename a WAR file.
|
||||
*
|
||||
* @param filename the filename to test.
|
||||
* @return True if a .war file.
|
||||
*/
|
||||
public static boolean isWebArchive(String filename)
|
||||
{
|
||||
return ".war".equals(getExtension(filename));
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the Path a file that ends in XML?
|
||||
*
|
||||
* @param path the path to test
|
||||
* @return true if a .xml, false otherwise
|
||||
*/
|
||||
public static boolean isXml(Path path)
|
||||
{
|
||||
return ".xml".equals(getExtension(path));
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the Path a file that ends in XML?
|
||||
*
|
||||
* @param filename the filename to test
|
||||
* @return true if a .xml, false otherwise
|
||||
*/
|
||||
public static boolean isXml(String filename)
|
||||
{
|
||||
return ".xml".equals(getExtension(filename));
|
||||
}
|
||||
|
||||
/**
|
||||
* Predicate to skip {@code META-INF/versions/*} tree from walk/stream results.
|
||||
*
|
||||
* <p>
|
||||
* This only works with a zipfs based FileSystem
|
||||
* </p>
|
||||
*
|
||||
* @param path the path to test
|
||||
* @return true if not in {@code META-INF/versions/*} tree
|
||||
*/
|
||||
public static boolean skipMetaInfVersions(Path path)
|
||||
{
|
||||
return !isMetaInfVersions(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Predicate to skip {@code module-info.class} files.
|
||||
*
|
||||
* <p>
|
||||
* This is a simple test against the last path segment using {@link Path#getFileName()}
|
||||
* </p>
|
||||
*
|
||||
* @param path the path to test
|
||||
* @return true if not a {@code module-info.class} file
|
||||
*/
|
||||
public static boolean skipModuleInfoClass(Path path)
|
||||
{
|
||||
Path filenameSegment = path.getFileName();
|
||||
if (filenameSegment == null)
|
||||
return true;
|
||||
|
||||
return !filenameSegment.toString().equalsIgnoreCase("module-info.class");
|
||||
}
|
||||
}
|
|
@ -17,7 +17,6 @@ import java.io.Closeable;
|
|||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
|
@ -51,8 +50,7 @@ public class MultiReleaseJarFile implements Closeable
|
|||
if (!Files.isRegularFile(jarFile))
|
||||
throw new IllegalArgumentException("Not a file: " + jarFile);
|
||||
|
||||
// TODO : use FileID.isJar() in future PR
|
||||
if (!Resource.isArchive(jarFile))
|
||||
if (!FileID.isJavaArchive(jarFile))
|
||||
throw new IllegalArgumentException("Not a Jar: " + jarFile);
|
||||
|
||||
if (!Files.isReadable(jarFile))
|
||||
|
@ -64,133 +62,6 @@ public class MultiReleaseJarFile implements Closeable
|
|||
LOG.debug("mounting {}", jarResource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Predicate to skip {@code module-info.class} files.
|
||||
*
|
||||
* <p>
|
||||
* This is a simple test against the last path segment using {@link Path#getFileName()}
|
||||
* </p>
|
||||
*
|
||||
* @param path the path to test
|
||||
* @return true if not a {@code module-info.class} file
|
||||
* TODO: move to FileID class in later PR
|
||||
*/
|
||||
public static boolean skipModuleInfoClass(Path path)
|
||||
{
|
||||
Path filenameSegment = path.getFileName();
|
||||
if (filenameSegment == null)
|
||||
return true;
|
||||
|
||||
return !filenameSegment.toString().equalsIgnoreCase("module-info.class");
|
||||
}
|
||||
|
||||
/**
|
||||
* Predicate to skip {@code META-INF/versions/*} tree from walk/stream results.
|
||||
*
|
||||
* <p>
|
||||
* This only works with a zipfs based FileSystem
|
||||
* </p>
|
||||
*
|
||||
* @param path the path to test
|
||||
* @return true if not in {@code META-INF/versions/*} tree
|
||||
* TODO: move to FileID class in later PR
|
||||
*/
|
||||
public static boolean skipMetaInfVersions(Path path)
|
||||
{
|
||||
return !isMetaInfVersions(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Predicate to filter on {@code META-INF/versions/*} tree in walk/stream results.
|
||||
*
|
||||
* <p>
|
||||
* This only works with a zipfs based FileSystem
|
||||
* </p>
|
||||
*
|
||||
* @param path the path to test
|
||||
* @return true if path is in {@code META-INF/versions/*} tree
|
||||
* TODO: move to FileID class in later PR
|
||||
*/
|
||||
public static boolean isMetaInfVersions(Path path)
|
||||
{
|
||||
if (path.getNameCount() < 3)
|
||||
return false;
|
||||
|
||||
Path path0 = path.getName(0);
|
||||
Path path1 = path.getName(1);
|
||||
Path path2 = path.getName(2);
|
||||
|
||||
return (path0.toString().equals("META-INF") &&
|
||||
path1.toString().equals("versions") &&
|
||||
path2.getFileName().toString().matches("[0-9]+"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Predicate to select all class files
|
||||
*
|
||||
* @param path the path to test
|
||||
* @return true if the filename ends with {@code .class}
|
||||
* TODO: move to FileID class in later PR
|
||||
*/
|
||||
public static boolean isClassFile(Path path)
|
||||
{
|
||||
String filename = path.getFileName().toString();
|
||||
// has to end in ".class"
|
||||
if (!filename.toLowerCase(Locale.ENGLISH).endsWith(".class"))
|
||||
return false;
|
||||
// is it a valid class filename?
|
||||
int start = 0;
|
||||
int end = filename.length() - 6; // drop ".class"
|
||||
if (end <= start) // if the filename is only ".class"
|
||||
return false;
|
||||
// Test first character
|
||||
if (!Character.isJavaIdentifierStart(filename.charAt(0)))
|
||||
return false;
|
||||
// Test rest
|
||||
for (int i = start + 1; i < end; i++)
|
||||
{
|
||||
if (!Character.isJavaIdentifierPart(filename.codePointAt(i)))
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Not a java identifier: {}", filename);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Predicate useful for {@code Stream<Path>} to exclude hidden paths following
|
||||
* filesystem rules for hidden directories and files.
|
||||
*
|
||||
* @param base the base path to search from (anything above this path is not evaluated)
|
||||
* @param path the path to evaluate
|
||||
* @return true if hidden by FileSystem rules, false if not
|
||||
* @see Files#isHidden(Path)
|
||||
* TODO: move to FileID.isHidden(Path, Path)
|
||||
*/
|
||||
public static boolean isHidden(Path base, Path path)
|
||||
{
|
||||
// Work with the path in relative form, from the base onwards to the path
|
||||
Path relative = base.relativize(path);
|
||||
|
||||
int count = relative.getNameCount();
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Files.isHidden(relative.getName(i)))
|
||||
return true;
|
||||
}
|
||||
catch (IOException ignore)
|
||||
{
|
||||
// ignore, if filesystem gives us an error, we cannot make the call on hidden status
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return A stream of versioned entries from the jar, excluding {@code META-INF/versions} entries.
|
||||
*/
|
||||
|
@ -201,7 +72,7 @@ public class MultiReleaseJarFile implements Closeable
|
|||
|
||||
return Files.walk(rootPath)
|
||||
// skip the entire META-INF/versions tree
|
||||
.filter(MultiReleaseJarFile::skipMetaInfVersions);
|
||||
.filter(FileID::skipMetaInfVersions);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -13,15 +13,24 @@
|
|||
|
||||
package org.eclipse.jetty.util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jetty.util.Utf8Appendable.NotUtf8Exception;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -36,8 +45,7 @@ import org.slf4j.LoggerFactory;
|
|||
*
|
||||
* @see UrlEncoded
|
||||
*/
|
||||
public class URIUtil
|
||||
implements Cloneable
|
||||
public final class URIUtil
|
||||
{
|
||||
private static final Logger LOG = LoggerFactory.getLogger(URIUtil.class);
|
||||
public static final String SLASH = "/";
|
||||
|
@ -1647,25 +1655,7 @@ public class URIUtil
|
|||
return query1 + '&' + query2;
|
||||
}
|
||||
|
||||
public static URI getJarSource(URL url)
|
||||
{
|
||||
return getJarSource(URI.create(url.toString()));
|
||||
}
|
||||
|
||||
public static URI getJarSource(URI uri)
|
||||
{
|
||||
if (!"jar".equals(uri.getScheme()))
|
||||
return uri;
|
||||
|
||||
// Get SSP (retaining encoded form)
|
||||
String s = uri.getRawSchemeSpecificPart();
|
||||
int bangSlash = s.indexOf("!/");
|
||||
if (bangSlash >= 0)
|
||||
s = s.substring(0, bangSlash);
|
||||
return URI.create(s);
|
||||
}
|
||||
|
||||
public static URI fixBadJavaIoFileUrl(URI uri)
|
||||
public static URI correctBadFileURI(URI uri)
|
||||
{
|
||||
if ((uri == null) || (uri.getScheme() == null))
|
||||
return uri;
|
||||
|
@ -1692,6 +1682,142 @@ public class URIUtil
|
|||
return uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Split a string of references, that may be split with {@code ,}, or {@code ;}, or {@code |} into URIs.
|
||||
* <p>
|
||||
* Each part of the input string could be path references (unix or windows style), or string URI references.
|
||||
* </p>
|
||||
* <p>
|
||||
* If the result of processing the input segment is a java archive, then its resulting URI will be a mountable URI as `jar:file:...!/`.
|
||||
* </p>
|
||||
*
|
||||
* @param str the input string of references
|
||||
* @see #toJarFileUri(URI)
|
||||
*/
|
||||
public static List<URI> split(String str)
|
||||
{
|
||||
List<URI> uris = new ArrayList<>();
|
||||
|
||||
StringTokenizer tokenizer = new StringTokenizer(str, ",;|");
|
||||
while (tokenizer.hasMoreTokens())
|
||||
{
|
||||
String reference = tokenizer.nextToken();
|
||||
try
|
||||
{
|
||||
// Is this a glob reference?
|
||||
if (reference.endsWith("/*") || reference.endsWith("\\*"))
|
||||
{
|
||||
String dir = reference.substring(0, reference.length() - 2);
|
||||
Path pathDir = Paths.get(dir);
|
||||
// Use directory
|
||||
if (Files.exists(pathDir) && Files.isDirectory(pathDir))
|
||||
{
|
||||
// To obtain the list of entries
|
||||
try (Stream<Path> listStream = Files.list(pathDir))
|
||||
{
|
||||
listStream
|
||||
.filter(Files::isRegularFile)
|
||||
.filter(FileID::isArchive)
|
||||
.sorted(Comparator.naturalOrder())
|
||||
.forEach(path -> uris.add(toJarFileUri(path.toUri())));
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new RuntimeException("Unable to process directory glob listing: " + reference, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Simple reference
|
||||
URI refUri = Resource.toURI(reference);
|
||||
// Is this a Java Archive that can be mounted?
|
||||
URI jarFileUri = toJarFileUri(refUri);
|
||||
if (jarFileUri != null)
|
||||
// add as mountable URI
|
||||
uris.add(jarFileUri);
|
||||
else
|
||||
// add as normal URI
|
||||
uris.add(refUri);
|
||||
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn("Invalid Resource Reference: " + reference);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
return uris;
|
||||
}
|
||||
|
||||
/**
|
||||
* Take an arbitrary URI and provide a URI that is suitable for mounting the URI as a Java FileSystem.
|
||||
*
|
||||
* The resulting URI will point to the {@code jar:file://foo.jar!/} said Java Archive (jar, war, or zip)
|
||||
*
|
||||
* @param uri the URI to mutate to a {@code jar:file:...} URI.
|
||||
* @return the <code>jar:${uri_to_java_archive}!/${internal-reference}</code> URI or null if not a Java Archive.
|
||||
* @see FileID#isArchive(URI)
|
||||
*/
|
||||
public static URI toJarFileUri(URI uri)
|
||||
{
|
||||
Objects.requireNonNull(uri, "URI");
|
||||
String scheme = Objects.requireNonNull(uri.getScheme(), "URI scheme");
|
||||
|
||||
if (!FileID.isArchive(uri))
|
||||
return null;
|
||||
|
||||
boolean hasInternalReference = uri.getRawSchemeSpecificPart().indexOf("!/") > 0;
|
||||
|
||||
if (scheme.equalsIgnoreCase("jar"))
|
||||
{
|
||||
if (uri.getRawSchemeSpecificPart().startsWith("file:"))
|
||||
{
|
||||
// Looking good as a jar:file: URI
|
||||
if (hasInternalReference)
|
||||
return uri; // is all good, no changes needed.
|
||||
else
|
||||
// add the internal reference indicator to the root of the archive
|
||||
return URI.create(uri.toASCIIString() + "!/");
|
||||
}
|
||||
}
|
||||
else if (scheme.equalsIgnoreCase("file"))
|
||||
{
|
||||
String rawUri = uri.toASCIIString();
|
||||
if (hasInternalReference)
|
||||
return URI.create("jar:" + rawUri);
|
||||
else
|
||||
return URI.create("jar:" + rawUri + "!/");
|
||||
}
|
||||
|
||||
// shouldn't be possible to reach this point
|
||||
throw new IllegalArgumentException("Cannot make %s into `jar:file:` URI".formatted(uri));
|
||||
}
|
||||
|
||||
/**
|
||||
* Unwrap a URI to expose its container path reference.
|
||||
*
|
||||
* Take out the container archive name URI from a {@code jar:file:${container-name}!/} URI.
|
||||
*
|
||||
* @param uri the input URI
|
||||
* @return the container String if a {@code jar} scheme, or just the URI untouched.
|
||||
*/
|
||||
public static URI unwrapContainer(URI uri)
|
||||
{
|
||||
Objects.requireNonNull(uri);
|
||||
|
||||
String scheme = uri.getScheme();
|
||||
if ((scheme == null) || !scheme.equalsIgnoreCase("jar"))
|
||||
return uri;
|
||||
|
||||
String spec = uri.getRawSchemeSpecificPart();
|
||||
int sep = spec.indexOf("!/");
|
||||
if (sep != -1)
|
||||
spec = spec.substring(0, sep);
|
||||
return URI.create(spec);
|
||||
}
|
||||
|
||||
/**
|
||||
* Take a URI and add a deep reference {@code jar:file://foo.jar!/suffix}, replacing
|
||||
* any existing deep reference on the input URI.
|
||||
|
@ -1740,7 +1866,9 @@ public class URIUtil
|
|||
URL[] urls = urlClassLoader.getURLs();
|
||||
return Stream.of(urls)
|
||||
.filter(Objects::nonNull)
|
||||
.map(URIUtil::getJarSource)
|
||||
.map(URIUtil::fixBadJavaIoFileUrl);
|
||||
.map(URL::toString)
|
||||
.map(URI::create)
|
||||
.map(URIUtil::unwrapContainer)
|
||||
.map(URIUtil::correctBadFileURI);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ import java.util.Set;
|
|||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
import org.eclipse.jetty.util.annotation.ManagedAttribute;
|
||||
import org.eclipse.jetty.util.annotation.ManagedObject;
|
||||
import org.eclipse.jetty.util.annotation.ManagedOperation;
|
||||
|
@ -226,7 +227,7 @@ public class FileSystemPool implements Dumpable
|
|||
|
||||
private Bucket(URI fsUri, FileSystem fileSystem, Resource.Mount mount)
|
||||
{
|
||||
URI containerUri = Resource.unwrapContainer(fsUri);
|
||||
URI containerUri = URIUtil.unwrapContainer(fsUri);
|
||||
Path path = Paths.get(containerUri);
|
||||
|
||||
long size = -1L;
|
||||
|
|
|
@ -18,6 +18,8 @@ import java.net.URI;
|
|||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
|
||||
/**
|
||||
* Java NIO Path Resource with file system pooling. {@link FileSystem} implementations that must be closed
|
||||
* must use this class, for instance the one handling the `jar` scheme.
|
||||
|
@ -29,7 +31,7 @@ public class MountedPathResource extends PathResource
|
|||
MountedPathResource(URI uri) throws IOException
|
||||
{
|
||||
super(uri, true);
|
||||
containerUri = unwrapContainer(getURI());
|
||||
containerUri = URIUtil.unwrapContainer(getURI());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -36,17 +36,14 @@ import java.text.DateFormat;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Base64;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jetty.util.FileID;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.Index;
|
||||
import org.eclipse.jetty.util.Loader;
|
||||
|
@ -144,7 +141,7 @@ public abstract class Resource implements ResourceFactory
|
|||
String scheme = uri.getScheme();
|
||||
if (scheme == null)
|
||||
return null;
|
||||
if (!isArchive(uri))
|
||||
if (!FileID.isArchive(uri))
|
||||
return null;
|
||||
try
|
||||
{
|
||||
|
@ -171,7 +168,7 @@ public abstract class Resource implements ResourceFactory
|
|||
*/
|
||||
public static Resource.Mount mount(URI uri) throws IOException
|
||||
{
|
||||
if (!isArchive(uri))
|
||||
if (!FileID.isArchive(uri))
|
||||
throw new IllegalArgumentException("URI is not a Java Archive: " + uri);
|
||||
if (!uri.getScheme().equalsIgnoreCase("jar"))
|
||||
throw new IllegalArgumentException("not an allowed URI: " + uri);
|
||||
|
@ -186,12 +183,12 @@ public abstract class Resource implements ResourceFactory
|
|||
*/
|
||||
public static Resource.Mount mountJar(Path path) throws IOException
|
||||
{
|
||||
if (!isArchive(path))
|
||||
if (!FileID.isArchive(path))
|
||||
throw new IllegalArgumentException("Path is not a Java Archive: " + path);
|
||||
URI pathUri = path.toUri();
|
||||
if (!pathUri.getScheme().equalsIgnoreCase("file"))
|
||||
throw new IllegalArgumentException("Not an allowed path: " + path);
|
||||
URI jarUri = toJarFileUri(pathUri);
|
||||
URI jarUri = URIUtil.toJarFileUri(pathUri);
|
||||
if (jarUri == null)
|
||||
throw new IllegalArgumentException("Not a mountable archive: " + path);
|
||||
return FileSystemPool.INSTANCE.mount(jarUri);
|
||||
|
@ -225,136 +222,6 @@ public abstract class Resource implements ResourceFactory
|
|||
return new ResourceCollection(List.of(resources));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if Path is a Java Archive (ends in {@code .jar}, {@code .war}, or {@code .zip}).
|
||||
*
|
||||
* @param path the path to test
|
||||
* @return true if path is a {@link Files#isRegularFile(Path, LinkOption...)} and name ends with {@code .jar}, {@code .war}, or {@code .zip}
|
||||
*/
|
||||
public static boolean isArchive(Path path)
|
||||
{
|
||||
if (path == null)
|
||||
return false;
|
||||
if (!Files.isRegularFile(path))
|
||||
return false;
|
||||
String filename = path.getFileName().toString().toLowerCase(Locale.ENGLISH);
|
||||
return (filename.endsWith(".jar") || filename.endsWith(".war") || filename.endsWith(".zip"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if URI is a Java Archive. (ends with {@code .jar}, {@code .war}, or {@code .zip}).
|
||||
*
|
||||
* @param uri the URI to test
|
||||
* @return true if the URI has a path that seems to point to a ({@code .jar}, {@code .war}, or {@code .zip}).
|
||||
*/
|
||||
public static boolean isArchive(URI uri)
|
||||
{
|
||||
if (uri == null)
|
||||
return false;
|
||||
if (uri.getScheme() == null)
|
||||
return false;
|
||||
String path = uri.getPath();
|
||||
int idxEnd = path == null ? -1 : path.length();
|
||||
if (uri.getScheme().equalsIgnoreCase("jar"))
|
||||
{
|
||||
String ssp = uri.getRawSchemeSpecificPart();
|
||||
path = URI.create(ssp).getPath();
|
||||
idxEnd = path.length();
|
||||
// look for `!/` split
|
||||
int jarEnd = path.indexOf("!/");
|
||||
if (jarEnd >= 0)
|
||||
idxEnd = jarEnd;
|
||||
}
|
||||
if (path == null)
|
||||
return false;
|
||||
int idxLastSlash = path.lastIndexOf('/', idxEnd);
|
||||
if (idxLastSlash < 0)
|
||||
return false; // no last slash, can't possibly be a valid jar/war/zip
|
||||
// look for filename suffix
|
||||
int idxSuffix = path.lastIndexOf('.', idxEnd);
|
||||
if (idxSuffix < 0)
|
||||
return false; // no suffix found, can't possibly be a jar/war/zip
|
||||
if (idxSuffix < idxLastSlash)
|
||||
return false; // last dot is before last slash, eg ("/path.to/something")
|
||||
String suffix = path.substring(idxSuffix, idxEnd).toLowerCase(Locale.ENGLISH);
|
||||
return suffix.equals(".jar") || suffix.equals(".war") || suffix.equals(".zip");
|
||||
}
|
||||
|
||||
/**
|
||||
* Take an arbitrary URI and provide a URI that is suitable for mounting the URI as a Java FileSystem.
|
||||
*
|
||||
* The resulting URI will point to the {@code jar:file://foo.jar!/} said Java Archive (jar, war, or zip)
|
||||
*
|
||||
* @param uri the URI to mutate to a {@code jar:file:...} URI.
|
||||
* @return the <code>jar:${uri_to_java_archive}!/${internal-reference}</code> URI or null if not a Java Archive.
|
||||
* @see #isArchive(URI)
|
||||
*/
|
||||
public static URI toJarFileUri(URI uri)
|
||||
{
|
||||
Objects.requireNonNull(uri, "URI");
|
||||
String scheme = Objects.requireNonNull(uri.getScheme(), "URI scheme");
|
||||
|
||||
if (!isArchive(uri))
|
||||
return null;
|
||||
|
||||
boolean hasInternalReference = uri.getRawSchemeSpecificPart().indexOf("!/") > 0;
|
||||
|
||||
if (scheme.equalsIgnoreCase("jar"))
|
||||
{
|
||||
if (uri.getRawSchemeSpecificPart().startsWith("file:"))
|
||||
{
|
||||
// Looking good as a jar:file: URI
|
||||
if (hasInternalReference)
|
||||
return uri; // is all good, no changes needed.
|
||||
else
|
||||
// add the internal reference indicator to the root of the archive
|
||||
return URI.create(uri.toASCIIString() + "!/");
|
||||
}
|
||||
}
|
||||
else if (scheme.equalsIgnoreCase("file"))
|
||||
{
|
||||
String rawUri = uri.toASCIIString();
|
||||
if (hasInternalReference)
|
||||
return URI.create("jar:" + rawUri);
|
||||
else
|
||||
return URI.create("jar:" + rawUri + "!/");
|
||||
}
|
||||
|
||||
// shouldn't be possible to reach this point
|
||||
throw new IllegalArgumentException("Cannot make %s into `jar:file:` URI".formatted(uri));
|
||||
}
|
||||
|
||||
// TODO: will be removed in MultiReleaseJarFile PR, as AnnotationParser is the only thing using this,
|
||||
// and it doesn't need to recreate the URI that it will already have.
|
||||
public static String toJarPath(String jarFile, String pathInJar)
|
||||
{
|
||||
return "jar:" + jarFile + URIUtil.addPaths("!/", pathInJar);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unwrap a URI to expose its container path reference.
|
||||
*
|
||||
* Take out the container archive name URI from a {@code jar:file:${container-name}!/} URI.
|
||||
*
|
||||
* @param uri the input URI
|
||||
* @return the container String if a {@code jar} scheme, or just the URI untouched.
|
||||
* TODO: reconcile with URIUtil.getJarSource(URI)
|
||||
*/
|
||||
public static URI unwrapContainer(URI uri)
|
||||
{
|
||||
Objects.requireNonNull(uri);
|
||||
|
||||
String scheme = uri.getScheme();
|
||||
if ((scheme == null) || !scheme.equalsIgnoreCase("jar"))
|
||||
return uri;
|
||||
|
||||
String spec = uri.getRawSchemeSpecificPart();
|
||||
int sep = spec.indexOf("!/");
|
||||
if (sep != -1)
|
||||
spec = spec.substring(0, sep);
|
||||
return URI.create(spec);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Convert a String into a URI suitable for use as a Resource.</p>
|
||||
*
|
||||
|
@ -852,6 +719,7 @@ public abstract class Resource implements ResourceFactory
|
|||
return newResource(resolvedUri);
|
||||
}
|
||||
|
||||
// TODO: move to URIUtil
|
||||
private static URI uriResolve(URI uri, String subUriPath) throws IOException
|
||||
{
|
||||
try
|
||||
|
@ -1327,75 +1195,6 @@ public abstract class Resource implements ResourceFactory
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Split a string of references, that may be split with {@code ,}, or {@code ;}, or {@code |} into URIs.
|
||||
* <p>
|
||||
* Each part of the input string could be path references (unix or windows style), or string URI references.
|
||||
* </p>
|
||||
* <p>
|
||||
* If the result of processing the input segment is a java archive, then its resulting URI will be a mountable URI as `jar:file:...!/`.
|
||||
* </p>
|
||||
*
|
||||
* @param str the input string of references
|
||||
* @see #toJarFileUri(URI)
|
||||
*/
|
||||
public static List<URI> split(String str)
|
||||
{
|
||||
List<URI> uris = new ArrayList<>();
|
||||
|
||||
StringTokenizer tokenizer = new StringTokenizer(str, ",;|");
|
||||
while (tokenizer.hasMoreTokens())
|
||||
{
|
||||
String reference = tokenizer.nextToken();
|
||||
try
|
||||
{
|
||||
// Is this a glob reference?
|
||||
if (reference.endsWith("/*") || reference.endsWith("\\*"))
|
||||
{
|
||||
String dir = reference.substring(0, reference.length() - 2);
|
||||
Path pathDir = Paths.get(dir);
|
||||
// Use directory
|
||||
if (Files.exists(pathDir) && Files.isDirectory(pathDir))
|
||||
{
|
||||
// To obtain the list of entries
|
||||
try (Stream<Path> listStream = Files.list(pathDir))
|
||||
{
|
||||
listStream
|
||||
.filter(Files::isRegularFile)
|
||||
.filter(Resource::isArchive)
|
||||
.sorted(Comparator.naturalOrder())
|
||||
.forEach(path -> uris.add(toJarFileUri(path.toUri())));
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new RuntimeException("Unable to process directory glob listing: " + reference, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Simple reference
|
||||
URI refUri = toURI(reference);
|
||||
// Is this a Java Archive that can be mounted?
|
||||
URI jarFileUri = toJarFileUri(refUri);
|
||||
if (jarFileUri != null)
|
||||
// add as mountable URI
|
||||
uris.add(jarFileUri);
|
||||
else
|
||||
// add as normal URI
|
||||
uris.add(refUri);
|
||||
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn("Invalid Resource Reference: " + reference);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
return uris;
|
||||
}
|
||||
|
||||
/**
|
||||
* Certain {@link Resource}s (e.g.: JAR files) require mounting before they can be used. This class is the representation
|
||||
* of such mount allowing the use of more {@link Resource}s.
|
||||
|
|
|
@ -0,0 +1,388 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
|
||||
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Path;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.FS;
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.eclipse.jetty.toolchain.test.jupiter.WorkDir;
|
||||
import org.eclipse.jetty.toolchain.test.jupiter.WorkDirExtension;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.condition.EnabledOnOs;
|
||||
import org.junit.jupiter.api.condition.OS;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
@ExtendWith(WorkDirExtension.class)
|
||||
public class FileIDTest
|
||||
{
|
||||
private static FileSystem metaInfVersionTestFileSystem;
|
||||
public WorkDir workDir;
|
||||
|
||||
@AfterAll
|
||||
public static void closeFileSystems()
|
||||
{
|
||||
IO.close(metaInfVersionTestFileSystem);
|
||||
}
|
||||
|
||||
private Path touchTestPath(String input) throws IOException
|
||||
{
|
||||
return touchTestPath(workDir.getPath(), input);
|
||||
}
|
||||
|
||||
private Path touchTestPath(Path base, String input) throws IOException
|
||||
{
|
||||
Path path = base.resolve(input);
|
||||
if (input.endsWith("/"))
|
||||
{
|
||||
FS.ensureEmpty(path);
|
||||
}
|
||||
else
|
||||
{
|
||||
FS.ensureDirExists(path.getParent());
|
||||
FS.touch(path);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an empty ZipFs FileSystem useful for testing skipMetaInfVersions and isMetaInfVersions rules
|
||||
*/
|
||||
private static FileSystem getMetaInfVersionTestJar() throws IOException
|
||||
{
|
||||
if (metaInfVersionTestFileSystem != null)
|
||||
return metaInfVersionTestFileSystem;
|
||||
|
||||
Path outputJar = MavenTestingUtils.getTargetTestingPath("getMetaInfVersionTestJar").resolve("metainf-versions.jar");
|
||||
FS.ensureEmpty(outputJar.getParent());
|
||||
|
||||
Map<String, String> env = new HashMap<>();
|
||||
env.put("create", "true");
|
||||
|
||||
URI uri = URI.create("jar:" + outputJar.toUri().toASCIIString());
|
||||
metaInfVersionTestFileSystem = FileSystems.newFileSystem(uri, env);
|
||||
|
||||
// this is an empty FileSystem, I don't need to create the files for the skipMetaInfVersions() tests
|
||||
|
||||
return metaInfVersionTestFileSystem;
|
||||
}
|
||||
|
||||
public static Stream<Arguments> basenameCases()
|
||||
{
|
||||
return Stream.of(
|
||||
Arguments.of("foo.xml", "foo"),
|
||||
Arguments.of("dir/foo.xml", "foo"),
|
||||
Arguments.of("dir/foo", "foo"),
|
||||
Arguments.of("foo", "foo")
|
||||
);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("basenameCases")
|
||||
public void testGetBasename(String input, String expected)
|
||||
{
|
||||
Path path = workDir.getEmptyPathDir().resolve(input);
|
||||
String actual = FileID.getBasename(path);
|
||||
assertThat(actual, is(expected));
|
||||
}
|
||||
|
||||
public static Stream<Arguments> containsDirectoryTrueCases()
|
||||
{
|
||||
return Stream.of(
|
||||
Arguments.of("path/to/webapps/root.war", "webapps"),
|
||||
Arguments.of("path/to/webapps/", "webapps"),
|
||||
Arguments.of("META-INF/services/org.eclipse.jetty.FooService", "META-INF"),
|
||||
Arguments.of("META-INF/lib/lib-1.jar", "META-INF"),
|
||||
Arguments.of("deeper/path/to/exploded-jar/META-INF/lib/lib-1.jar", "META-INF")
|
||||
);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("containsDirectoryTrueCases")
|
||||
public void testContainsDirectoryTrue(String input, String dirname) throws IOException
|
||||
{
|
||||
Path path = touchTestPath(input);
|
||||
assertTrue(FileID.containsDirectory(path, dirname), "containsDirectory(%s, \"%s\")".formatted(path, dirname));
|
||||
}
|
||||
|
||||
public static Stream<Arguments> containsDirectoryFalseCases()
|
||||
{
|
||||
return Stream.of(
|
||||
Arguments.of("path/to/webapps/root.war", "WEB-INF"),
|
||||
Arguments.of("path/to/webapps/", "WEB-INF"),
|
||||
Arguments.of("classes/org.eclipse.jetty.util.Foo", "util"),
|
||||
Arguments.of("path/lib-a/foo.txt", "lib")
|
||||
);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("containsDirectoryFalseCases")
|
||||
public void testContainsDirectoryFalse(String input, String dirname) throws IOException
|
||||
{
|
||||
Path path = touchTestPath(input);
|
||||
assertFalse(FileID.containsDirectory(path, dirname), "containsDirectory(%s, \"%s\")".formatted(path, dirname));
|
||||
}
|
||||
|
||||
public static Stream<Arguments> extensionCases()
|
||||
{
|
||||
return Stream.of(
|
||||
Arguments.of("foo.xml", ".xml"),
|
||||
Arguments.of("dir/foo.xml", ".xml"),
|
||||
Arguments.of("foo.jar", ".jar"),
|
||||
Arguments.of("FOO.WAR", ".war"),
|
||||
Arguments.of("Foo.Zip", ".zip")
|
||||
);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("extensionCases")
|
||||
public void testGetExtension(String input, String expected) throws IOException
|
||||
{
|
||||
String actual;
|
||||
|
||||
actual = FileID.getExtension(input);
|
||||
assertThat("getExtension((String) \"%s\")".formatted(input), actual, is(expected));
|
||||
Path path = touchTestPath(input);
|
||||
actual = FileID.getExtension(path);
|
||||
assertThat("getExtension((Path) \"%s\")".formatted(path), actual, is(expected));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {
|
||||
"jar:file:/home/user/project/with.jar/in/path/name",
|
||||
"file:/home/user/project/directory/",
|
||||
"file:/home/user/hello.ear",
|
||||
"/home/user/hello.jar",
|
||||
"/home/user/app.war"
|
||||
})
|
||||
public void testIsArchiveUriFalse(String rawUri)
|
||||
{
|
||||
assertFalse(FileID.isArchive(URI.create(rawUri)), "Should be detected as a JAR URI: " + rawUri);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {
|
||||
"file:/home/user/.m2/repository/com/company/1.0/company-1.0.jar",
|
||||
"jar:file:/home/user/.m2/repository/com/company/1.0/company-1.0.jar!/",
|
||||
"jar:file:/home/user/.m2/repository/com/company/1.0/company-1.0.jar",
|
||||
"file:/home/user/install/jetty-home-12.0.0.zip",
|
||||
"file:/opt/websites/webapps/company.war",
|
||||
"jar:file:/home/user/.m2/repository/jakarta/servlet/jakarta.servlet-api/6.0.0/jakarta.servlet-api-6.0.0.jar!/META-INF/resources"
|
||||
})
|
||||
public void testIsArchiveUriTrue(String rawUri)
|
||||
{
|
||||
assertTrue(FileID.isArchive(URI.create(rawUri)), "Should be detected as a JAR URI: " + rawUri);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {
|
||||
// Doesn't end in class
|
||||
"Foo.txt",
|
||||
// No name
|
||||
".class",
|
||||
// Illegal characters
|
||||
"tab\tcharacter.class",
|
||||
// Doesn't start with identifier
|
||||
"42.class",
|
||||
"org/eclipse/jetty/demo/123Foo.class",
|
||||
// Has spaces
|
||||
"org/eclipse/jetty/demo/A $ Inner.class"
|
||||
})
|
||||
public void testIsClassFileFalse(String input) throws IOException
|
||||
{
|
||||
Path testPath = touchTestPath(input);
|
||||
assertFalse(FileID.isClassFile(testPath), "isClassFile(" + testPath + ")");
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {
|
||||
"Foo.class",
|
||||
"org/eclipse/jetty/demo/Zed.class",
|
||||
"org/eclipse/jetty/demo/Zed$Inner.class"
|
||||
})
|
||||
public void testIsClassFileTrue(String input) throws IOException
|
||||
{
|
||||
Path testPath = touchTestPath(input);
|
||||
assertTrue(FileID.isClassFile(testPath), "isClassFile(" + testPath + ")");
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {
|
||||
"dir/foo.txt",
|
||||
"bar",
|
||||
"zed.png",
|
||||
"a/b/c/d/e/f/g.jpeg"
|
||||
})
|
||||
public void testIsHiddenFalse(String input) throws IOException
|
||||
{
|
||||
Path base = workDir.getEmptyPathDir();
|
||||
Path path = touchTestPath(base, input);
|
||||
assertFalse(FileID.isHidden(base, path), "isHidden(" + input + ")");
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {
|
||||
".dir/foo.txt",
|
||||
".bar",
|
||||
"a/b/c/.d/e/f/g.jpeg"
|
||||
})
|
||||
@EnabledOnOs({OS.LINUX, OS.MAC})
|
||||
public void testIsHiddenTrue(String input) throws IOException
|
||||
{
|
||||
Path base = workDir.getEmptyPathDir();
|
||||
Path path = touchTestPath(base, input);
|
||||
assertTrue(FileID.isHidden(base, path), "isHidden(" + input + ")");
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {
|
||||
"/META-INF/versions/9/foo.txt",
|
||||
"/META-INF/versions/17/org/eclipse/demo/Util.class",
|
||||
"/META-INF/versions/17/WEB-INF/web.xml",
|
||||
"/META-INF/versions/10/module-info.class"
|
||||
})
|
||||
public void testIsMetaInfVersions(String input) throws IOException
|
||||
{
|
||||
FileSystem zipfs = getMetaInfVersionTestJar();
|
||||
Path testPath = zipfs.getPath(input);
|
||||
assertTrue(FileID.isMetaInfVersions(testPath), "isMetaInfVersions(" + testPath + ")");
|
||||
assertFalse(FileID.skipMetaInfVersions(testPath), "skipMetaInfVersions(" + testPath + ")");
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {
|
||||
"foo",
|
||||
"dir/",
|
||||
"zed.txt",
|
||||
"dir/zed.txt",
|
||||
"dir/bar.war/zed.txt",
|
||||
"dir/bar.war/",
|
||||
"cee.jar",
|
||||
"cee.zip"
|
||||
})
|
||||
public void testIsWebArchiveFalse(String input) throws IOException
|
||||
{
|
||||
assertFalse(FileID.isWebArchive(input), "isWebArchive((String) \"%s\")".formatted(input));
|
||||
Path path = touchTestPath(input);
|
||||
assertFalse(FileID.isWebArchive(path), "isWebArchive((Path) \"%s\")".formatted(path));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {
|
||||
"dir/foo.war",
|
||||
"DIR/FOO.WAR",
|
||||
"Dir/Foo.War",
|
||||
"zed.war",
|
||||
"ZED.WAR",
|
||||
"Zed.War"
|
||||
})
|
||||
public void testIsWebArchiveTrue(String input) throws IOException
|
||||
{
|
||||
assertTrue(FileID.isWebArchive(input), "isWebArchive((String) \"%s\")".formatted(input));
|
||||
Path path = touchTestPath(input);
|
||||
assertTrue(FileID.isWebArchive(path), "isWebArchive((Path) \"%s\")".formatted(path));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {
|
||||
"foo.jar",
|
||||
"FOO.war",
|
||||
"Foo.zip",
|
||||
"dir/zed.xml/",
|
||||
"dir/zed.xml/bar.txt"
|
||||
})
|
||||
public void testIsXmlFalse(String input) throws IOException
|
||||
{
|
||||
assertFalse(FileID.isXml(input), "isXml((String) \"%s\")".formatted(input));
|
||||
Path path = touchTestPath(input);
|
||||
assertFalse(FileID.isXml(path), "isXml((Path) \"%s\")".formatted(path));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {
|
||||
"foo.xml",
|
||||
"FOO.XML",
|
||||
"Foo.Xml",
|
||||
"dir/zed.xml",
|
||||
"DIR/ZED.XML",
|
||||
"Dir/Zed.Xml",
|
||||
})
|
||||
public void testIsXmlTrue(String input) throws IOException
|
||||
{
|
||||
assertTrue(FileID.isXml(input), "isXml((String) \"%s\")".formatted(input));
|
||||
Path path = touchTestPath(input);
|
||||
assertTrue(FileID.isXml(path), "isXml((Path) \"%s\")".formatted(path));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {
|
||||
"/root.txt",
|
||||
"/META-INF/MANIFEST.MF",
|
||||
"/META-INF/services/versions/foo.txt",
|
||||
"/META-INF/versions/", // root, no version
|
||||
"/META-INF/versions/Zed.class", // root, no version
|
||||
"/meta-inf/versions/10/Foo.class", // not following case sensitivity rules in Java spec
|
||||
"/meta-inf/VERSIONS/10/Zed.class", // not following case sensitivity rules in Java spec
|
||||
})
|
||||
public void testNotMetaInfVersions(String input) throws IOException
|
||||
{
|
||||
FileSystem zipfs = getMetaInfVersionTestJar();
|
||||
Path testPath = zipfs.getPath(input);
|
||||
assertTrue(FileID.skipMetaInfVersions(testPath), "skipMetaInfVersions(" + testPath + ")");
|
||||
assertFalse(FileID.isMetaInfVersions(testPath), "isMetaInfVersions(" + testPath + ")");
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {
|
||||
"foo/module-info.class",
|
||||
"module-info.class",
|
||||
"Module-Info.Class", // case differences
|
||||
"META-INF/versions/17/module-info.class"
|
||||
})
|
||||
public void testSkipModuleInfoClassFalse(String input) throws IOException
|
||||
{
|
||||
Path path = touchTestPath(input);
|
||||
assertFalse(FileID.skipModuleInfoClass(path), "skipModuleInfoClass(" + path + ")");
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {
|
||||
"foo/Bar.class",
|
||||
"Zed.class",
|
||||
"META-INF/versions/9/foo/Bar.class",
|
||||
"META-INF/versions/9/foo/module-info.class/Zed.class", // as path segment
|
||||
"", // no segment
|
||||
})
|
||||
public void testSkipModuleInfoClassTrue(String input) throws IOException
|
||||
{
|
||||
Path path = touchTestPath(input);
|
||||
assertTrue(FileID.skipModuleInfoClass(path), "skipModuleInfoClass(" + path + ")");
|
||||
}
|
||||
}
|
|
@ -32,34 +32,19 @@ import java.util.stream.Collectors;
|
|||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.FS;
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.eclipse.jetty.toolchain.test.jupiter.WorkDir;
|
||||
import org.eclipse.jetty.toolchain.test.jupiter.WorkDirExtension;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.condition.EnabledOnOs;
|
||||
import org.junit.jupiter.api.condition.OS;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
@ExtendWith(WorkDirExtension.class)
|
||||
public class MultiReleaseJarFileTest
|
||||
{
|
||||
public WorkDir workDir;
|
||||
private static FileSystem metaInfVersionTestFileSystem;
|
||||
|
||||
@AfterAll
|
||||
public static void closeFileSystems()
|
||||
{
|
||||
IO.close(metaInfVersionTestFileSystem);
|
||||
}
|
||||
|
||||
private void createExampleJar(Path outputJar) throws IOException
|
||||
{
|
||||
|
@ -205,154 +190,4 @@ public class MultiReleaseJarFileTest
|
|||
|
||||
assertThat(entries, Matchers.containsInAnyOrder(expected));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {
|
||||
"foo/Bar.class",
|
||||
"Zed.class",
|
||||
"META-INF/versions/9/foo/Bar.class",
|
||||
"META-INF/versions/9/foo/module-info.class/Zed.class", // as path segment
|
||||
"", // no segment
|
||||
})
|
||||
public void testSkipModuleInfoClassTrue(String input)
|
||||
{
|
||||
Path path = workDir.getPath().resolve(input);
|
||||
assertTrue(MultiReleaseJarFile.skipModuleInfoClass(path), "skipModuleInfoClass(" + path + ")");
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {
|
||||
"foo/module-info.class",
|
||||
"module-info.class",
|
||||
"Module-Info.Class", // case differences
|
||||
"META-INF/versions/17/module-info.class"
|
||||
})
|
||||
public void testSkipModuleInfoClassFalse(String input)
|
||||
{
|
||||
Path path = workDir.getPath().resolve(input);
|
||||
assertFalse(MultiReleaseJarFile.skipModuleInfoClass(path), "skipModuleInfoClass(" + path + ")");
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an empty ZipFs FileSystem useful for testing skipMetaInfVersions and isMetaInfVersions rules
|
||||
*/
|
||||
private static FileSystem getMetaInfVersionTestJar() throws IOException
|
||||
{
|
||||
if (metaInfVersionTestFileSystem != null)
|
||||
return metaInfVersionTestFileSystem;
|
||||
|
||||
Path outputJar = MavenTestingUtils.getTargetTestingPath("getMetaInfVersionTestJar").resolve("metainf-versions.jar");
|
||||
FS.ensureEmpty(outputJar.getParent());
|
||||
|
||||
Map<String, String> env = new HashMap<>();
|
||||
env.put("create", "true");
|
||||
|
||||
URI uri = URI.create("jar:" + outputJar.toUri().toASCIIString());
|
||||
metaInfVersionTestFileSystem = FileSystems.newFileSystem(uri, env);
|
||||
|
||||
// this is an empty FileSystem, I don't need to create the files for the skipMetaInfVersions() tests
|
||||
|
||||
return metaInfVersionTestFileSystem;
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {
|
||||
"/root.txt",
|
||||
"/META-INF/MANIFEST.MF",
|
||||
"/META-INF/services/versions/foo.txt",
|
||||
"/META-INF/versions/", // root, no version
|
||||
"/META-INF/versions/Zed.class", // root, no version
|
||||
"/meta-inf/versions/10/Foo.class", // not following case sensitivity rules in Java spec
|
||||
"/meta-inf/VERSIONS/10/Zed.class", // not following case sensitivity rules in Java spec
|
||||
})
|
||||
public void testNotMetaInfVersions(String input) throws IOException
|
||||
{
|
||||
FileSystem zipfs = getMetaInfVersionTestJar();
|
||||
Path testPath = zipfs.getPath(input);
|
||||
assertTrue(MultiReleaseJarFile.skipMetaInfVersions(testPath), "skipMetaInfVersions(" + testPath + ")");
|
||||
assertFalse(MultiReleaseJarFile.isMetaInfVersions(testPath), "isMetaInfVersions(" + testPath + ")");
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {
|
||||
"/META-INF/versions/9/foo.txt",
|
||||
"/META-INF/versions/17/org/eclipse/demo/Util.class",
|
||||
"/META-INF/versions/17/WEB-INF/web.xml",
|
||||
"/META-INF/versions/10/module-info.class"
|
||||
})
|
||||
public void testIsMetaInfVersions(String input) throws IOException
|
||||
{
|
||||
FileSystem zipfs = getMetaInfVersionTestJar();
|
||||
Path testPath = zipfs.getPath(input);
|
||||
assertTrue(MultiReleaseJarFile.isMetaInfVersions(testPath), "isMetaInfVersions(" + testPath + ")");
|
||||
assertFalse(MultiReleaseJarFile.skipMetaInfVersions(testPath), "skipMetaInfVersions(" + testPath + ")");
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {
|
||||
"Foo.class",
|
||||
"org/eclipse/jetty/demo/Zed.class",
|
||||
"org/eclipse/jetty/demo/Zed$Inner.class"
|
||||
})
|
||||
public void testIsClassFileTrue(String input)
|
||||
{
|
||||
Path base = MavenTestingUtils.getTargetTestingPath();
|
||||
Path testPath = base.resolve(input);
|
||||
assertTrue(MultiReleaseJarFile.isClassFile(testPath), "isClassFile(" + testPath + ")");
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {
|
||||
// Doesn't end in class
|
||||
"Foo.txt",
|
||||
// No name
|
||||
".class",
|
||||
// Illegal characters
|
||||
"tab\tcharacter.class",
|
||||
// Doesn't start with identifier
|
||||
"42.class",
|
||||
"org/eclipse/jetty/demo/123Foo.class",
|
||||
// Has spaces
|
||||
"org/eclipse/jetty/demo/A $ Inner.class"
|
||||
})
|
||||
public void testIsClassFileFalse(String input)
|
||||
{
|
||||
Path base = MavenTestingUtils.getTargetTestingPath();
|
||||
Path testPath = base.resolve(input);
|
||||
assertFalse(MultiReleaseJarFile.isClassFile(testPath), "isClassFile(" + testPath + ")");
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {
|
||||
".dir/foo.txt",
|
||||
".bar",
|
||||
"a/b/c/.d/e/f/g.jpeg"
|
||||
})
|
||||
@EnabledOnOs({OS.LINUX, OS.MAC})
|
||||
public void testIsHiddenTrue(String input) throws IOException
|
||||
{
|
||||
Path base = MavenTestingUtils.getTargetTestingPath("testIsHiddenTrue");
|
||||
Path path = base.resolve(input);
|
||||
FS.ensureDirExists(path.getParent());
|
||||
FS.touch(path);
|
||||
|
||||
assertTrue(MultiReleaseJarFile.isHidden(base, path), "isHidden(" + input + ")");
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {
|
||||
"dir/foo.txt",
|
||||
"bar",
|
||||
"zed.png",
|
||||
"a/b/c/d/e/f/g.jpeg"
|
||||
})
|
||||
public void testIsHiddenFalse(String input) throws IOException
|
||||
{
|
||||
Path base = MavenTestingUtils.getTargetTestingPath("testIsHiddenFalse");
|
||||
Path path = base.resolve(input);
|
||||
FS.ensureDirExists(path.getParent());
|
||||
FS.touch(path);
|
||||
|
||||
assertFalse(MultiReleaseJarFile.isHidden(base, path), "isHidden(" + input + ")");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,11 +38,13 @@ import org.junit.jupiter.params.provider.Arguments;
|
|||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
|
@ -518,31 +520,7 @@ public class URIUtilTest
|
|||
assertTrue(URIUtil.equalsIgnoreEncodings(uriA, uriB));
|
||||
}
|
||||
|
||||
public static Stream<Arguments> getJarSourceStringSource()
|
||||
{
|
||||
return Stream.of(
|
||||
// Common cases
|
||||
Arguments.of("file:///tmp/", "file:///tmp/"),
|
||||
Arguments.of("jar:file:///tmp/foo.jar", "file:///tmp/foo.jar"),
|
||||
Arguments.of("jar:file:///tmp/foo.jar!/some/path", "file:///tmp/foo.jar"),
|
||||
// Bad File.toURL cases
|
||||
Arguments.of("file:/tmp/", "file:/tmp/"),
|
||||
Arguments.of("jar:file:/tmp/foo.jar", "file:/tmp/foo.jar"),
|
||||
Arguments.of("jar:file:/tmp/foo.jar!/some/path", "file:/tmp/foo.jar")
|
||||
);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("getJarSourceStringSource")
|
||||
public void testJarSourceURI(String uri, String expectedJarUri)
|
||||
{
|
||||
URI input = URI.create(uri);
|
||||
URI expected = URI.create(expectedJarUri);
|
||||
URI actual = URIUtil.getJarSource(input);
|
||||
assertThat(actual.toASCIIString(), is(expected.toASCIIString()));
|
||||
}
|
||||
|
||||
public static Stream<Arguments> badJavaIoFileUrlCases()
|
||||
public static Stream<Arguments> correctBadFileURICases()
|
||||
{
|
||||
return Stream.of(
|
||||
// Already valid URIs
|
||||
|
@ -573,19 +551,19 @@ public class URIUtilTest
|
|||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("badJavaIoFileUrlCases")
|
||||
public void testFixBadJavaIoFileUrl(String input, String expected)
|
||||
@MethodSource("correctBadFileURICases")
|
||||
public void testCorrectBadFileURI(String input, String expected)
|
||||
{
|
||||
URI inputUri = URI.create(input);
|
||||
URI actualUri = URIUtil.fixBadJavaIoFileUrl(inputUri);
|
||||
URI actualUri = URIUtil.correctBadFileURI(inputUri);
|
||||
URI expectedUri = URI.create(expected);
|
||||
assertThat(actualUri.toASCIIString(), is(expectedUri.toASCIIString()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFixBadJavaIoFileUrlActualFile() throws Exception
|
||||
public void testCorrectBadFileURIActualFile() throws Exception
|
||||
{
|
||||
File file = MavenTestingUtils.getTargetFile("testFixBadJavaIoFileUrlActualFile.txt");
|
||||
File file = MavenTestingUtils.getTargetFile("testCorrectBadFileURIActualFile.txt");
|
||||
FS.touch(file);
|
||||
|
||||
URI expectedUri = file.toPath().toUri();
|
||||
|
@ -599,8 +577,8 @@ public class URIUtilTest
|
|||
assertThat(fileUri.toASCIIString(), not(containsString("://")));
|
||||
assertThat(fileUrlUri.toASCIIString(), not(containsString("://")));
|
||||
|
||||
assertThat(URIUtil.fixBadJavaIoFileUrl(fileUri).toASCIIString(), is(expectedUri.toASCIIString()));
|
||||
assertThat(URIUtil.fixBadJavaIoFileUrl(fileUrlUri).toASCIIString(), is(expectedUri.toASCIIString()));
|
||||
assertThat(URIUtil.correctBadFileURI(fileUri).toASCIIString(), is(expectedUri.toASCIIString()));
|
||||
assertThat(URIUtil.correctBadFileURI(fileUrlUri).toASCIIString(), is(expectedUri.toASCIIString()));
|
||||
}
|
||||
|
||||
public static Stream<Arguments> encodeSpacesSource()
|
||||
|
@ -752,7 +730,7 @@ public class URIUtilTest
|
|||
final String TEST_RESOURCE_JAR = "test-base-resource.jar";
|
||||
List<Arguments> arguments = new ArrayList<>();
|
||||
Path testJar = MavenTestingUtils.getTestResourcePathFile(TEST_RESOURCE_JAR);
|
||||
URI jarFileUri = Resource.toJarFileUri(testJar.toUri());
|
||||
URI jarFileUri = URIUtil.toJarFileUri(testJar.toUri());
|
||||
|
||||
try (Resource.Mount jarMount = Resource.mount(jarFileUri))
|
||||
{
|
||||
|
@ -871,4 +849,174 @@ public class URIUtilTest
|
|||
final URI inputURI = input == null ? null : URI.create(input);
|
||||
assertThrows(IllegalArgumentException.class, () -> URIUtil.uriJarPrefix(inputURI, suffix));
|
||||
}
|
||||
|
||||
public static Stream<Arguments> jarFileUriCases()
|
||||
{
|
||||
List<Arguments> cases = new ArrayList<>();
|
||||
|
||||
String expected = "jar:file:/path/company-1.0.jar!/";
|
||||
cases.add(Arguments.of("file:/path/company-1.0.jar", expected));
|
||||
cases.add(Arguments.of("jar:file:/path/company-1.0.jar", expected));
|
||||
cases.add(Arguments.of("jar:file:/path/company-1.0.jar!/", expected));
|
||||
cases.add(Arguments.of("jar:file:/path/company-1.0.jar!/META-INF/services", expected + "META-INF/services"));
|
||||
|
||||
expected = "jar:file:/opt/jetty/webapps/app.war!/";
|
||||
cases.add(Arguments.of("file:/opt/jetty/webapps/app.war", expected));
|
||||
cases.add(Arguments.of("jar:file:/opt/jetty/webapps/app.war", expected));
|
||||
cases.add(Arguments.of("jar:file:/opt/jetty/webapps/app.war!/", expected));
|
||||
cases.add(Arguments.of("jar:file:/opt/jetty/webapps/app.war!/WEB-INF/classes", expected + "WEB-INF/classes"));
|
||||
|
||||
return cases.stream();
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("jarFileUriCases")
|
||||
public void testToJarFileUri(String inputRawUri, String expectedRawUri)
|
||||
{
|
||||
URI actual = URIUtil.toJarFileUri(URI.create(inputRawUri));
|
||||
assertNotNull(actual);
|
||||
assertThat(actual.toASCIIString(), is(expectedRawUri));
|
||||
}
|
||||
|
||||
public static Stream<Arguments> unwrapContainerCases()
|
||||
{
|
||||
return Stream.of(
|
||||
Arguments.of("/path/to/foo.jar", "file:///path/to/foo.jar"),
|
||||
Arguments.of("/path/to/bogus.txt", "file:///path/to/bogus.txt"),
|
||||
Arguments.of("file:///path/to/zed.jar", "file:///path/to/zed.jar"),
|
||||
Arguments.of("jar:file:///path/to/bar.jar!/internal.txt", "file:///path/to/bar.jar")
|
||||
);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("unwrapContainerCases")
|
||||
public void testUnwrapContainer(String inputRawUri, String expected)
|
||||
{
|
||||
URI input = Resource.toURI(inputRawUri);
|
||||
URI actual = URIUtil.unwrapContainer(input);
|
||||
assertThat(actual.toASCIIString(), is(expected));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSplitSingleJar()
|
||||
{
|
||||
// Bad java file.uri syntax
|
||||
String input = "file:/home/user/lib/acme.jar";
|
||||
List<URI> uris = URIUtil.split(input);
|
||||
String expected = String.format("jar:%s!/", input);
|
||||
assertThat(uris.get(0).toString(), is(expected));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSplitSinglePath()
|
||||
{
|
||||
String input = "/home/user/lib/acme.jar";
|
||||
List<URI> uris = URIUtil.split(input);
|
||||
String expected = String.format("jar:file://%s!/", input);
|
||||
assertThat(uris.get(0).toString(), is(expected));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSplitOnComma()
|
||||
{
|
||||
Path base = workDir.getEmptyPathDir();
|
||||
Path dir = base.resolve("dir");
|
||||
FS.ensureDirExists(dir);
|
||||
Path foo = dir.resolve("foo");
|
||||
FS.ensureDirExists(foo);
|
||||
Path bar = dir.resolve("bar");
|
||||
FS.ensureDirExists(bar);
|
||||
|
||||
// This represents the user-space raw configuration
|
||||
String config = String.format("%s,%s,%s", dir, foo, bar);
|
||||
|
||||
// Split using commas
|
||||
List<URI> uris = URIUtil.split(config);
|
||||
|
||||
URI[] expected = new URI[] {
|
||||
dir.toUri(),
|
||||
foo.toUri(),
|
||||
bar.toUri()
|
||||
};
|
||||
assertThat(uris, contains(expected));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSplitOnPipe()
|
||||
{
|
||||
Path base = workDir.getEmptyPathDir();
|
||||
Path dir = base.resolve("dir");
|
||||
FS.ensureDirExists(dir);
|
||||
Path foo = dir.resolve("foo");
|
||||
FS.ensureDirExists(foo);
|
||||
Path bar = dir.resolve("bar");
|
||||
FS.ensureDirExists(bar);
|
||||
|
||||
// This represents the user-space raw configuration
|
||||
String config = String.format("%s|%s|%s", dir, foo, bar);
|
||||
|
||||
// Split using commas
|
||||
List<URI> uris = URIUtil.split(config);
|
||||
|
||||
URI[] expected = new URI[] {
|
||||
dir.toUri(),
|
||||
foo.toUri(),
|
||||
bar.toUri()
|
||||
};
|
||||
assertThat(uris, contains(expected));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSplitOnSemicolon()
|
||||
{
|
||||
Path base = workDir.getEmptyPathDir();
|
||||
Path dir = base.resolve("dir");
|
||||
FS.ensureDirExists(dir);
|
||||
Path foo = dir.resolve("foo");
|
||||
FS.ensureDirExists(foo);
|
||||
Path bar = dir.resolve("bar");
|
||||
FS.ensureDirExists(bar);
|
||||
|
||||
// This represents the user-space raw configuration
|
||||
String config = String.format("%s;%s;%s", dir, foo, bar);
|
||||
|
||||
// Split using commas
|
||||
List<URI> uris = URIUtil.split(config);
|
||||
|
||||
URI[] expected = new URI[] {
|
||||
dir.toUri(),
|
||||
foo.toUri(),
|
||||
bar.toUri()
|
||||
};
|
||||
assertThat(uris, contains(expected));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSplitOnPipeWithGlob() throws IOException
|
||||
{
|
||||
Path base = workDir.getEmptyPathDir();
|
||||
Path dir = base.resolve("dir");
|
||||
FS.ensureDirExists(dir);
|
||||
Path foo = dir.resolve("foo");
|
||||
FS.ensureDirExists(foo);
|
||||
Path bar = dir.resolve("bar");
|
||||
FS.ensureDirExists(bar);
|
||||
FS.touch(bar.resolve("lib-foo.jar"));
|
||||
FS.touch(bar.resolve("lib-zed.zip"));
|
||||
|
||||
// This represents the user-space raw configuration with a glob
|
||||
String config = String.format("%s;%s;%s%s*", dir, foo, bar, File.separator);
|
||||
|
||||
// Split using commas
|
||||
List<URI> uris = URIUtil.split(config);
|
||||
|
||||
URI[] expected = new URI[] {
|
||||
dir.toUri(),
|
||||
foo.toUri(),
|
||||
// Should see the two archives as `jar:file:` URI entries
|
||||
URIUtil.toJarFileUri(bar.resolve("lib-foo.jar").toUri()),
|
||||
URIUtil.toJarFileUri(bar.resolve("lib-zed.zip").toUri())
|
||||
};
|
||||
assertThat(uris, contains(expected));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ import org.eclipse.jetty.toolchain.test.FS;
|
|||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.eclipse.jetty.toolchain.test.jupiter.WorkDir;
|
||||
import org.eclipse.jetty.toolchain.test.jupiter.WorkDirExtension;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
|
@ -172,7 +173,7 @@ public class ResourceCollectionTest
|
|||
String config = String.format("%s,%s,%s", dir, foo, bar);
|
||||
|
||||
// To use this, we need to split it (and optionally honor globs)
|
||||
List<URI> uris = Resource.split(config);
|
||||
List<URI> uris = URIUtil.split(config);
|
||||
// Now let's create a ResourceCollection from this list of URIs
|
||||
// Since this is user space, we cannot know ahead of time what
|
||||
// this list contains, so we mount because we assume there
|
||||
|
@ -201,7 +202,7 @@ public class ResourceCollectionTest
|
|||
String config = String.format("%s;%s;%s%s*", dir, foo, bar, File.separator);
|
||||
|
||||
// To use this, we need to split it (and optionally honor globs)
|
||||
List<URI> uris = Resource.split(config);
|
||||
List<URI> uris = URIUtil.split(config);
|
||||
// Now let's create a ResourceCollection from this list of URIs
|
||||
// Since this is user space, we cannot know ahead of time what
|
||||
// this list contains, so we mount because we assume there
|
||||
|
|
|
@ -30,6 +30,7 @@ import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
|||
import org.eclipse.jetty.toolchain.test.jupiter.WorkDir;
|
||||
import org.eclipse.jetty.toolchain.test.jupiter.WorkDirExtension;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.Assumptions;
|
||||
|
@ -41,15 +42,11 @@ import org.junit.jupiter.api.extension.ExtendWith;
|
|||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.startsWith;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
@ -409,205 +406,8 @@ public class ResourceTest
|
|||
public void testJarReferenceAsURINotYetMounted() throws Exception
|
||||
{
|
||||
Path jar = MavenTestingUtils.getTestResourcePathFile("example.jar");
|
||||
URI jarFileUri = Resource.toJarFileUri(jar.toUri());
|
||||
URI jarFileUri = URIUtil.toJarFileUri(jar.toUri());
|
||||
assertNotNull(jarFileUri);
|
||||
assertThrows(IllegalStateException.class, () -> Resource.newResource(jarFileUri));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {
|
||||
"file:/home/user/.m2/repository/com/company/1.0/company-1.0.jar",
|
||||
"jar:file:/home/user/.m2/repository/com/company/1.0/company-1.0.jar!/",
|
||||
"jar:file:/home/user/.m2/repository/com/company/1.0/company-1.0.jar",
|
||||
"file:/home/user/install/jetty-home-12.0.0.zip",
|
||||
"file:/opt/websites/webapps/company.war",
|
||||
"jar:file:/home/user/.m2/repository/jakarta/servlet/jakarta.servlet-api/6.0.0/jakarta.servlet-api-6.0.0.jar!/META-INF/resources"
|
||||
})
|
||||
public void testIsArchiveUriTrue(String rawUri)
|
||||
{
|
||||
assertTrue(Resource.isArchive(URI.create(rawUri)), "Should be detected as a JAR URI: " + rawUri);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {
|
||||
"jar:file:/home/user/project/with.jar/in/path/name",
|
||||
"file:/home/user/project/directory/",
|
||||
"file:/home/user/hello.ear",
|
||||
"/home/user/hello.jar",
|
||||
"/home/user/app.war"
|
||||
})
|
||||
public void testIsArchiveUriFalse(String rawUri)
|
||||
{
|
||||
assertFalse(Resource.isArchive(URI.create(rawUri)), "Should be detected as a JAR URI: " + rawUri);
|
||||
}
|
||||
|
||||
public static Stream<Arguments> jarFileUriCases()
|
||||
{
|
||||
List<Arguments> cases = new ArrayList<>();
|
||||
|
||||
String expected = "jar:file:/path/company-1.0.jar!/";
|
||||
cases.add(Arguments.of("file:/path/company-1.0.jar", expected));
|
||||
cases.add(Arguments.of("jar:file:/path/company-1.0.jar", expected));
|
||||
cases.add(Arguments.of("jar:file:/path/company-1.0.jar!/", expected));
|
||||
cases.add(Arguments.of("jar:file:/path/company-1.0.jar!/META-INF/services", expected + "META-INF/services"));
|
||||
|
||||
expected = "jar:file:/opt/jetty/webapps/app.war!/";
|
||||
cases.add(Arguments.of("file:/opt/jetty/webapps/app.war", expected));
|
||||
cases.add(Arguments.of("jar:file:/opt/jetty/webapps/app.war", expected));
|
||||
cases.add(Arguments.of("jar:file:/opt/jetty/webapps/app.war!/", expected));
|
||||
cases.add(Arguments.of("jar:file:/opt/jetty/webapps/app.war!/WEB-INF/classes", expected + "WEB-INF/classes"));
|
||||
|
||||
return cases.stream();
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("jarFileUriCases")
|
||||
public void testToJarFileUri(String inputRawUri, String expectedRawUri)
|
||||
{
|
||||
URI actual = Resource.toJarFileUri(URI.create(inputRawUri));
|
||||
assertNotNull(actual);
|
||||
assertThat(actual.toASCIIString(), is(expectedRawUri));
|
||||
}
|
||||
|
||||
public static Stream<Arguments> unwrapContainerCases()
|
||||
{
|
||||
return Stream.of(
|
||||
Arguments.of("/path/to/foo.jar", "file:///path/to/foo.jar"),
|
||||
Arguments.of("/path/to/bogus.txt", "file:///path/to/bogus.txt"),
|
||||
Arguments.of("file:///path/to/zed.jar", "file:///path/to/zed.jar"),
|
||||
Arguments.of("jar:file:///path/to/bar.jar!/internal.txt", "file:///path/to/bar.jar")
|
||||
);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("unwrapContainerCases")
|
||||
public void testUnwrapContainer(String inputRawUri, String expected)
|
||||
{
|
||||
URI input = Resource.toURI(inputRawUri);
|
||||
URI actual = Resource.unwrapContainer(input);
|
||||
assertThat(actual.toASCIIString(), is(expected));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSplitSingleJar()
|
||||
{
|
||||
// Bad java file.uri syntax
|
||||
String input = "file:/home/user/lib/acme.jar";
|
||||
List<URI> uris = Resource.split(input);
|
||||
String expected = String.format("jar:%s!/", input);
|
||||
assertThat(uris.get(0).toString(), is(expected));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSplitSinglePath()
|
||||
{
|
||||
String input = "/home/user/lib/acme.jar";
|
||||
List<URI> uris = Resource.split(input);
|
||||
String expected = String.format("jar:file://%s!/", input);
|
||||
assertThat(uris.get(0).toString(), is(expected));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSplitOnComma()
|
||||
{
|
||||
Path base = workDir.getEmptyPathDir();
|
||||
Path dir = base.resolve("dir");
|
||||
FS.ensureDirExists(dir);
|
||||
Path foo = dir.resolve("foo");
|
||||
FS.ensureDirExists(foo);
|
||||
Path bar = dir.resolve("bar");
|
||||
FS.ensureDirExists(bar);
|
||||
|
||||
// This represents the user-space raw configuration
|
||||
String config = String.format("%s,%s,%s", dir, foo, bar);
|
||||
|
||||
// Split using commas
|
||||
List<URI> uris = Resource.split(config);
|
||||
|
||||
URI[] expected = new URI[] {
|
||||
dir.toUri(),
|
||||
foo.toUri(),
|
||||
bar.toUri()
|
||||
};
|
||||
assertThat(uris, contains(expected));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSplitOnPipe()
|
||||
{
|
||||
Path base = workDir.getEmptyPathDir();
|
||||
Path dir = base.resolve("dir");
|
||||
FS.ensureDirExists(dir);
|
||||
Path foo = dir.resolve("foo");
|
||||
FS.ensureDirExists(foo);
|
||||
Path bar = dir.resolve("bar");
|
||||
FS.ensureDirExists(bar);
|
||||
|
||||
// This represents the user-space raw configuration
|
||||
String config = String.format("%s|%s|%s", dir, foo, bar);
|
||||
|
||||
// Split using commas
|
||||
List<URI> uris = Resource.split(config);
|
||||
|
||||
URI[] expected = new URI[] {
|
||||
dir.toUri(),
|
||||
foo.toUri(),
|
||||
bar.toUri()
|
||||
};
|
||||
assertThat(uris, contains(expected));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSplitOnSemicolon()
|
||||
{
|
||||
Path base = workDir.getEmptyPathDir();
|
||||
Path dir = base.resolve("dir");
|
||||
FS.ensureDirExists(dir);
|
||||
Path foo = dir.resolve("foo");
|
||||
FS.ensureDirExists(foo);
|
||||
Path bar = dir.resolve("bar");
|
||||
FS.ensureDirExists(bar);
|
||||
|
||||
// This represents the user-space raw configuration
|
||||
String config = String.format("%s;%s;%s", dir, foo, bar);
|
||||
|
||||
// Split using commas
|
||||
List<URI> uris = Resource.split(config);
|
||||
|
||||
URI[] expected = new URI[] {
|
||||
dir.toUri(),
|
||||
foo.toUri(),
|
||||
bar.toUri()
|
||||
};
|
||||
assertThat(uris, contains(expected));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSplitOnPipeWithGlob() throws IOException
|
||||
{
|
||||
Path base = workDir.getEmptyPathDir();
|
||||
Path dir = base.resolve("dir");
|
||||
FS.ensureDirExists(dir);
|
||||
Path foo = dir.resolve("foo");
|
||||
FS.ensureDirExists(foo);
|
||||
Path bar = dir.resolve("bar");
|
||||
FS.ensureDirExists(bar);
|
||||
FS.touch(bar.resolve("lib-foo.jar"));
|
||||
FS.touch(bar.resolve("lib-zed.zip"));
|
||||
|
||||
// This represents the user-space raw configuration with a glob
|
||||
String config = String.format("%s;%s;%s%s*", dir, foo, bar, File.separator);
|
||||
|
||||
// Split using commas
|
||||
List<URI> uris = Resource.split(config);
|
||||
|
||||
URI[] expected = new URI[] {
|
||||
dir.toUri(),
|
||||
foo.toUri(),
|
||||
// Should see the two archives as `jar:file:` URI entries
|
||||
Resource.toJarFileUri(bar.resolve("lib-foo.jar").toUri()),
|
||||
Resource.toJarFileUri(bar.resolve("lib-zed.zip").toUri())
|
||||
};
|
||||
assertThat(uris, contains(expected));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jetty.util.ExceptionUtil;
|
||||
import org.eclipse.jetty.util.FileID;
|
||||
import org.eclipse.jetty.util.Loader;
|
||||
import org.eclipse.jetty.util.MultiReleaseJarFile;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
|
@ -816,8 +817,7 @@ public class AnnotationParser
|
|||
if (jarResource == null)
|
||||
return;
|
||||
|
||||
// TODO: what if the input is "FOO.JAR" or "Bar.Jar" ? - need to use FileID.isArchive() or FileID.isJar()
|
||||
if (jarResource.toString().endsWith(".jar"))
|
||||
if (FileID.isJavaArchive(jarResource.getPath()))
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Scanning jar {}", jarResource);
|
||||
|
@ -826,9 +826,9 @@ public class AnnotationParser
|
|||
try (MultiReleaseJarFile jarFile = new MultiReleaseJarFile(jarResource.getPath());
|
||||
Stream<Path> jarEntryStream = jarFile.stream()
|
||||
.filter(Files::isRegularFile)
|
||||
.filter(MultiReleaseJarFile::skipModuleInfoClass)
|
||||
.filter(MultiReleaseJarFile::skipMetaInfVersions)
|
||||
.filter(MultiReleaseJarFile::isClassFile)
|
||||
.filter(FileID::skipModuleInfoClass)
|
||||
.filter(FileID::skipMetaInfVersions)
|
||||
.filter(FileID::isClassFile)
|
||||
)
|
||||
{
|
||||
jarEntryStream.forEach(e ->
|
||||
|
@ -917,7 +917,7 @@ public class AnnotationParser
|
|||
*
|
||||
* @param name the class file name
|
||||
* @return whether the class file name is valid
|
||||
* TODO: does multiple things, we should be able to move this FileID in future PR
|
||||
* TODO: does multiple things, we should be able to eliminate this in future PR by consolidating the ZipFS and Directory scanning behaviors into a single Files.walk() stream
|
||||
*/
|
||||
public boolean isValidClassFileName(String name)
|
||||
{
|
||||
|
@ -926,7 +926,7 @@ public class AnnotationParser
|
|||
return false;
|
||||
|
||||
// skip anything that is not a class file
|
||||
// TODO: exists in MultiReleaseJarFile.isClassFile(Path)
|
||||
// TODO: exists in FileID.isClassFile(Path) use consistently in both ZipFS and Directory cases
|
||||
String lc = name.toLowerCase(Locale.ENGLISH);
|
||||
if (!lc.endsWith(".class"))
|
||||
{
|
||||
|
@ -935,7 +935,7 @@ public class AnnotationParser
|
|||
return false;
|
||||
}
|
||||
|
||||
// TODO: exists in MultiReleaseJarFile.notModuleInfoClass(Path)
|
||||
// TODO: exists in FileID.notModuleInfoClass(Path) use consistently in both ZipFS and Directory cases
|
||||
if (lc.equals("module-info.class"))
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
|
@ -944,7 +944,7 @@ public class AnnotationParser
|
|||
}
|
||||
|
||||
// skip any classfiles that are not a valid java identifier
|
||||
// TODO: exists in MultiReleaseJarFile.isClassFile(Path)
|
||||
// TODO: exists in FileID.isClassFile(Path) use consistently in both ZipFS and Directory cases
|
||||
int c0 = 0;
|
||||
int ldir = name.lastIndexOf('/', name.length() - 6);
|
||||
c0 = (ldir > -1 ? ldir + 1 : c0);
|
||||
|
@ -963,7 +963,7 @@ public class AnnotationParser
|
|||
*
|
||||
* @param path the class file path
|
||||
* @return whether the class file path is valid
|
||||
* TODO: remove, handled by MultiReleaseJarFile.skipHiddenDirs
|
||||
* TODO: remove, handled by FileID.skipHiddenDirs
|
||||
*/
|
||||
public boolean isValidClassFilePath(String path)
|
||||
{
|
||||
|
|
|
@ -294,7 +294,7 @@ public class MavenWebAppContext extends WebAppContext
|
|||
_webInfJars.forEach(f ->
|
||||
{
|
||||
// ensure our JAR file references are `jar:file:...` URI references
|
||||
URI jarFileUri = Resource.toJarFileUri(f.toURI());
|
||||
URI jarFileUri = URIUtil.toJarFileUri(f.toURI());
|
||||
// else use file uri as-is
|
||||
_classpathUris.add(Objects.requireNonNullElseGet(jarFileUri, f::toURI));
|
||||
});
|
||||
|
|
|
@ -28,6 +28,7 @@ import java.util.stream.Collectors;
|
|||
import org.eclipse.jetty.ee10.quickstart.QuickStartConfiguration;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.util.resource.ResourceCollection;
|
||||
import org.eclipse.jetty.xml.XmlConfiguration;
|
||||
|
@ -224,7 +225,7 @@ public class WebAppPropertyConverter
|
|||
if (!StringUtil.isBlank(str))
|
||||
{
|
||||
// This is a use provided list of overlays, which could have mountable entries.
|
||||
List<URI> uris = Resource.split(str);
|
||||
List<URI> uris = URIUtil.split(str);
|
||||
// TODO: need a better place to close/release this mount.
|
||||
Resource.Mount mount = Resource.mountCollection(uris);
|
||||
webApp.addBean(mount); // let jetty-core ContextHandler.doStop() release mount
|
||||
|
|
|
@ -23,6 +23,7 @@ import org.eclipse.jetty.ee10.plus.webapp.PlusConfiguration;
|
|||
import org.eclipse.jetty.ee10.webapp.MetaInfConfiguration;
|
||||
import org.eclipse.jetty.ee10.webapp.WebAppContext;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.xml.XmlConfiguration;
|
||||
import org.slf4j.Logger;
|
||||
|
@ -95,7 +96,7 @@ public class PreconfigureQuickStartWar
|
|||
if (!dir.exists())
|
||||
Files.createDirectories(dir.getPath());
|
||||
|
||||
URI jarUri = Resource.toJarFileUri(war.getURI());
|
||||
URI jarUri = URIUtil.toJarFileUri(war.getURI());
|
||||
try (Resource.Mount warMount = Resource.mount(jarUri))
|
||||
{
|
||||
// unpack contents of war to directory
|
||||
|
|
|
@ -738,7 +738,7 @@ public class ClassMatcher extends AbstractSet<String>
|
|||
{
|
||||
try
|
||||
{
|
||||
return URIUtil.getJarSource(url.toURI());
|
||||
return URIUtil.unwrapContainer(url.toURI());
|
||||
}
|
||||
catch (URISyntaxException ignored)
|
||||
{
|
||||
|
|
|
@ -23,6 +23,7 @@ import java.util.Map;
|
|||
import java.util.Objects;
|
||||
|
||||
import jakarta.servlet.ServletContext;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.util.thread.AutoLock;
|
||||
import org.slf4j.Logger;
|
||||
|
@ -458,7 +459,7 @@ public class MetaData
|
|||
List<String> orderedLibs = new ArrayList<>();
|
||||
for (Resource jar: orderedWebInfJars)
|
||||
{
|
||||
URI uri = Resource.unwrapContainer(jar.getURI());
|
||||
URI uri = URIUtil.unwrapContainer(jar.getURI());
|
||||
orderedLibs.add(uri.getPath());
|
||||
}
|
||||
context.setAttribute(ServletContext.ORDERED_LIBS, Collections.unmodifiableList(orderedLibs));
|
||||
|
|
|
@ -36,6 +36,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jetty.util.FileID;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.PatternMatcher;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
|
@ -685,7 +686,7 @@ public class MetaInfConfiguration extends AbstractConfiguration
|
|||
|
||||
try (Stream<Path> entries = Files.walk(dir)
|
||||
.filter(Files::isRegularFile)
|
||||
.filter(MetaInfConfiguration::isTldFile))
|
||||
.filter(path -> FileID.isTldFile(path)))
|
||||
{
|
||||
Iterator<Path> iter = entries.iterator();
|
||||
while (iter.hasNext())
|
||||
|
@ -714,7 +715,7 @@ public class MetaInfConfiguration extends AbstractConfiguration
|
|||
try (Stream<Path> stream = Files.walk(mount.root().getPath()))
|
||||
{
|
||||
Iterator<Path> it = stream
|
||||
.filter(MetaInfConfiguration::isTldFile)
|
||||
.filter(path -> FileID.isTldFile(path))
|
||||
.iterator();
|
||||
while (it.hasNext())
|
||||
{
|
||||
|
@ -725,18 +726,6 @@ public class MetaInfConfiguration extends AbstractConfiguration
|
|||
return tlds;
|
||||
}
|
||||
|
||||
private static boolean isTldFile(Path path)
|
||||
{
|
||||
if (!Files.isRegularFile(path))
|
||||
return false;
|
||||
if (path.getNameCount() < 2)
|
||||
return false;
|
||||
if (!path.getName(0).toString().equalsIgnoreCase("META-INF"))
|
||||
return false;
|
||||
String filename = path.getFileName().toString();
|
||||
return filename.toLowerCase(Locale.ENGLISH).endsWith(".tld");
|
||||
}
|
||||
|
||||
protected List<Resource> findClassDirs(WebAppContext context)
|
||||
throws Exception
|
||||
{
|
||||
|
@ -884,6 +873,6 @@ public class MetaInfConfiguration extends AbstractConfiguration
|
|||
|
||||
private boolean isFileSupported(Resource resource)
|
||||
{
|
||||
return Resource.isArchive(resource.getURI());
|
||||
return FileID.isArchive(resource.getURI());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,6 +41,7 @@ import org.eclipse.jetty.util.ClassVisibilityChecker;
|
|||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.TypeUtil;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.util.resource.ResourceCollection;
|
||||
import org.slf4j.Logger;
|
||||
|
@ -271,7 +272,7 @@ public class WebAppClassLoader extends URLClassLoader implements ClassVisibility
|
|||
if (classPath == null)
|
||||
return;
|
||||
|
||||
List<URI> uris = Resource.split(classPath);
|
||||
List<URI> uris = URIUtil.split(classPath);
|
||||
_mountedExtraClassPath = Resource.mountCollection(uris);
|
||||
|
||||
ResourceCollection rc = (ResourceCollection)_mountedExtraClassPath.root();
|
||||
|
@ -324,7 +325,7 @@ public class WebAppClassLoader extends URLClassLoader implements ClassVisibility
|
|||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("addJar - {}", jar);
|
||||
URI jarUri = Resource.toJarFileUri(jar.toUri());
|
||||
URI jarUri = URIUtil.toJarFileUri(jar.toUri());
|
||||
addClassPath(jarUri.toASCIIString());
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
|
|
@ -1244,7 +1244,7 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
|
|||
*/
|
||||
public void setExtraClasspath(String extraClasspath)
|
||||
{
|
||||
List<URI> uris = Resource.split(extraClasspath);
|
||||
List<URI> uris = URIUtil.split(extraClasspath);
|
||||
Resource.Mount mount = Resource.mountCollection(uris);
|
||||
addBean(mount); // let doStop() cleanup mount
|
||||
setExtraClasspath((ResourceCollection)mount.root());
|
||||
|
|
|
@ -44,6 +44,8 @@ import org.eclipse.jetty.toolchain.test.FS;
|
|||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.eclipse.jetty.toolchain.test.jupiter.WorkDir;
|
||||
import org.eclipse.jetty.toolchain.test.jupiter.WorkDirExtension;
|
||||
import org.eclipse.jetty.util.FileID;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
import org.eclipse.jetty.util.component.LifeCycle;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.hamcrest.Matchers;
|
||||
|
@ -517,10 +519,10 @@ public class WebAppContextTest
|
|||
{
|
||||
expectedUris = s
|
||||
.filter(Files::isRegularFile)
|
||||
.filter((path) -> path.getFileName().toString().endsWith(".jar"))
|
||||
.filter(FileID::isJavaArchive)
|
||||
.sorted(Comparator.naturalOrder())
|
||||
.map(Path::toUri)
|
||||
.map(Resource::toJarFileUri)
|
||||
.map(URIUtil::toJarFileUri)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
List<URI> actualURIs = new ArrayList<>();
|
||||
|
|
|
@ -31,6 +31,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jetty.util.ExceptionUtil;
|
||||
import org.eclipse.jetty.util.FileID;
|
||||
import org.eclipse.jetty.util.Loader;
|
||||
import org.eclipse.jetty.util.MultiReleaseJarFile;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
|
@ -817,8 +818,7 @@ public class AnnotationParser
|
|||
if (jarResource == null)
|
||||
return;
|
||||
|
||||
// TODO: what if the input is "FOO.JAR" or "Bar.Jar" ? - need to use FileID.isArchive() or FileID.isJar()
|
||||
if (jarResource.toString().endsWith(".jar"))
|
||||
if (FileID.isJavaArchive(jarResource.getPath()))
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Scanning jar {}", jarResource);
|
||||
|
@ -827,9 +827,9 @@ public class AnnotationParser
|
|||
try (MultiReleaseJarFile jarFile = new MultiReleaseJarFile(jarResource.getPath());
|
||||
Stream<Path> jarEntryStream = jarFile.stream()
|
||||
.filter(Files::isRegularFile)
|
||||
.filter(MultiReleaseJarFile::skipModuleInfoClass)
|
||||
.filter(MultiReleaseJarFile::skipMetaInfVersions)
|
||||
.filter(MultiReleaseJarFile::isClassFile))
|
||||
.filter(FileID::skipModuleInfoClass)
|
||||
.filter(FileID::skipMetaInfVersions)
|
||||
.filter(FileID::isClassFile))
|
||||
{
|
||||
jarEntryStream.forEach(e ->
|
||||
{
|
||||
|
@ -915,7 +915,7 @@ public class AnnotationParser
|
|||
*
|
||||
* @param name the class file name
|
||||
* @return whether the class file name is valid
|
||||
* TODO: does multiple things, we should be able to move this FileID in future PR
|
||||
* TODO: does multiple things, we should be able to eliminate this in future PR by consolidating the ZipFS and Directory scanning behaviors into a single Files.walk() stream
|
||||
*/
|
||||
public boolean isValidClassFileName(String name)
|
||||
{
|
||||
|
@ -924,7 +924,7 @@ public class AnnotationParser
|
|||
return false;
|
||||
|
||||
//skip anything that is not a class file
|
||||
// TODO: exists in MultiReleaseJarFile.isClassFile(Path)
|
||||
// TODO: exists in FileID.isClassFile(Path) use consistently in both ZipFS and Directory cases
|
||||
String lc = name.toLowerCase(Locale.ENGLISH);
|
||||
if (!lc.endsWith(".class"))
|
||||
{
|
||||
|
@ -933,7 +933,7 @@ public class AnnotationParser
|
|||
return false;
|
||||
}
|
||||
|
||||
// TODO: exists in MultiReleaseJarFile.notModuleInfoClass(Path)
|
||||
// TODO: exists in FileID.notModuleInfoClass(Path) use consistently in both ZipFS and Directory cases
|
||||
if (lc.equals("module-info.class"))
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
|
@ -942,7 +942,7 @@ public class AnnotationParser
|
|||
}
|
||||
|
||||
//skip any classfiles that are not a valid java identifier
|
||||
// TODO: exists in MultiReleaseJarFile.isClassFile(Path)
|
||||
// TODO: exists in FileID.isClassFile(Path) use consistently in both ZipFS and Directory cases
|
||||
int c0 = 0;
|
||||
int ldir = name.lastIndexOf('/', name.length() - 6);
|
||||
c0 = (ldir > -1 ? ldir + 1 : c0);
|
||||
|
@ -961,7 +961,7 @@ public class AnnotationParser
|
|||
*
|
||||
* @param path the class file path
|
||||
* @return whether the class file path is valid
|
||||
* TODO: remove, handled by MultiReleaseJarFile.skipHiddenDirs
|
||||
* TODO: remove, handled by FileID.skipHiddenDirs
|
||||
*/
|
||||
public boolean isValidClassFilePath(String path)
|
||||
{
|
||||
|
|
|
@ -294,7 +294,7 @@ public class MavenWebAppContext extends WebAppContext
|
|||
_webInfJars.forEach(f ->
|
||||
{
|
||||
// ensure our JAR file references are `jar:file:...` URI references
|
||||
URI jarFileUri = Resource.toJarFileUri(f.toURI());
|
||||
URI jarFileUri = URIUtil.toJarFileUri(f.toURI());
|
||||
// else use file uri as-is
|
||||
_classpathUris.add(Objects.requireNonNullElseGet(jarFileUri, f::toURI));
|
||||
});
|
||||
|
|
|
@ -28,6 +28,7 @@ import java.util.stream.Collectors;
|
|||
import org.eclipse.jetty.ee9.quickstart.QuickStartConfiguration;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.util.resource.ResourceCollection;
|
||||
import org.eclipse.jetty.xml.XmlConfiguration;
|
||||
|
@ -224,7 +225,7 @@ public class WebAppPropertyConverter
|
|||
if (!StringUtil.isBlank(str))
|
||||
{
|
||||
// This is a use provided list of overlays, which could have mountable entries.
|
||||
List<URI> uris = Resource.split(str);
|
||||
List<URI> uris = URIUtil.split(str);
|
||||
// TODO: need a better place to close/release this mount.
|
||||
Resource.Mount mount = Resource.mountCollection(uris);
|
||||
webApp.addBean(mount); // let ee9 ContextHandler.doStop() release mount
|
||||
|
|
|
@ -738,7 +738,7 @@ public class ClassMatcher extends AbstractSet<String>
|
|||
{
|
||||
try
|
||||
{
|
||||
return URIUtil.getJarSource(url.toURI());
|
||||
return URIUtil.unwrapContainer(url.toURI());
|
||||
}
|
||||
catch (URISyntaxException ignored)
|
||||
{
|
||||
|
|
|
@ -23,6 +23,7 @@ import java.util.Map;
|
|||
import java.util.Objects;
|
||||
|
||||
import jakarta.servlet.ServletContext;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.util.thread.AutoLock;
|
||||
import org.slf4j.Logger;
|
||||
|
@ -458,7 +459,7 @@ public class MetaData
|
|||
List<String> orderedLibs = new ArrayList<>();
|
||||
for (Resource jar: orderedWebInfJars)
|
||||
{
|
||||
URI uri = Resource.unwrapContainer(jar.getURI());
|
||||
URI uri = URIUtil.unwrapContainer(jar.getURI());
|
||||
orderedLibs.add(uri.getPath());
|
||||
}
|
||||
context.setAttribute(ServletContext.ORDERED_LIBS, Collections.unmodifiableList(orderedLibs));
|
||||
|
|
|
@ -36,6 +36,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jetty.util.FileID;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.PatternMatcher;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
|
@ -668,7 +669,7 @@ public class MetaInfConfiguration extends AbstractConfiguration
|
|||
|
||||
try (Stream<Path> entries = Files.walk(dir)
|
||||
.filter(Files::isRegularFile)
|
||||
.filter(MetaInfConfiguration::isTldFile))
|
||||
.filter(path -> FileID.isTldFile(path)))
|
||||
{
|
||||
Iterator<Path> iter = entries.iterator();
|
||||
while (iter.hasNext())
|
||||
|
@ -698,7 +699,7 @@ public class MetaInfConfiguration extends AbstractConfiguration
|
|||
try (Stream<Path> stream = Files.walk(mount.root().getPath()))
|
||||
{
|
||||
Iterator<Path> it = stream
|
||||
.filter(MetaInfConfiguration::isTldFile)
|
||||
.filter(path -> FileID.isTldFile(path))
|
||||
.iterator();
|
||||
while (it.hasNext())
|
||||
{
|
||||
|
@ -709,18 +710,6 @@ public class MetaInfConfiguration extends AbstractConfiguration
|
|||
return tlds;
|
||||
}
|
||||
|
||||
private static boolean isTldFile(Path path)
|
||||
{
|
||||
if (!Files.isRegularFile(path))
|
||||
return false;
|
||||
if (path.getNameCount() < 2)
|
||||
return false;
|
||||
if (!path.getName(0).toString().equalsIgnoreCase("META-INF"))
|
||||
return false;
|
||||
String filename = path.getFileName().toString();
|
||||
return filename.toLowerCase(Locale.ENGLISH).endsWith(".tld");
|
||||
}
|
||||
|
||||
protected List<Resource> findClassDirs(WebAppContext context)
|
||||
throws Exception
|
||||
{
|
||||
|
@ -871,6 +860,6 @@ public class MetaInfConfiguration extends AbstractConfiguration
|
|||
|
||||
private boolean isFileSupported(Resource resource)
|
||||
{
|
||||
return Resource.isArchive(resource.getURI());
|
||||
return FileID.isArchive(resource.getURI());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,6 +41,7 @@ import org.eclipse.jetty.util.ClassVisibilityChecker;
|
|||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.TypeUtil;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.util.resource.ResourceCollection;
|
||||
import org.slf4j.Logger;
|
||||
|
@ -270,7 +271,7 @@ public class WebAppClassLoader extends URLClassLoader implements ClassVisibility
|
|||
if (classPath == null)
|
||||
return;
|
||||
|
||||
List<URI> uris = Resource.split(classPath);
|
||||
List<URI> uris = URIUtil.split(classPath);
|
||||
_mountedExtraClassPath = Resource.mountCollection(uris);
|
||||
|
||||
ResourceCollection rc = (ResourceCollection)_mountedExtraClassPath.root();
|
||||
|
@ -324,7 +325,7 @@ public class WebAppClassLoader extends URLClassLoader implements ClassVisibility
|
|||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("addJar - {}", jar);
|
||||
URI jarUri = Resource.toJarFileUri(jar.toUri());
|
||||
URI jarUri = URIUtil.toJarFileUri(jar.toUri());
|
||||
addClassPath(jarUri.toASCIIString());
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
|
|
@ -1251,7 +1251,7 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
|
|||
*/
|
||||
public void setExtraClasspath(String extraClasspath) throws IOException
|
||||
{
|
||||
List<URI> uris = Resource.split(extraClasspath);
|
||||
List<URI> uris = URIUtil.split(extraClasspath);
|
||||
_mountedExtraClasspath = Resource.mountCollection(uris);
|
||||
setExtraClasspath((ResourceCollection)_mountedExtraClasspath.root());
|
||||
}
|
||||
|
|
|
@ -44,6 +44,7 @@ import org.eclipse.jetty.toolchain.test.FS;
|
|||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.eclipse.jetty.toolchain.test.jupiter.WorkDir;
|
||||
import org.eclipse.jetty.toolchain.test.jupiter.WorkDirExtension;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
import org.eclipse.jetty.util.component.LifeCycle;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.hamcrest.Matchers;
|
||||
|
@ -526,7 +527,7 @@ public class WebAppContextTest
|
|||
.filter((path) -> path.getFileName().toString().endsWith(".jar"))
|
||||
.sorted(Comparator.naturalOrder())
|
||||
.map(Path::toUri)
|
||||
.map(Resource::toJarFileUri)
|
||||
.map(URIUtil::toJarFileUri)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
List<URI> actualURIs = new ArrayList<>();
|
||||
|
|
Loading…
Reference in New Issue