Extract ArgumentHints interface

This commit is contained in:
Spencer Gibb
2017-03-17 22:28:43 -06:00
parent c152efd523
commit 6880468482
5 changed files with 110 additions and 129 deletions

View File

@@ -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<String> 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)");
}
}

View File

@@ -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<String> 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)");
}
}

View File

@@ -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> 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");

View File

@@ -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<String> 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)");
}
}

View File

@@ -124,7 +124,7 @@ public class RouteDefinitionRouteLocator implements RouteLocator {
.build();
}
private Collection<WebFilter> loadFilters(List<GlobalFilter> filters) {
public static Collection<WebFilter> loadFilters(List<GlobalFilter> 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<String> 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<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();
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<String, String> args) {
TupleBuilder builder = TupleBuilder.tuple();
List<String> 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<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();
if (hasArguments.validateArgs()) {
for (String name : argNames) {
if (!tuple.hasFieldName(name)) {
throw new IllegalArgumentException("Missing argument '" + name + "'. Given " + tuple);
}
}
}
return tuple;
}
private List<WebFilter> getFilters(RouteDefinition routeDefinition) {
//TODO: probably a java 8 stream way of doing this
List<WebFilter> combined = new ArrayList<>(loadFilters(this.globalFilters));
@@ -238,43 +242,7 @@ public class RouteDefinitionRouteLocator implements RouteLocator {
+ args + " to " + predicate.getName());
}
TupleBuilder builder = TupleBuilder.tuple();
List<String> 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<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();
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;