All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.jetty.util.FileID Maven / Gradle / Ivy

There is a newer version: 12.1.0.alpha0
Show newest version
//
// ========================================================================
// Copyright (c) 1995 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;
import java.util.regex.Pattern;

/**
 * Simple, yet surprisingly common utility methods for identifying various file types commonly seen and worked with in a
 * deployment scenario.
 */
public class FileID
{
    private static final Pattern NUMBER = Pattern.compile("[0-9]+");

    /**
     * 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)
    {
        Path filename = path.getFileName();
        if (filename == null)
            return "";
        String basename = filename.toString();
        int dot = basename.lastIndexOf('.');
        if (dot >= 0)
            basename = basename.substring(0, dot);
        return basename;
    }

    /**
     * Get the last segment of the URI returning it as the filename
     *
     * @param uri the URI to look for the filename
     * @return The last segment of the uri
     */
    public static String getFileName(URI uri)
    {
        if (uri == null)
            return "";
        if (uri.isOpaque())
        {
            return getFileName(uri.getSchemeSpecificPart());
        }
        return getFileName(uri.getPath());
    }

    /**
     * Get the last segment of a String path returning it as the filename
     *
     * @param path the string path to look for the filename
     * @return The last segment of the path
     */
    public static String getFileName(String path)
    {
        if (path == null || "/".equals(path))
            return "";
        int idx = path.lastIndexOf('/');
        if (idx >= 0)
        {
            if (idx == path.length() - 1)
            {
                // we found the trailing slash
                // eg: file:/path/to/dir/
                // we want to return the "dir" segment here
                int previousSlash = path.lastIndexOf('/', idx - 1);
                if (previousSlash >= 0)
                {
                    // we have a previous slash
                    // so return the segment without the trailing slash
                    return path.substring(previousSlash + 1, idx);
                }
                else
                {
                    // we have no previous slash
                    // this input string is something like "foo/"
                    // so return the segment without trailing slash
                    return path.substring(0, idx);
                }
            }
            return path.substring(idx + 1);
        }
        return path;
    }

    /**
     * 

* Retrieve the extension of a URI path. *

* *

* This is the name of the last segment of the URI path with a substring * for the extension (if any), excluding the dot, lower-cased. *

* *
{@code
     * "foo.tar.gz" "gz"
     * "foo.bar"    "bar"
     * "foo."       ""
     * "foo"        null
     * ".bar"       null
     * null         null
     * }
* * @param uri The URI to search * @return The last segment extension. Null if input uri is null, or scheme is null, or URI is not a `jar:file:` or `file:` based URI */ public static String getExtension(URI uri) { if (uri == null) return null; if (uri.getScheme() == null) return null; String path = null; if (uri.getScheme().equalsIgnoreCase("jar")) { URI sspUri = URI.create(uri.getRawSchemeSpecificPart()); if (!sspUri.getScheme().equalsIgnoreCase("file")) { return null; // not a `jar:file:` based URI } path = sspUri.getPath(); } else { path = uri.getPath(); } // look for `!/` split int jarEnd = path.indexOf("!/"); if (jarEnd >= 0) { return getExtension(path.substring(0, jarEnd)); } return getExtension(path); } /** *

* 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), excluding the dot, lower-cased. *

* *
{@code
     * "foo.tar.gz" "gz"
     * "foo.bar"    "bar"
     * "foo."       ""
     * "foo"        null
     * ".bar"       null
     * null         null
     * }
* * @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 excluding the leading dot; * 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, or only filename that is only an extension (".foo") return filename.substring(lastDot + 1).toLowerCase(Locale.ENGLISH); } /** * Test if Path matches any of the indicated extensions. * * @param path the Path to test * @param extensions the list of extensions (all lowercase, without preceding {@code .} dot) * @return true if Path is a file, and has an extension, and it matches any of the indicated extensions */ public static boolean isExtension(Path path, String... extensions) { return matchesExtension(getExtension(path), extensions); } /** * Test if URI matches any of the indicated extensions. * * @param uri the URI to test * @param extensions the list of extensions (all lowercase, without preceding {@code .} dot) * @return true if URI has an extension, and it matches any of the indicated extensions */ public static boolean isExtension(URI uri, String... extensions) { return matchesExtension(getExtension(uri), extensions); } /** * Test if filename matches any of the indicated extensions. * * @param filename the filename to test * @param extensions the list of extensions (all lowercase, without preceding {@code .} dot) * @return true if filename has an extension, and it matches any of the indicated extensions */ public static boolean isExtension(String filename, String... extensions) { return matchesExtension(getExtension(filename), extensions); } private static boolean matchesExtension(String ext, String... extensions) { if (ext == null) return false; for (String extension : extensions) { if (ext.equals(extension)) return true; } return false; } /** * Does the provided path have a directory segment with the given name. * * @param path the path to search * @param segmentName the segment name (of the given path) to look for (case-insensitive lookup), * only capable of searching 1 segment name at a time, does not support "foo/bar" multi-segment * names. * @return true if the directory name exists in path, false if otherwise */ public static boolean hasNamedPathSegment(Path path, String segmentName) { 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(segmentName)) return true; } return false; } /** * 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) { return isExtension(path, "jar", "war", "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) { return isExtension(filename, "jar", "war", "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) { return isExtension(uri, "jar", "war", "zip"); } /** * Test if Path is any supported Java Library Archive type (suitable to use as a library in a classpath/classloader) * * @param path the path to test * @return true if path is a file, and an extension of {@code jar}, or {@code zip} * @see #getExtension(Path) */ public static boolean isLibArchive(Path path) { return isExtension(path, "jar", "zip"); } /** * Test if filename is any supported Java Library Archive type (suitable to use as a library in a classpath/classloader) * * @param filename the filename to test * @return true if path is a file and name ends with {@code jar}, or {@code zip} * @see #getExtension(String) */ public static boolean isLibArchive(String filename) { return isExtension(filename, "jar", "zip"); } /** * Test if URI is any supported Java Library Archive type (suitable to use as a library in a classpath/classloader) * * @param uri the URI to test * @return true if the URI has a path that seems to point to a ({@code jar}, or {@code zip}). * @see #getExtension(URI) */ public static boolean isLibArchive(URI uri) { return isExtension(uri, "jar", "zip"); } /** * Predicate to test for class files * * @param path the path to test * @return true if the filename ends with {@code .class} */ public static boolean isClassFile(Path path) { Path fileNamePath = path.getFileName(); if (fileNamePath == null) return false; String filename = fileNamePath.toString(); // has to end in ".class" if (!StringUtil.asciiEndsWithIgnoreCase(filename, ".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} to exclude hidden paths following * filesystem rules for hidden directories and files. * * @param path the possibly relative path to evaluate * @return true if hidden by FileSystem rules, false if not * @see Files#isHidden(Path) */ public static boolean isHidden(Path path) { int count = path.getNameCount(); for (int i = 0; i < count; i++) { Path segment = path.getName(i); String segmentName = segment.toString(); if (segmentName.isBlank()) continue; // skip blank entries // default behavior that Jetty enforces if (segmentName.charAt(0) == '.') return true; // FileSystem behavior, that the FileSystem enforces try { if (Files.isHidden(segment)) return true; } catch (IOException ignore) { // ignore, if filesystem gives us an error, we cannot make the call on hidden status } } return false; } /** * Predicate useful for {@code Stream} 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 return isHidden(base.relativize(path)); } /** * Is the URI pointing to a Java Archive (JAR) File (not directory) * * @param uri the uri to test. * @return True if a jar file. */ public static boolean isJavaArchive(URI uri) { return isExtension(uri, "jar"); } /** * 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 isExtension(path, "jar"); } /** * 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 isExtension(filename, "jar"); } /** * Predicate to filter on {@code META-INF/versions/*} tree in walk/stream results. * *

* This only works with a zipfs based FileSystem *

* * @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; if (!StringUtil.asciiEqualsIgnoreCase("META-INF", path.getName(0).toString())) return false; if (!StringUtil.asciiEqualsIgnoreCase("versions", path.getName(1).toString())) return false; return NUMBER.matcher(path.getName(2).getFileName().toString()).matches(); } /** * Predicate to skip {@code META-INF/versions/*} tree from walk/stream results. * *

* This only works with a zipfs based FileSystem *

* * @param path the path to test * @return true if not in {@code META-INF/versions/*} tree */ public static boolean isNotMetaInfVersions(Path path) { return !isMetaInfVersions(path); } /** * Predicate to skip {@code module-info.class} files. * *

* This is a simple test against the last path segment using {@link Path#getFileName()} *

* * @param path the path to test * @return true if not a {@code module-info.class} file */ public static boolean isModuleInfoClass(Path path) { Path filenameSegment = path.getFileName(); if (filenameSegment == null) return false; return filenameSegment.toString().equalsIgnoreCase("module-info.class"); } /** * Predicate to skip {@code module-info.class} files. * *

* This is a simple test against the last path segment using {@link Path#getFileName()} *

* * @param path the path to test * @return true if not a {@code module-info.class} file */ public static boolean isNotModuleInfoClass(Path path) { return !isModuleInfoClass(path); } /** * Is the path a TLD File * * @param path the path to test. * @return True if a .tld file. */ public static boolean isTld(Path path) { if (path == null) return false; if (!hasNamedPathSegment(path, "META-INF")) return false; return isExtension(path, "tld"); } /** * 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 isExtension(path, "war"); } /** * Is the path a Web Archive File (not directory) * * @param uri the uri to test. * @return True if a war file. */ public static boolean isWebArchive(URI uri) { return isExtension(uri, "war"); } /** * 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 isExtension(filename, "war"); } /** * 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 isExtension(path, "xml"); } /** * 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 isExtension(filename, "xml"); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy