diff --git a/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/filter/factory/WebFilterFactory.java b/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/filter/factory/WebFilterFactory.java index f8777a4f..25d81396 100644 --- a/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/filter/factory/WebFilterFactory.java +++ b/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/filter/factory/WebFilterFactory.java @@ -17,49 +17,23 @@ package org.springframework.cloud.gateway.filter.factory; +import org.springframework.cloud.gateway.support.ArgumentHints; import org.springframework.cloud.gateway.support.NameUtils; import org.springframework.tuple.Tuple; -import org.springframework.util.Assert; import org.springframework.web.server.WebFilter; -import java.util.Collections; -import java.util.List; - /** * @author Spencer Gibb */ @FunctionalInterface -public interface WebFilterFactory { +public interface WebFilterFactory extends ArgumentHints { String NAME_KEY = "name"; String VALUE_KEY = "value"; - //TODO: move from String... to Tuple WebFilter apply(Tuple args); default String name() { return NameUtils.normalizeFilterName(getClass()); } - - /** - * Returns hints about the number of args and the order for shortcut parsing. - * @return - */ - default List argNames() { - return Collections.emptyList(); - } - - /** - * Validate supplied argument size against {@see #argNames} size. - * Useful for variable arg predicates. - * @return - */ - default boolean validateArgs() { - return true; - } - - default void validate(int requiredSize, Tuple args) { - Assert.isTrue(args != null && args.size() == requiredSize, - "args must have "+ requiredSize +" entry(s)"); - } } diff --git a/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/handler/predicate/RequestPredicateFactory.java b/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/handler/predicate/RequestPredicateFactory.java index 2ec259e5..bb360f7c 100644 --- a/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/handler/predicate/RequestPredicateFactory.java +++ b/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/handler/predicate/RequestPredicateFactory.java @@ -17,19 +17,16 @@ package org.springframework.cloud.gateway.handler.predicate; -import java.util.Collections; -import java.util.List; - +import org.springframework.cloud.gateway.support.ArgumentHints; import org.springframework.cloud.gateway.support.NameUtils; import org.springframework.tuple.Tuple; -import org.springframework.util.Assert; import org.springframework.web.reactive.function.server.RequestPredicate; /** * @author Spencer Gibb */ @FunctionalInterface -public interface RequestPredicateFactory { +public interface RequestPredicateFactory extends ArgumentHints { RequestPredicate apply(Tuple args); @@ -37,25 +34,4 @@ public interface RequestPredicateFactory { return NameUtils.normalizePredicateName(getClass()); } - /** - * Returns hints about the number of args and the order for shortcut parsing. - * @return - */ - default List argNames() { - return Collections.emptyList(); - } - - /** - * Auto validate supplied argument size against {@see #argNames} size and that an arg for each key exists. - * Useful for variable arg predicates. - * @return - */ - default boolean validateArgs() { - return true; - } - - default void validate(int minimumSize, Tuple args) { - Assert.isTrue(args != null && args.size() >= minimumSize, - "args must have at least "+ minimumSize +" entry(s)"); - } } diff --git a/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/model/Route.java b/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/model/Route.java index a654a661..c048d669 100644 --- a/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/model/Route.java +++ b/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/model/Route.java @@ -19,6 +19,7 @@ package org.springframework.cloud.gateway.model; import java.net.URI; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Objects; @@ -73,6 +74,11 @@ public class Route { return this; } + public Builder uri(String uri) { + this.uri = URI.create(uri); + return this; + } + public Builder uri(URI uri) { this.uri = uri; return this; @@ -93,6 +99,11 @@ public class Route { return this; } + public Builder addAll(Collection webFilter) { + this.webFilters.addAll(webFilter); + return this; + } + public Route build() { Assert.notNull(this.id, "id can not be null"); Assert.notNull(this.uri, "uri can not be null"); diff --git a/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/support/ArgumentHints.java b/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/support/ArgumentHints.java new file mode 100644 index 00000000..37c0acb5 --- /dev/null +++ b/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/support/ArgumentHints.java @@ -0,0 +1,52 @@ +/* + * Copyright 2013-2017 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 + * + * 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.springframework.cloud.gateway.support; + +import org.springframework.tuple.Tuple; +import org.springframework.util.Assert; + +import java.util.Collections; +import java.util.List; + +/** + * @author Spencer Gibb + */ +public interface ArgumentHints { + + /** + * Returns hints about the number of args and the order for shortcut parsing. + * @return + */ + default List argNames() { + return Collections.emptyList(); + } + + /** + * Validate supplied argument size against {@see #argNames} size. + * Useful for variable arg predicates. + * @return + */ + default boolean validateArgs() { + return true; + } + + default void validate(int requiredSize, Tuple args) { + Assert.isTrue(args != null && args.size() == requiredSize, + "args must have "+ requiredSize +" entry(s)"); + } +} diff --git a/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/support/RouteDefinitionRouteLocator.java b/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/support/RouteDefinitionRouteLocator.java index b908042b..5e68dfc1 100644 --- a/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/support/RouteDefinitionRouteLocator.java +++ b/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/support/RouteDefinitionRouteLocator.java @@ -124,7 +124,7 @@ public class RouteDefinitionRouteLocator implements RouteLocator { .build(); } - private Collection loadFilters(List filters) { + public static Collection loadFilters(List filters) { return filters.stream() .map(filter -> { WebFilterAdapter webFilter = new WebFilterAdapter(filter); @@ -148,42 +148,7 @@ public class RouteDefinitionRouteLocator implements RouteLocator { logger.debug("RouteDefinition " + id + " applying filter " + args + " to " + definition.getName()); } - //TODO: move Tuple building to common class, see RequestPredicateFactory.lookup - TupleBuilder builder = TupleBuilder.tuple(); - - List argNames = filter.argNames(); - if (!argNames.isEmpty()) { - // ensure size is the same for key replacement later - if (filter.validateArgs() && args.size() != argNames.size()) { - throw new IllegalArgumentException("Wrong number of arguments. Expected " + argNames - + " " + argNames + ". Found " + args.size() + " " + args + "'"); - } - } - - int entryIdx = 0; - for (Map.Entry 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(); - - if (filter.validateArgs()) { - for (String name : argNames) { - if (!tuple.hasFieldName(name)) { - throw new IllegalArgumentException("Missing argument '" + name + "'. Given " + tuple); - } - } - } + Tuple tuple = getTuple(filter, args); return filter.apply(tuple); }) @@ -197,6 +162,45 @@ public class RouteDefinitionRouteLocator implements RouteLocator { return ordered; } + private Tuple getTuple(ArgumentHints hasArguments, Map args) { + TupleBuilder builder = TupleBuilder.tuple(); + + List argNames = hasArguments.argNames(); + if (!argNames.isEmpty()) { + // ensure size is the same for key replacement later + if (hasArguments.validateArgs() && args.size() != argNames.size()) { + throw new IllegalArgumentException("Wrong number of arguments. Expected " + argNames + + " " + argNames + ". Found " + args.size() + " " + args + "'"); + } + } + + int entryIdx = 0; + for (Map.Entry 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(); + + if (hasArguments.validateArgs()) { + for (String name : argNames) { + if (!tuple.hasFieldName(name)) { + throw new IllegalArgumentException("Missing argument '" + name + "'. Given " + tuple); + } + } + } + return tuple; + } + private List getFilters(RouteDefinition routeDefinition) { //TODO: probably a java 8 stream way of doing this List combined = new ArrayList<>(loadFilters(this.globalFilters)); @@ -238,43 +242,7 @@ public class RouteDefinitionRouteLocator implements RouteLocator { + args + " to " + predicate.getName()); } - TupleBuilder builder = TupleBuilder.tuple(); - - List argNames = found.argNames(); - if (!argNames.isEmpty()) { - if (!argNames.isEmpty()) { - // ensure size is the same for key replacement later - if (found.validateArgs() && args.size() != argNames.size()) { - throw new IllegalArgumentException("Wrong number of arguments. Expected " + argNames - + " " + argNames + ". Found " + args.size() + " " + args + "'"); - } - } - } - - int entryIdx = 0; - for (Map.Entry 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(); - - if (found.validateArgs()) { - for (String name : argNames) { - if (!tuple.hasFieldName(name)) { - throw new IllegalArgumentException("Missing argument '" + name + "'. Given " + tuple); - } - } - } + Tuple tuple = getTuple(found, args); return found.apply(tuple); } @@ -302,7 +270,7 @@ public class RouteDefinitionRouteLocator implements RouteLocator { } } - public class OrderedWebFilter implements WebFilter, Ordered { + public static class OrderedWebFilter implements WebFilter, Ordered { private final WebFilter delegate; private final int order;