| // |
| // ======================================================================== |
| // Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd. |
| // ------------------------------------------------------------------------ |
| // All rights reserved. This program and the accompanying materials |
| // are made available under the terms of the Eclipse Public License v1.0 |
| // and Apache License v2.0 which accompanies this distribution. |
| // |
| // The Eclipse Public License is available at |
| // http://www.eclipse.org/legal/epl-v10.html |
| // |
| // The Apache License v2.0 is available at |
| // http://www.opensource.org/licenses/apache2.0.php |
| // |
| // You may elect to redistribute this code under either of these licenses. |
| // ======================================================================== |
| // |
| |
| package org.eclipse.jetty.start; |
| |
| import java.io.File; |
| import java.io.IOException; |
| import java.nio.file.FileSystem; |
| import java.nio.file.FileSystems; |
| import java.nio.file.Files; |
| import java.nio.file.Path; |
| import java.nio.file.PathMatcher; |
| |
| /** |
| * Common PathMatcher implementations. |
| */ |
| public class PathMatchers |
| { |
| private static class NonHiddenMatcher implements PathMatcher |
| { |
| @Override |
| public boolean matches(Path path) |
| { |
| try |
| { |
| return !Files.isHidden(path); |
| } |
| catch (IOException e) |
| { |
| StartLog.debug(e); |
| return false; |
| } |
| } |
| } |
| |
| private static final char GLOB_CHARS[] = "*?".toCharArray(); |
| private static final char SYNTAXED_GLOB_CHARS[] = "{}[]|:".toCharArray(); |
| private static final Path EMPTY_PATH = new File(".").toPath(); |
| |
| /** |
| * Convert a pattern to a Path object. |
| * |
| * @param pattern |
| * the raw pattern (can contain "glob:" or "regex:" syntax indicator) |
| * @return the Path version of the pattern provided. |
| */ |
| private static Path asPath(final String pattern) |
| { |
| String test = pattern; |
| if (test.startsWith("glob:")) |
| { |
| test = test.substring("glob:".length()); |
| } |
| else if (test.startsWith("regex:")) |
| { |
| test = test.substring("regex:".length()); |
| } |
| return new File(test).toPath(); |
| } |
| |
| public static PathMatcher getMatcher(final String rawpattern) |
| { |
| FileSystem fs = FileSystems.getDefault(); |
| |
| String pattern = rawpattern; |
| |
| // Strip trailing slash (if present) |
| int lastchar = pattern.charAt(pattern.length() - 1); |
| if (lastchar == '/' || lastchar == '\\') |
| { |
| pattern = pattern.substring(0,pattern.length() - 1); |
| } |
| |
| // If using FileSystem.getPathMatcher() with "glob:" or "regex:" |
| // use FileSystem default pattern behavior |
| if (pattern.startsWith("glob:") || pattern.startsWith("regex:")) |
| { |
| StartLog.debug("Using Standard " + fs.getClass().getName() + " pattern: " + pattern); |
| return fs.getPathMatcher(pattern); |
| } |
| |
| // If the pattern starts with a root path then its assumed to |
| // be a full system path |
| if (isAbsolute(pattern)) |
| { |
| String pat = "glob:" + pattern; |
| StartLog.debug("Using absolute path pattern: " + pat); |
| return fs.getPathMatcher(pat); |
| } |
| |
| // Doesn't start with filesystem root, then assume the pattern |
| // is a relative file path pattern. |
| String pat = "glob:**/" + pattern; |
| StartLog.debug("Using relative path pattern: " + pat); |
| return fs.getPathMatcher(pat); |
| } |
| |
| public static PathMatcher getNonHidden() |
| { |
| return new NonHiddenMatcher(); |
| } |
| |
| /** |
| * Provide the non-glob / non-regex prefix on the pattern as a Path reference. |
| * |
| * @param pattern |
| * the pattern to test |
| * @return the Path representing the search root for the pattern provided. |
| */ |
| public static Path getSearchRoot(final String pattern) |
| { |
| StringBuilder root = new StringBuilder(); |
| |
| int start = 0; |
| boolean syntaxed = false; |
| if (pattern.startsWith("glob:")) |
| { |
| start = "glob:".length(); |
| syntaxed = true; |
| } |
| else if (pattern.startsWith("regex:")) |
| { |
| start = "regex:".length(); |
| syntaxed = true; |
| } |
| int len = pattern.length(); |
| int lastSep = 0; |
| for (int i = start; i < len; i++) |
| { |
| int cp = pattern.codePointAt(i); |
| if (cp < 127) |
| { |
| char c = (char)cp; |
| |
| // unix path case |
| if (c == '/') |
| { |
| root.append(c); |
| lastSep = root.length(); |
| } |
| else if (c == '\\') |
| { |
| root.append("\\"); |
| lastSep = root.length(); |
| |
| // possible escaped sequence. |
| // only really interested in windows escape sequences "\\" |
| int count = countChars(pattern,i+1,'\\'); |
| if (count > 0) |
| { |
| // skip extra slashes |
| i += count; |
| } |
| } |
| else |
| { |
| if (isGlob(c,syntaxed)) |
| { |
| break; |
| } |
| root.append(c); |
| } |
| } |
| else |
| { |
| root.appendCodePoint(cp); |
| } |
| } |
| |
| String rootPath = root.substring(0,lastSep); |
| if (rootPath.length() <= 0) |
| { |
| return EMPTY_PATH; |
| } |
| |
| return asPath(rootPath); |
| } |
| |
| private static int countChars(String pattern, int offset, char c) |
| { |
| int count = 0; |
| int len = pattern.length(); |
| for (int i = offset; i < len; i++) |
| { |
| if (pattern.charAt(i) == c) |
| { |
| count++; |
| } |
| else |
| { |
| break; |
| } |
| } |
| return count; |
| } |
| |
| /** |
| * Tests if provided pattern is an absolute reference (or not) |
| * |
| * @param pattern |
| * the pattern to test |
| * @return true if pattern is an absolute reference. |
| */ |
| public static boolean isAbsolute(final String pattern) |
| { |
| Path searchRoot = getSearchRoot(pattern); |
| if (searchRoot == EMPTY_PATH) |
| { |
| return false; |
| } |
| return searchRoot.isAbsolute(); |
| } |
| |
| /** |
| * Determine if part is a glob pattern. |
| * |
| * @param part |
| * the string to check |
| * @param syntaxed |
| * true if overall pattern is syntaxed with <code>"glob:"</code> or <code>"regex:"</code> |
| * @return true if part has glob characters |
| */ |
| private static boolean isGlob(char c, boolean syntaxed) |
| { |
| for (char g : GLOB_CHARS) |
| { |
| if (c == g) |
| { |
| return true; |
| } |
| } |
| if (syntaxed) |
| { |
| for (char g : SYNTAXED_GLOB_CHARS) |
| { |
| if (c == g) |
| { |
| return true; |
| } |
| } |
| } |
| return false; |
| } |
| } |