This is an automated email from the ASF dual-hosted git repository. wusheng pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/skywalking.git
The following commit(s) were added to refs/heads/master by this push: new dcb71cd Optimize trace ignore plugin (#4209) dcb71cd is described below commit dcb71cdeee7ad14188fcecb3674172e18d0c6158 Author: Kanro <hi...@live.cn> AuthorDate: Sun Jan 12 09:49:28 2020 +0800 Optimize trace ignore plugin (#4209) * Optimize trace ignore plugin * Add license for FastPathMatcher * Boot again after setting config in test * Fix check style * Fix typos Co-authored-by: kezhenxu94 <kezhenx...@163.com> --- .../trace/ignore/TraceIgnoreExtendService.java | 29 +-- .../trace/ignore/matcher/AntPathMatcher.java | 251 --------------------- .../trace/ignore/matcher/FastPathMatcher.java | 156 +++++++++++++ .../apm/plugin/trace/ignore/TraceIgnoreTest.java | 16 +- .../plugin/trace/ignore/TracePathMatcherTest.java | 62 +++-- 5 files changed, 229 insertions(+), 285 deletions(-) diff --git a/apm-sniffer/optional-plugins/trace-ignore-plugin/src/main/java/org/apache/skywalking/apm/plugin/trace/ignore/TraceIgnoreExtendService.java b/apm-sniffer/optional-plugins/trace-ignore-plugin/src/main/java/org/apache/skywalking/apm/plugin/trace/ignore/TraceIgnoreExtendService.java index 2c88a1d..f90e84f 100644 --- a/apm-sniffer/optional-plugins/trace-ignore-plugin/src/main/java/org/apache/skywalking/apm/plugin/trace/ignore/TraceIgnoreExtendService.java +++ b/apm-sniffer/optional-plugins/trace-ignore-plugin/src/main/java/org/apache/skywalking/apm/plugin/trace/ignore/TraceIgnoreExtendService.java @@ -28,14 +28,12 @@ import org.apache.skywalking.apm.agent.core.logging.api.ILog; import org.apache.skywalking.apm.agent.core.logging.api.LogManager; import org.apache.skywalking.apm.plugin.trace.ignore.conf.IgnoreConfig; import org.apache.skywalking.apm.plugin.trace.ignore.conf.IgnoreConfigInitializer; -import org.apache.skywalking.apm.plugin.trace.ignore.matcher.AntPathMatcher; +import org.apache.skywalking.apm.plugin.trace.ignore.matcher.FastPathMatcher; import org.apache.skywalking.apm.plugin.trace.ignore.matcher.TracePathMatcher; import org.apache.skywalking.apm.util.StringUtil; /** - * - * @author liujc [liujunc1...@163.com] - * + * @author liujc [liujunc1...@163.com], kanro */ @OverrideImplementor(ContextManagerExtendService.class) public class TraceIgnoreExtendService extends ContextManagerExtendService { @@ -46,30 +44,27 @@ public class TraceIgnoreExtendService extends ContextManagerExtendService { private static final String PATTERN_SEPARATOR = ","; - private TracePathMatcher pathMatcher = new AntPathMatcher(); + private TracePathMatcher pathMatcher = new FastPathMatcher(); + + private String[] patterns = new String[]{}; @Override public void boot() { try { IgnoreConfigInitializer.initialize(); - } catch (ConfigNotFoundException e) { - LOGGER.error("trace ignore config init error", e); - } catch (AgentPackageNotFoundException e) { + if (StringUtil.isNotEmpty(IgnoreConfig.Trace.IGNORE_PATH)) { + patterns = IgnoreConfig.Trace.IGNORE_PATH.split(PATTERN_SEPARATOR); + } + } catch (ConfigNotFoundException | AgentPackageNotFoundException e) { LOGGER.error("trace ignore config init error", e); } } @Override public AbstractTracerContext createTraceContext(String operationName, boolean forceSampling) { - String pattens = IgnoreConfig.Trace.IGNORE_PATH; - if (!StringUtil.isEmpty(pattens) && !forceSampling) { - String path = operationName; - if (!StringUtil.isEmpty(path) && path.length() > 1 && path.endsWith(DEFAULT_PATH_SEPARATOR)) { - path = path.substring(0, path.length() - 1); - } - - for (String pattern : pattens.split(PATTERN_SEPARATOR)) { - if (pathMatcher.match(pattern, path)) { + if (patterns.length > 0 && !forceSampling) { + for (String pattern : patterns) { + if (pathMatcher.match(pattern, operationName)) { LOGGER.debug("operationName : " + operationName + " Ignore tracking"); return new IgnoredTracerContext(); } diff --git a/apm-sniffer/optional-plugins/trace-ignore-plugin/src/main/java/org/apache/skywalking/apm/plugin/trace/ignore/matcher/AntPathMatcher.java b/apm-sniffer/optional-plugins/trace-ignore-plugin/src/main/java/org/apache/skywalking/apm/plugin/trace/ignore/matcher/AntPathMatcher.java deleted file mode 100644 index 9ed1afc..0000000 --- a/apm-sniffer/optional-plugins/trace-ignore-plugin/src/main/java/org/apache/skywalking/apm/plugin/trace/ignore/matcher/AntPathMatcher.java +++ /dev/null @@ -1,251 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package org.apache.skywalking.apm.plugin.trace.ignore.matcher; - -import org.apache.skywalking.apm.util.StringUtil; - -import java.util.ArrayList; -import java.util.List; -import java.util.StringTokenizer; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * - * @author liujc [liujunc1...@163.com] - * - */ -public class AntPathMatcher implements TracePathMatcher { - - private static final String DEFAULT_PATH_SEPARATOR = "/"; - - private static final String ANY_ONE_MATCHING_CHAR = "?"; - - private static final String ANY_MATCHING_CHAR = "*"; - - private static final String MULTILEVEL_DIRECTORIES_ANY_MATCHING_CHAR = ANY_MATCHING_CHAR.concat(ANY_MATCHING_CHAR); - - @Override - public boolean match(String pattern, String path) { - if (!MatchAssist.checkPatternAndPath(pattern, path)) { - return false; - } - - // resolve pattern and path by default path separator - String[] resolvedPatterns = MatchAssist.resolvePath(pattern); - String[] resolvedPaths = MatchAssist.resolvePath(path); - - int patternIdxStart = 0; - int patternIdxEnd = resolvedPatterns.length - 1; - int pathIdxStart = 0; - int pathIdxEnd = resolvedPaths.length - 1; - - - // try to match first '**' - while (true) { - if (patternIdxStart > patternIdxEnd || pathIdxStart > pathIdxEnd) { - break; - } - String resolvedPattern = resolvedPatterns[patternIdxStart]; - if (MULTILEVEL_DIRECTORIES_ANY_MATCHING_CHAR.equals(resolvedPattern)) { - break; - } - if (!MatchAssist.matchStrings(resolvedPattern, resolvedPaths[pathIdxStart])) { - return false; - } - patternIdxStart++; - pathIdxStart++; - } - - if (pathIdxStart > pathIdxEnd) { - if (patternIdxStart > patternIdxEnd) { - return pattern.endsWith(DEFAULT_PATH_SEPARATOR) == path.endsWith(DEFAULT_PATH_SEPARATOR); - } - return patternIdxStart == patternIdxEnd && resolvedPatterns[patternIdxStart].equals(ANY_MATCHING_CHAR) && path.endsWith(DEFAULT_PATH_SEPARATOR) - || MatchAssist.checkPatternIdx(patternIdxStart, patternIdxEnd, resolvedPatterns); - } - else if (patternIdxStart > patternIdxEnd) { - return false; - } - - // try to match last '**' - while (true) { - if (patternIdxStart > patternIdxEnd || pathIdxStart > pathIdxEnd) { - break; - } - String resolvedPattern = resolvedPatterns[patternIdxEnd]; - if (resolvedPattern.equals(MULTILEVEL_DIRECTORIES_ANY_MATCHING_CHAR)) { - break; - } - if (!MatchAssist.matchStrings(resolvedPattern, resolvedPaths[pathIdxEnd])) { - return false; - } - patternIdxEnd--; - pathIdxEnd--; - } - if (pathIdxStart > pathIdxEnd) { - return MatchAssist.checkPatternIdx(patternIdxStart, patternIdxEnd, resolvedPatterns); - } - - while (patternIdxStart != patternIdxEnd && pathIdxStart <= pathIdxEnd) { - int patIdxTmp = -1; - for (int i = patternIdxStart + 1; i <= patternIdxEnd; i++) { - if (resolvedPatterns[i].equals(MULTILEVEL_DIRECTORIES_ANY_MATCHING_CHAR)) { - patIdxTmp = i; - break; - } - } - if (patIdxTmp == patternIdxStart + 1) { - // '**/**' situation, so skip one - patternIdxStart++; - continue; - } - // Find the pattern between patternIdxStart & padIdxTmp in str between - // strIdxStart & strIdxEnd - int patLength = patIdxTmp - patternIdxStart - 1; - int strLength = pathIdxEnd - pathIdxStart + 1; - int foundIdx = -1; - - strLoop: - for (int i = 0; i <= strLength - patLength; i++) { - for (int j = 0; j < patLength; j++) { - String subPat = resolvedPatterns[patternIdxStart + j + 1]; - String subStr = resolvedPatterns[pathIdxStart + i + j]; - if (!MatchAssist.matchStrings(subPat, subStr)) { - continue strLoop; - } - } - foundIdx = pathIdxStart + i; - break; - } - - if (foundIdx == -1) { - return false; - } - - patternIdxStart = patIdxTmp; - pathIdxStart = foundIdx + patLength; - } - - return MatchAssist.checkPatternIdx(patternIdxStart, patternIdxEnd, resolvedPatterns); - } - - - - - private static class MatchAssist { - - private static final Pattern GLOB_PATTERN = Pattern.compile("\\?|\\*|\\{((?:\\{[^/]+?\\}|[^/{}]|\\\\[{}])+?)\\}"); - - private static final String DEFAULT_VARIABLE_PATTERN = "(.*)"; - - private static final ConcurrentMap<String, Pattern> GLOBAL_COMPILED_PATTERN_CACHE = new ConcurrentHashMap<String, Pattern>(); - - - private static boolean checkPatternIdx(int patternIdxStart, int patternIdxEnd, String[] resolvedPatterns) { - for (int i = patternIdxStart; i <= patternIdxEnd; i++) { - if (!resolvedPatterns[i].equals(MULTILEVEL_DIRECTORIES_ANY_MATCHING_CHAR)) { - return false; - } - } - return true; - } - - /** - * make sure of the pattern and path is validate - */ - private static boolean checkPatternAndPath(String pattern, String path) { - return !StringUtil.isEmpty(pattern) && !StringUtil.isEmpty(path) && - path.startsWith(DEFAULT_PATH_SEPARATOR) == pattern.startsWith(DEFAULT_PATH_SEPARATOR); - } - - /** - * resolve path by default path separator - */ - private static String[] resolvePath(String path) { - if (path == null) { - return null; - } - StringTokenizer st = new StringTokenizer(path, DEFAULT_PATH_SEPARATOR); - List<String> tokens = new ArrayList<String>(); - while (st.hasMoreTokens()) { - String token = st.nextToken(); - token = token.trim(); - if (token.length() > 0) { - tokens.add(token); - } - } - return tokens.toArray(new String[tokens.size()]); - } - - /** - * use pattern match path - */ - private static boolean matchStrings(String pattern, String path) { - if (StringUtil.isEmpty(pattern) || StringUtil.isEmpty(path)) { - return false; - } - // if this pattern has been compiled - Pattern compliedPattern = GLOBAL_COMPILED_PATTERN_CACHE.get(pattern); - if (compliedPattern == null) { - // build new pattern - StringBuilder patternBuilder = new StringBuilder(); - Matcher matcher = GLOB_PATTERN.matcher(pattern); - int end = 0; - while (matcher.find()) { - patternBuilder.append(quote(pattern, end, matcher.start())); - String match = matcher.group(); - if (ANY_ONE_MATCHING_CHAR.equals(match)) { - patternBuilder.append('.'); - } - else if (ANY_MATCHING_CHAR.equals(match)) { - patternBuilder.append(".".concat(ANY_MATCHING_CHAR)); - } - else if (match.startsWith("{") && match.endsWith("}")) { - int colonIdx = match.indexOf(':'); - if (colonIdx == -1) { - patternBuilder.append(DEFAULT_VARIABLE_PATTERN); - } - else { - String variablePattern = match.substring(colonIdx + 1, match.length() - 1); - patternBuilder.append('('); - patternBuilder.append(variablePattern); - patternBuilder.append(')'); - } - } - end = matcher.end(); - } - patternBuilder.append(quote(pattern, end, pattern.length())); - compliedPattern = Pattern.compile(patternBuilder.toString()); - GLOBAL_COMPILED_PATTERN_CACHE.putIfAbsent(pattern, compliedPattern); - } - - return compliedPattern.matcher(path).matches(); - } - - private static String quote(String s, int start, int end) { - if (start == end) { - return ""; - } - return Pattern.quote(s.substring(start, end)); - } - } -} diff --git a/apm-sniffer/optional-plugins/trace-ignore-plugin/src/main/java/org/apache/skywalking/apm/plugin/trace/ignore/matcher/FastPathMatcher.java b/apm-sniffer/optional-plugins/trace-ignore-plugin/src/main/java/org/apache/skywalking/apm/plugin/trace/ignore/matcher/FastPathMatcher.java new file mode 100644 index 0000000..0d7c206 --- /dev/null +++ b/apm-sniffer/optional-plugins/trace-ignore-plugin/src/main/java/org/apache/skywalking/apm/plugin/trace/ignore/matcher/FastPathMatcher.java @@ -0,0 +1,156 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.apm.plugin.trace.ignore.matcher; + +/** + * @author kanro + */ +public class FastPathMatcher implements TracePathMatcher { + @Override + public boolean match(String pattern, String path) { + return normalMatch(pattern, 0, path, 0); + } + + private boolean normalMatch(String pat, int p, String str, int s) { + while (p < pat.length()) { + char pc = pat.charAt(p); + char sc = safeCharAt(str, s); + + // Got * in pattern, enter the wildcard mode. + // ↓ ↓ + // pattern: a/* a/* + // ↓ ↓ + // string: a/bcd a/ + if (pc == '*') { + p++; + // Got * in pattern again, enter the multi-wildcard mode. + // ↓ ↓ + // pattern: a/** a/** + // ↓ ↓ + // string: a/bcd a/ + if (safeCharAt(pat, p) == '*') { + p++; + // Enter the multi-wildcard mode. + // ↓ ↓ + // pattern: a/** a/** + // ↓ ↓ + // string: a/bcd a/ + return multiWildcardMatch(pat, p, str, s); + } else { + // Enter the wildcard mode. + // ↓ + // pattern: a/* + // ↓ + // string: a/bcd + return wildcardMatch(pat, p, str, s); + } + } + + // Matching ? for non-'/' char, or matching the same chars. + // ↓ ↓ ↓ + // pattern: a/?/c a/b/c a/b + // ↓ ↓ ↓ + // string: a/b/c a/b/d a/d + if ((pc == '?' && sc != 0 && sc != '/') || pc == sc) { + s++; + p++; + continue; + } + + // Not matched. + // ↓ + // pattern: a/b + // ↓ + // string: a/c + return false; + } + + return s == str.length(); + } + + private boolean wildcardMatch(String pat, int p, String str, int s) { + char pc = safeCharAt(pat, p); + + while (true) { + char sc = safeCharAt(str, s); + + if (sc == '/') { + // Both of pattern and string '/' matched, exit wildcard mode. + // ↓ + // pattern: a/*/ + // ↓ + // string: a/bc/ + if (pc == sc) { + return normalMatch(pat, p + 1, str, s + 1); + } + + // Not matched string in current path part. + // ↓ ↓ + // pattern: a/* a/*d + // ↓ ↓ + // string: a/bc/ a/bc/ + return false; + } + + // Try to enter normal mode, if not matched, increasing pointer of string and try again. + if (!normalMatch(pat, p, str, s)) { + // End of string, not matched. + if (s >= str.length()) { + return false; + } + + s++; + continue; + } + + // Matched in next normal mode. + return true; + } + } + + private boolean multiWildcardMatch(String pat, int p, String str, int s) { + // End of pattern, just check the end of string is '/' quickly. + if (p >= pat.length() && s < str.length()) { + return str.charAt(str.length() - 1) != '/'; + } + + while (true) { + // Try to enter normal mode, if not matched, increasing pointer of string and try again. + if (!normalMatch(pat, p, str, s)) { + // End of string, not matched. + if (s >= str.length()) { + return false; + } + + s++; + continue; + } + + return true; + } + } + + private char safeCharAt(String value, int index) { + if (index >= value.length()) { + return 0; + } + + return value.charAt(index); + } +} diff --git a/apm-sniffer/optional-plugins/trace-ignore-plugin/src/test/java/org/apache/skywalking/apm/plugin/trace/ignore/TraceIgnoreTest.java b/apm-sniffer/optional-plugins/trace-ignore-plugin/src/test/java/org/apache/skywalking/apm/plugin/trace/ignore/TraceIgnoreTest.java index 9ca70ed..f0ffa4e 100644 --- a/apm-sniffer/optional-plugins/trace-ignore-plugin/src/test/java/org/apache/skywalking/apm/plugin/trace/ignore/TraceIgnoreTest.java +++ b/apm-sniffer/optional-plugins/trace-ignore-plugin/src/test/java/org/apache/skywalking/apm/plugin/trace/ignore/TraceIgnoreTest.java @@ -18,15 +18,22 @@ package org.apache.skywalking.apm.plugin.trace.ignore; -import java.util.Properties; import org.apache.skywalking.apm.agent.core.boot.ServiceManager; -import org.apache.skywalking.apm.agent.core.context.*; +import org.apache.skywalking.apm.agent.core.context.AbstractTracerContext; +import org.apache.skywalking.apm.agent.core.context.ContextManagerExtendService; +import org.apache.skywalking.apm.agent.core.context.IgnoredTracerContext; +import org.apache.skywalking.apm.agent.core.context.TracingContext; import org.apache.skywalking.apm.agent.test.tools.AgentServiceRule; import org.apache.skywalking.apm.plugin.trace.ignore.conf.IgnoreConfig; -import org.apache.skywalking.apm.util.*; -import org.junit.*; +import org.apache.skywalking.apm.util.ConfigInitializer; +import org.apache.skywalking.apm.util.PropertyPlaceholderHelper; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; import org.junit.contrib.java.lang.system.EnvironmentVariables; +import java.util.Properties; + import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; @@ -51,6 +58,7 @@ public class TraceIgnoreTest { public void testTraceIgnore() { ContextManagerExtendService service = ServiceManager.INSTANCE.findService(ContextManagerExtendService.class); IgnoreConfig.Trace.IGNORE_PATH = "/eureka/**"; + service.boot(); AbstractTracerContext ignoredTracerContext = service.createTraceContext("/eureka/apps", false); Assert.assertEquals(IgnoredTracerContext.class, ignoredTracerContext.getClass()); diff --git a/apm-sniffer/optional-plugins/trace-ignore-plugin/src/test/java/org/apache/skywalking/apm/plugin/trace/ignore/TracePathMatcherTest.java b/apm-sniffer/optional-plugins/trace-ignore-plugin/src/test/java/org/apache/skywalking/apm/plugin/trace/ignore/TracePathMatcherTest.java index 8b3871d..7a8cc5e 100644 --- a/apm-sniffer/optional-plugins/trace-ignore-plugin/src/test/java/org/apache/skywalking/apm/plugin/trace/ignore/TracePathMatcherTest.java +++ b/apm-sniffer/optional-plugins/trace-ignore-plugin/src/test/java/org/apache/skywalking/apm/plugin/trace/ignore/TracePathMatcherTest.java @@ -18,7 +18,7 @@ package org.apache.skywalking.apm.plugin.trace.ignore; -import org.apache.skywalking.apm.plugin.trace.ignore.matcher.AntPathMatcher; +import org.apache.skywalking.apm.plugin.trace.ignore.matcher.FastPathMatcher; import org.apache.skywalking.apm.plugin.trace.ignore.matcher.TracePathMatcher; import org.junit.Assert; import org.junit.Test; @@ -27,50 +27,86 @@ public class TracePathMatcherTest { @Test public void testAntPathMatcher() { - TracePathMatcher pathMatcher = new AntPathMatcher(); + TracePathMatcher pathMatcher = new FastPathMatcher(); String patten = "/eureka/*"; - String path = "/eureka/app"; - + String path = "/eureka/apps"; boolean match = pathMatcher.match(patten, path); Assert.assertTrue(match); + path = "/eureka/"; + match = pathMatcher.match(patten, path); + Assert.assertTrue(match); + path = "/eureka/apps/"; + match = pathMatcher.match(patten, path); + Assert.assertFalse(match); + patten = "/eureka/*/"; + path = "/eureka/apps/"; + match = pathMatcher.match(patten, path); + Assert.assertTrue(match); + path = "/eureka/"; + match = pathMatcher.match(patten, path); + Assert.assertFalse(match); path = "/eureka/apps/list"; match = pathMatcher.match(patten, path); Assert.assertFalse(match); patten = "/eureka/**"; + path = "/eureka/"; match = pathMatcher.match(patten, path); Assert.assertTrue(match); - - patten = "/eureka/apps/lis?"; + path = "/eureka/apps/test"; match = pathMatcher.match(patten, path); Assert.assertTrue(match); + path = "/eureka/apps/test/"; + match = pathMatcher.match(patten, path); + Assert.assertFalse(match); - path = "eureka/apps/lists"; + patten = "eureka/apps/?"; + path = "eureka/apps/list"; + match = pathMatcher.match(patten, path); + Assert.assertFalse(match); + path = "eureka/apps/"; match = pathMatcher.match(patten, path); Assert.assertFalse(match); + path = "eureka/apps/a"; + match = pathMatcher.match(patten, path); + Assert.assertTrue(match); patten = "eureka/**/lists"; + path = "eureka/apps/lists"; match = pathMatcher.match(patten, path); Assert.assertTrue(match); - - path = "eureka/apps/a/b/c/lists"; + path = "eureka/apps/test/lists"; match = pathMatcher.match(patten, path); Assert.assertTrue(match); - - path = "eureka/apps/a/b/c/"; + path = "eureka/apps/test/"; + match = pathMatcher.match(patten, path); + Assert.assertFalse(match); + path = "eureka/apps/test"; match = pathMatcher.match(patten, path); Assert.assertFalse(match); - patten = "eureka/**/b/**"; + patten = "eureka/**/test/**"; + path = "eureka/apps/test/list"; + match = pathMatcher.match(patten, path); + Assert.assertTrue(match); + path = "eureka/apps/foo/test/list/bar"; match = pathMatcher.match(patten, path); Assert.assertTrue(match); + path = "eureka/apps/foo/test/list/bar/"; + match = pathMatcher.match(patten, path); + Assert.assertFalse(match); + path = "eureka/apps/test/list"; + match = pathMatcher.match(patten, path); + Assert.assertTrue(match); + path = "eureka/test/list"; + match = pathMatcher.match(patten, path); + Assert.assertFalse(match); patten = "/eureka/**/b/**/*.txt"; path = "/eureka/a/aa/aaa/b/bb/bbb/xxxxxx.txt"; match = pathMatcher.match(patten, path); Assert.assertTrue(match); - path = "/eureka/a/aa/aaa/b/bb/bbb/xxxxxx"; match = pathMatcher.match(patten, path); Assert.assertFalse(match);