Moves to named Tuple args
Moves most RequestPredicateFactories to named Tuple arguments rather than indexed.
This commit is contained in:
@@ -28,6 +28,7 @@ import org.springframework.cloud.gateway.model.FilterDefinition;
|
||||
import org.springframework.cloud.gateway.model.PredicateDefinition;
|
||||
import org.springframework.cloud.gateway.model.Route;
|
||||
|
||||
import static org.springframework.cloud.gateway.handler.predicate.PathRequestPredicateFactory.PATTERN_KEY;
|
||||
import static org.springframework.cloud.gateway.support.NameUtils.normalizeFilterName;
|
||||
import static org.springframework.cloud.gateway.support.NameUtils.normalizePredicateName;
|
||||
|
||||
@@ -58,7 +59,7 @@ public class DiscoveryClientRouteLocator implements RouteLocator {
|
||||
// add a predicate that matches the url at /serviceId/**
|
||||
PredicateDefinition predicate = new PredicateDefinition();
|
||||
predicate.setName(normalizePredicateName(PathRequestPredicateFactory.class));
|
||||
predicate.setArgs(Collections.singletonMap("path", "/" + serviceId + "/**"));
|
||||
predicate.setArgs(Collections.singletonMap(PATTERN_KEY, "/" + serviceId + "/**"));
|
||||
route.getPredicates().add(predicate);
|
||||
|
||||
//TODO: support for other default predicates
|
||||
|
||||
@@ -27,6 +27,7 @@ import org.springframework.cloud.gateway.api.RouteLocator;
|
||||
import org.springframework.cloud.gateway.handler.predicate.RequestPredicateFactory;
|
||||
import org.springframework.cloud.gateway.model.PredicateDefinition;
|
||||
import org.springframework.cloud.gateway.model.Route;
|
||||
import org.springframework.cloud.gateway.support.NameUtils;
|
||||
import org.springframework.tuple.Tuple;
|
||||
import org.springframework.tuple.TupleBuilder;
|
||||
import org.springframework.web.reactive.function.server.PublicDefaultServerRequest;
|
||||
@@ -146,7 +147,6 @@ public class RequestPredicateHandlerMapping extends AbstractHandlerMapping {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private RequestPredicate combinePredicates(Route route) {
|
||||
List<PredicateDefinition> predicates = route.getPredicates();
|
||||
RequestPredicate predicate = lookup(route, predicates.get(0));
|
||||
@@ -159,20 +159,42 @@ public class RequestPredicateHandlerMapping extends AbstractHandlerMapping {
|
||||
return predicate;
|
||||
}
|
||||
|
||||
//TODO: decouple from HandlerMapping?
|
||||
private RequestPredicate lookup(Route route, PredicateDefinition predicate) {
|
||||
RequestPredicateFactory found = this.routePredicates.get(predicate.getName());
|
||||
if (found == null) {
|
||||
throw new IllegalArgumentException("Unable to find RequestPredicateFactory with name " + predicate.getName());
|
||||
}
|
||||
Map<String, String> args = predicate.getArgs();
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Route " + route.getId() + " applying "
|
||||
+ predicate.getArgs() + " to " + predicate.getName());
|
||||
+ args + " to " + predicate.getName());
|
||||
}
|
||||
|
||||
TupleBuilder builder = TupleBuilder.tuple();
|
||||
|
||||
for (Map.Entry<String, String> entry : predicate.getArgs().entrySet()) {
|
||||
builder.put(entry.getKey(), entry.getValue());
|
||||
List<String> argNames = found.argNames();
|
||||
if (!argNames.isEmpty()) {
|
||||
// ensure size is the same for key replacement later
|
||||
if (found.validateArgSize() && args.size() != argNames.size()) {
|
||||
throw new IllegalArgumentException("Wrong number of arguments. Expected " + argNames
|
||||
+ " " + argNames + ". Found "+ args.size() +" " + args +"'");
|
||||
}
|
||||
}
|
||||
|
||||
int entryIdx = 0;
|
||||
for (Map.Entry<String, String> entry : args.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
|
||||
// RequestPredicateFactory has name hints and this has a fake key name
|
||||
// replace with the matching key hint
|
||||
if (key.startsWith(NameUtils.GENERATED_NAME_PREFIX) && !argNames.isEmpty()
|
||||
&& entryIdx < args.size()) {
|
||||
key = argNames.get(entryIdx);
|
||||
}
|
||||
|
||||
builder.put(key, entry.getValue());
|
||||
entryIdx++;
|
||||
}
|
||||
|
||||
Tuple tuple = builder.build();
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
package org.springframework.cloud.gateway.handler.predicate;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.tuple.Tuple;
|
||||
import org.springframework.web.reactive.function.server.RequestPredicate;
|
||||
@@ -29,10 +31,16 @@ import static org.springframework.cloud.gateway.handler.predicate.BetweenRequest
|
||||
*/
|
||||
public class AfterRequestPredicateFactory implements RequestPredicateFactory {
|
||||
|
||||
public static final String DATETIME_KEY = "datetime";
|
||||
|
||||
@Override
|
||||
public List<String> argNames() {
|
||||
return Collections.singletonList(DATETIME_KEY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequestPredicate apply(Tuple args) {
|
||||
validate(1, args);
|
||||
final ZonedDateTime dateTime = parseZonedDateTime(args.getString(0));
|
||||
final ZonedDateTime dateTime = parseZonedDateTime(args.getString(DATETIME_KEY));
|
||||
|
||||
return request -> {
|
||||
final ZonedDateTime now = ZonedDateTime.now();
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
package org.springframework.cloud.gateway.handler.predicate;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.tuple.Tuple;
|
||||
import org.springframework.web.reactive.function.server.RequestPredicate;
|
||||
@@ -29,10 +31,16 @@ import static org.springframework.cloud.gateway.handler.predicate.BetweenRequest
|
||||
*/
|
||||
public class BeforeRequestPredicateFactory implements RequestPredicateFactory {
|
||||
|
||||
public static final String DATETIME_KEY = "datetime";
|
||||
|
||||
@Override
|
||||
public List<String> argNames() {
|
||||
return Collections.singletonList(DATETIME_KEY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequestPredicate apply(Tuple args) {
|
||||
validate(1, args);
|
||||
final ZonedDateTime dateTime = parseZonedDateTime(args.getString(0));
|
||||
final ZonedDateTime dateTime = parseZonedDateTime(args.getString(DATETIME_KEY));
|
||||
|
||||
return request -> {
|
||||
final ZonedDateTime now = ZonedDateTime.now();
|
||||
|
||||
@@ -30,15 +30,16 @@ import org.springframework.web.reactive.function.server.RequestPredicate;
|
||||
*/
|
||||
public class BetweenRequestPredicateFactory implements RequestPredicateFactory {
|
||||
|
||||
public static final String DATETIME1_KEY = "datetime1";
|
||||
public static final String DATETIME2_KEY = "datetime2";
|
||||
|
||||
@Override
|
||||
public RequestPredicate apply(Tuple args) {
|
||||
validate(2, args);
|
||||
|
||||
//TODO: is ZonedDateTime the right thing to use?
|
||||
final ZonedDateTime dateTime1 = parseZonedDateTime(args.getString(0));
|
||||
final ZonedDateTime dateTime2 = parseZonedDateTime(args.getString(1));
|
||||
Assert.isTrue(dateTime1.isBefore(dateTime2), args.getString(0) +
|
||||
" must be before " + args.getString(1));
|
||||
final ZonedDateTime dateTime1 = parseZonedDateTime(args.getString(DATETIME1_KEY));
|
||||
final ZonedDateTime dateTime2 = parseZonedDateTime(args.getString(DATETIME2_KEY));
|
||||
Assert.isTrue(dateTime1.isBefore(dateTime2), args.getString(DATETIME1_KEY) +
|
||||
" must be before " + args.getString(DATETIME2_KEY));
|
||||
|
||||
return request -> {
|
||||
final ZonedDateTime now = ZonedDateTime.now();
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
package org.springframework.cloud.gateway.handler.predicate;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.http.HttpCookie;
|
||||
@@ -29,11 +30,18 @@ import org.springframework.web.reactive.function.server.RequestPredicate;
|
||||
*/
|
||||
public class CookieRequestPredicateFactory implements RequestPredicateFactory {
|
||||
|
||||
public static final String NAME_KEY = "name";
|
||||
public static final String REGEXP_KEY = "regexp";
|
||||
|
||||
@Override
|
||||
public List<String> argNames() {
|
||||
return Arrays.asList(NAME_KEY, REGEXP_KEY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequestPredicate apply(Tuple args) {
|
||||
validate(2, args);
|
||||
String name = args.getString(0);
|
||||
String regexp = args.getString(1);
|
||||
String name = args.getString(NAME_KEY);
|
||||
String regexp = args.getString(REGEXP_KEY);
|
||||
|
||||
return request -> {
|
||||
//TODO: bad cast?
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
package org.springframework.cloud.gateway.handler.predicate;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.tuple.Tuple;
|
||||
@@ -28,11 +29,18 @@ import org.springframework.web.reactive.function.server.RequestPredicates;
|
||||
*/
|
||||
public class HeaderRequestPredicateFactory implements RequestPredicateFactory {
|
||||
|
||||
public static final String HEADER_KEY = "header";
|
||||
public static final String REGEXP_KEY = "regexp";
|
||||
|
||||
@Override
|
||||
public List<String> argNames() {
|
||||
return Arrays.asList(HEADER_KEY, REGEXP_KEY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequestPredicate apply(Tuple args) {
|
||||
validate(2, args);
|
||||
String header = args.getString(0);
|
||||
String regexp = args.getString(1);
|
||||
String header = args.getString(HEADER_KEY);
|
||||
String regexp = args.getString(REGEXP_KEY);
|
||||
|
||||
return RequestPredicates.headers(headers -> {
|
||||
List<String> values = headers.asHttpHeaders().get(header);
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
|
||||
package org.springframework.cloud.gateway.handler.predicate;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.tuple.Tuple;
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
import org.springframework.util.PathMatcher;
|
||||
@@ -28,16 +31,21 @@ import org.springframework.web.reactive.function.server.RequestPredicates;
|
||||
*/
|
||||
public class HostRequestPredicateFactory implements RequestPredicateFactory {
|
||||
|
||||
public static final String PATTERN_KEY = "pattern";
|
||||
private PathMatcher pathMatcher = new AntPathMatcher(".");
|
||||
|
||||
public void setPathMatcher(PathMatcher pathMatcher) {
|
||||
this.pathMatcher = pathMatcher;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> argNames() {
|
||||
return Collections.singletonList(PATTERN_KEY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequestPredicate apply(Tuple args) {
|
||||
validate(1, args);
|
||||
String pattern = args.getString(0);
|
||||
String pattern = args.getString(PATTERN_KEY);
|
||||
|
||||
return RequestPredicates.headers(headers -> {
|
||||
String host = headers.asHttpHeaders().getFirst("Host");
|
||||
|
||||
@@ -22,15 +22,24 @@ import org.springframework.tuple.Tuple;
|
||||
import org.springframework.web.reactive.function.server.RequestPredicate;
|
||||
import org.springframework.web.reactive.function.server.RequestPredicates;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
public class MethodRequestPredicateFactory implements RequestPredicateFactory {
|
||||
|
||||
public static final String METHOD_KEY = "method";
|
||||
|
||||
@Override
|
||||
public List<String> argNames() {
|
||||
return Arrays.asList(METHOD_KEY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequestPredicate apply(Tuple args) {
|
||||
validate(1, args);
|
||||
String method = args.getString(0);
|
||||
String method = args.getString(METHOD_KEY);
|
||||
return RequestPredicates.method(HttpMethod.resolve(method));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,18 +20,37 @@ package org.springframework.cloud.gateway.handler.predicate;
|
||||
import org.springframework.tuple.Tuple;
|
||||
import org.springframework.web.reactive.function.server.RequestPredicate;
|
||||
import org.springframework.web.reactive.function.server.RequestPredicates;
|
||||
import org.springframework.web.util.patterns.PathPatternParser;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
public class PathRequestPredicateFactory implements RequestPredicateFactory {
|
||||
|
||||
public static final String PATTERN_KEY = "pattern";
|
||||
|
||||
private PathPatternParser pathPatternParser;
|
||||
|
||||
public void setPathPatternParser(PathPatternParser pathPatternParser) {
|
||||
this.pathPatternParser = pathPatternParser;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> argNames() {
|
||||
return Collections.singletonList(PATTERN_KEY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequestPredicate apply(Tuple args) {
|
||||
validate(1, args);
|
||||
String pattern = args.getString(0);
|
||||
String pattern = args.getString(PATTERN_KEY);
|
||||
|
||||
if (this.pathPatternParser != null) {
|
||||
return RequestPredicates.pathPredicates(this.pathPatternParser).apply(pattern);
|
||||
}
|
||||
|
||||
//TODO: support custom PathPatternParser
|
||||
return RequestPredicates.path(pattern);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,17 +22,33 @@ import org.springframework.web.reactive.function.server.PublicDefaultServerReque
|
||||
import org.springframework.web.reactive.function.server.RequestPredicate;
|
||||
import org.springframework.web.reactive.function.server.RequestPredicates;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
public class QueryRequestPredicateFactory implements RequestPredicateFactory {
|
||||
|
||||
public static final String PARAM_KEY = "param";
|
||||
public static final String REGEXP_KEY = "regexp";
|
||||
|
||||
@Override
|
||||
public List<String> argNames() {
|
||||
return Arrays.asList(PARAM_KEY, REGEXP_KEY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validateArgSize() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequestPredicate apply(Tuple args) {
|
||||
validate(1, args);
|
||||
String param = args.getString(0);
|
||||
String param = args.getString(PARAM_KEY);
|
||||
|
||||
if (args.size() < 2) {
|
||||
if (!args.hasFieldName(REGEXP_KEY)) {
|
||||
return req -> {
|
||||
//TODO: ServerRequest support for query params with no value
|
||||
PublicDefaultServerRequest request = (PublicDefaultServerRequest) req;
|
||||
@@ -40,7 +56,7 @@ public class QueryRequestPredicateFactory implements RequestPredicateFactory {
|
||||
};
|
||||
}
|
||||
|
||||
String regexp = args.getString(1);
|
||||
String regexp = args.getString(REGEXP_KEY);
|
||||
|
||||
return RequestPredicates.queryParam(param, value -> value.matches(regexp));
|
||||
}
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
|
||||
package org.springframework.cloud.gateway.handler.predicate;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.tuple.Tuple;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.reactive.function.server.RequestPredicate;
|
||||
@@ -28,6 +31,18 @@ public interface RequestPredicateFactory {
|
||||
|
||||
RequestPredicate apply(Tuple args);
|
||||
|
||||
/**
|
||||
* Returns hints about the number of args and the order for shortcut parsing.
|
||||
* @return
|
||||
*/
|
||||
default List<String> argNames() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
default boolean validateArgSize() {
|
||||
return true;
|
||||
}
|
||||
|
||||
default void validate(int minimumSize, Tuple args) {
|
||||
Assert.isTrue(args != null && args.size() >= minimumSize,
|
||||
"args must have at least "+ minimumSize +" entry(s)");
|
||||
|
||||
@@ -24,7 +24,7 @@ import org.springframework.cloud.gateway.handler.predicate.RequestPredicateFacto
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
public class NameUtils {
|
||||
public static final String GENERATED_NAME_PREFIX = "__:_._gen__+_";
|
||||
public static final String GENERATED_NAME_PREFIX = "_genkey_";
|
||||
|
||||
public static String generateName(int i) {
|
||||
return GENERATED_NAME_PREFIX + i;
|
||||
|
||||
@@ -20,6 +20,7 @@ package org.springframework.cloud.gateway.handler.predicate;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.cloud.gateway.handler.predicate.AfterRequestPredicateFactory.DATETIME_KEY;
|
||||
import static org.springframework.cloud.gateway.handler.predicate.BetweenRequestPredicateFactoryTests.getRequest;
|
||||
import static org.springframework.cloud.gateway.handler.predicate.BetweenRequestPredicateFactoryTests.minusHours;
|
||||
import static org.springframework.cloud.gateway.handler.predicate.BetweenRequestPredicateFactoryTests.minusHoursMillis;
|
||||
@@ -69,6 +70,6 @@ public class AfterRequestPredicateFactoryTests {
|
||||
}
|
||||
|
||||
private boolean runPredicate(String dateString) {
|
||||
return new AfterRequestPredicateFactory().apply(tuple().of("1", dateString)).test(getRequest());
|
||||
return new AfterRequestPredicateFactory().apply(tuple().of(DATETIME_KEY, dateString)).test(getRequest());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ package org.springframework.cloud.gateway.handler.predicate;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.cloud.gateway.handler.predicate.BeforeRequestPredicateFactory.DATETIME_KEY;
|
||||
import static org.springframework.cloud.gateway.handler.predicate.BetweenRequestPredicateFactoryTests.getRequest;
|
||||
import static org.springframework.cloud.gateway.handler.predicate.BetweenRequestPredicateFactoryTests.minusHours;
|
||||
import static org.springframework.cloud.gateway.handler.predicate.BetweenRequestPredicateFactoryTests.minusHoursMillis;
|
||||
@@ -69,6 +70,6 @@ public class BeforeRequestPredicateFactoryTests {
|
||||
}
|
||||
|
||||
private boolean runPredicate(String dateString) {
|
||||
return new BeforeRequestPredicateFactory().apply(tuple().of("1", dateString)).test(getRequest());
|
||||
return new BeforeRequestPredicateFactory().apply(tuple().of(DATETIME_KEY, dateString)).test(getRequest());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,8 @@ import org.springframework.web.reactive.function.server.ServerRequest;
|
||||
import org.springframework.web.server.adapter.DefaultServerWebExchange;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.cloud.gateway.handler.predicate.BetweenRequestPredicateFactory.DATETIME1_KEY;
|
||||
import static org.springframework.cloud.gateway.handler.predicate.BetweenRequestPredicateFactory.DATETIME2_KEY;
|
||||
import static org.springframework.tuple.TupleBuilder.tuple;
|
||||
|
||||
/**
|
||||
@@ -96,7 +98,8 @@ public class BetweenRequestPredicateFactoryTests {
|
||||
}
|
||||
|
||||
boolean runPredicate(String dateString1, String dateString2) {
|
||||
return new BetweenRequestPredicateFactory().apply(tuple().of("1", dateString1, "2", dateString2)).test(getRequest());
|
||||
return new BetweenRequestPredicateFactory().apply(tuple()
|
||||
.of(DATETIME1_KEY, dateString1, DATETIME2_KEY, dateString2)).test(getRequest());
|
||||
}
|
||||
|
||||
static String minusHoursMillis(int hours) {
|
||||
|
||||
@@ -180,7 +180,7 @@ spring:
|
||||
predicates:
|
||||
- name: Path
|
||||
args:
|
||||
path: /**
|
||||
pattern: /**
|
||||
|
||||
#myservice:
|
||||
# ribbon:
|
||||
|
||||
Reference in New Issue
Block a user