Rossen Stoyanchev
6 years ago
11 changed files with 449 additions and 83 deletions
@ -0,0 +1,100 @@
@@ -0,0 +1,100 @@
|
||||
/* |
||||
* Copyright 2002-2019 the original author or authors. |
||||
* |
||||
* Licensed 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 |
||||
* |
||||
* https://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.springframework.util; |
||||
|
||||
import java.util.Comparator; |
||||
import java.util.Map; |
||||
|
||||
import org.springframework.lang.Nullable; |
||||
|
||||
/** |
||||
* Contract for matching routes to patterns. |
||||
* |
||||
* <p>Equivalent to {@link PathMatcher}, but enables use of parsed |
||||
* representations of routes and patterns for efficiency reasons in scenarios |
||||
* where routes from incoming messages are continuously matched against a |
||||
* large number of message handler patterns. |
||||
* |
||||
* @author Rossen Stoyanchev |
||||
* @since 5.2 |
||||
*/ |
||||
public interface RouteMatcher { |
||||
|
||||
/** |
||||
* Return a parsed representation of the given route. |
||||
* @param routeValue the route to parse |
||||
* @return the parsed representation of the route |
||||
*/ |
||||
Route parseRoute(String routeValue); |
||||
|
||||
|
||||
/** |
||||
* Whether the given {@code route} contains pattern syntax which requires |
||||
* the {@link #match(String, Route)} method, or if it is a regular String |
||||
* that could be compared directly to others. |
||||
* @param route the route to check |
||||
* @return {@code true} if the given {@code route} represents a pattern |
||||
*/ |
||||
boolean isPattern(String route); |
||||
|
||||
/** |
||||
* Combines two patterns into a single pattern. |
||||
* @param pattern1 the first pattern |
||||
* @param pattern2 the second pattern |
||||
* @return the combination of the two patterns |
||||
* @throws IllegalArgumentException when the two patterns cannot be combined |
||||
*/ |
||||
String combine(String pattern1, String pattern2); |
||||
|
||||
/** |
||||
* Match the given route against the given pattern. |
||||
* @param pattern the pattern to try to match |
||||
* @param route the route to test against |
||||
* @return {@code true} if there is a match, {@code false} otherwise |
||||
*/ |
||||
boolean match(String pattern, Route route); |
||||
|
||||
/** |
||||
* Match the pattern to the route and extract template variables. |
||||
* @param pattern the pattern, possibly containing templates variables |
||||
* @param route the route to extract template variables from |
||||
* @return a map with template variables and values |
||||
*/ |
||||
@Nullable |
||||
Map<String, String> matchAndExtract(String pattern, Route route); |
||||
|
||||
/** |
||||
* Given a route, return a {@link Comparator} suitable for sorting patterns |
||||
* in order of explicitness for that route, so that more specific patterns |
||||
* come before more generic ones. |
||||
* @param route the full path to use for comparison |
||||
* @return a comparator capable of sorting patterns in order of explicitness |
||||
*/ |
||||
Comparator<String> getPatternComparator(Route route); |
||||
|
||||
|
||||
/** |
||||
* A parsed representation of a route. |
||||
*/ |
||||
interface Route { |
||||
|
||||
/** |
||||
* The original route value. |
||||
*/ |
||||
String value(); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,101 @@
@@ -0,0 +1,101 @@
|
||||
/* |
||||
* Copyright 2002-2019 the original author or authors. |
||||
* |
||||
* Licensed 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 |
||||
* |
||||
* https://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.springframework.util; |
||||
|
||||
import java.util.Comparator; |
||||
import java.util.Map; |
||||
|
||||
import org.springframework.lang.Nullable; |
||||
|
||||
/** |
||||
* {@code RouteMatcher} that delegates to a {@link PathMatcher}. |
||||
* |
||||
* <p><strong>Note:</strong> This implementation is not efficient since |
||||
* {@code PathMatcher} treats paths and patterns as Strings. For more optimized |
||||
* performance use the {@code PathPatternRouteMatcher} from {@code spring-web} |
||||
* which enables use of parsed routes and patterns. |
||||
* |
||||
* @author Rossen Stoyanchev |
||||
* @since 5.2 |
||||
*/ |
||||
public class SimpleRouteMatcher implements RouteMatcher { |
||||
|
||||
private final PathMatcher pathMatcher; |
||||
|
||||
|
||||
public SimpleRouteMatcher(PathMatcher pathMatcher) { |
||||
Assert.notNull(pathMatcher, "PathMatcher is required"); |
||||
this.pathMatcher = pathMatcher; |
||||
} |
||||
|
||||
|
||||
public PathMatcher getPathMatcher() { |
||||
return this.pathMatcher; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public Route parseRoute(String route) { |
||||
return new DefaultRoute(route); |
||||
} |
||||
|
||||
@Override |
||||
public boolean isPattern(String route) { |
||||
return this.pathMatcher.isPattern(route); |
||||
} |
||||
|
||||
@Override |
||||
public String combine(String pattern1, String pattern2) { |
||||
return this.pathMatcher.combine(pattern1, pattern2); |
||||
} |
||||
|
||||
@Override |
||||
public boolean match(String pattern, Route route) { |
||||
return this.pathMatcher.match(pattern, route.value()); |
||||
} |
||||
|
||||
@Override |
||||
@Nullable |
||||
public Map<String, String> matchAndExtract(String pattern, Route route) { |
||||
if (!match(pattern, route)) { |
||||
return null; |
||||
} |
||||
return this.pathMatcher.extractUriTemplateVariables(pattern, route.value()); |
||||
} |
||||
|
||||
@Override |
||||
public Comparator<String> getPatternComparator(Route route) { |
||||
return this.pathMatcher.getPatternComparator(route.value()); |
||||
} |
||||
|
||||
|
||||
private static class DefaultRoute implements Route { |
||||
|
||||
private final String path; |
||||
|
||||
|
||||
DefaultRoute(String path) { |
||||
this.path = path; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public String value() { |
||||
return this.path; |
||||
} |
||||
} |
||||
|
||||
} |
@ -0,0 +1,106 @@
@@ -0,0 +1,106 @@
|
||||
/* |
||||
* Copyright 2002-2019 the original author or authors. |
||||
* |
||||
* Licensed 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 |
||||
* |
||||
* https://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.springframework.web.util.pattern; |
||||
|
||||
import java.util.Comparator; |
||||
import java.util.Map; |
||||
import java.util.concurrent.ConcurrentHashMap; |
||||
|
||||
import org.springframework.http.server.PathContainer; |
||||
import org.springframework.lang.Nullable; |
||||
import org.springframework.util.Assert; |
||||
import org.springframework.util.RouteMatcher; |
||||
|
||||
/** |
||||
* {@code RouteMatcher} built on {@link PathPatternParser} that uses |
||||
* {@link PathContainer} and {@link PathPattern} as parsed representations of |
||||
* routes and patterns. |
||||
* |
||||
* @author Rossen Stoyanchev |
||||
* @since 5.2 |
||||
*/ |
||||
public class PathPatternRouteMatcher implements RouteMatcher { |
||||
|
||||
private final PathPatternParser parser; |
||||
|
||||
private final Map<String, PathPattern> pathPatternCache = new ConcurrentHashMap<>(); |
||||
|
||||
|
||||
public PathPatternRouteMatcher(PathPatternParser parser) { |
||||
Assert.notNull(parser, "PathPatternParser must not be null"); |
||||
this.parser = parser; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public Route parseRoute(String routeValue) { |
||||
return new PathContainerRoute(PathContainer.parsePath(routeValue)); |
||||
} |
||||
|
||||
@Override |
||||
public boolean isPattern(String route) { |
||||
return getPathPattern(route).hasPatternSyntax(); |
||||
} |
||||
|
||||
@Override |
||||
public String combine(String pattern1, String pattern2) { |
||||
return getPathPattern(pattern1).combine(getPathPattern(pattern2)).getPatternString(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean match(String pattern, Route route) { |
||||
return getPathPattern(pattern).matches(getPathContainer(route)); |
||||
} |
||||
|
||||
@Override |
||||
@Nullable |
||||
public Map<String, String> matchAndExtract(String pattern, Route route) { |
||||
PathPattern.PathMatchInfo info = getPathPattern(pattern).matchAndExtract(getPathContainer(route)); |
||||
return info != null ? info.getUriVariables() : null; |
||||
} |
||||
|
||||
@Override |
||||
public Comparator<String> getPatternComparator(Route route) { |
||||
return Comparator.comparing(this::getPathPattern); |
||||
} |
||||
|
||||
private PathPattern getPathPattern(String pattern) { |
||||
return this.pathPatternCache.computeIfAbsent(pattern, this.parser::parse); |
||||
} |
||||
|
||||
private PathContainer getPathContainer(Route route) { |
||||
Assert.isInstanceOf(PathContainerRoute.class, route); |
||||
return ((PathContainerRoute) route).pathContainer; |
||||
} |
||||
|
||||
|
||||
private static class PathContainerRoute implements Route { |
||||
|
||||
private final PathContainer pathContainer; |
||||
|
||||
|
||||
PathContainerRoute(PathContainer pathContainer) { |
||||
this.pathContainer = pathContainer; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public String value() { |
||||
return this.pathContainer.value(); |
||||
} |
||||
} |
||||
|
||||
} |
Loading…
Reference in new issue