From 6936c83b18b42b3a8bf75ec1f4f2a7ca672e24c8 Mon Sep 17 00:00:00 2001 From: Spencer Gibb Date: Wed, 11 Dec 2019 15:06:37 -0500 Subject: [PATCH] Moves blocking random uuid to route definition locator. This allows the blocking calls to be put on the elastic scheduler. --- .../CompositeRouteDefinitionLocator.java | 30 ++++++++- .../InMemoryRouteDefinitionRepository.java | 4 ++ .../cloud/gateway/route/RouteDefinition.java | 4 +- .../route/RouteDefinitionDefaultIdTests.java | 61 +++++++++++++++++++ .../test/resources/application-defaultid.yml | 11 ++++ 5 files changed, 106 insertions(+), 4 deletions(-) create mode 100644 spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/route/RouteDefinitionDefaultIdTests.java create mode 100644 spring-cloud-gateway-core/src/test/resources/application-defaultid.yml diff --git a/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/route/CompositeRouteDefinitionLocator.java b/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/route/CompositeRouteDefinitionLocator.java index fbef41b6..58342d2c 100644 --- a/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/route/CompositeRouteDefinitionLocator.java +++ b/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/route/CompositeRouteDefinitionLocator.java @@ -16,22 +16,50 @@ package org.springframework.cloud.gateway.route; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import reactor.core.scheduler.Schedulers; + +import org.springframework.util.AlternativeJdkIdGenerator; +import org.springframework.util.IdGenerator; /** * @author Spencer Gibb */ public class CompositeRouteDefinitionLocator implements RouteDefinitionLocator { + private static final Log log = LogFactory + .getLog(CompositeRouteDefinitionLocator.class); + private final Flux delegates; + private final IdGenerator idGenerator; + public CompositeRouteDefinitionLocator(Flux delegates) { + this(delegates, new AlternativeJdkIdGenerator()); + } + + public CompositeRouteDefinitionLocator(Flux delegates, + IdGenerator idGenerator) { this.delegates = delegates; + this.idGenerator = idGenerator; } @Override public Flux getRouteDefinitions() { - return this.delegates.flatMap(RouteDefinitionLocator::getRouteDefinitions); + return this.delegates.flatMap(RouteDefinitionLocator::getRouteDefinitions) + .flatMap(routeDefinition -> Mono.justOrEmpty(routeDefinition.getId()) + .defaultIfEmpty(idGenerator.generateId().toString()) + .publishOn(Schedulers.elastic()).map(id -> { + routeDefinition.setId(id); + if (log.isDebugEnabled()) { + log.debug( + "Id set on route definition: " + routeDefinition); + } + return routeDefinition; + })); } } diff --git a/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/route/InMemoryRouteDefinitionRepository.java b/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/route/InMemoryRouteDefinitionRepository.java index 7cf734e8..10aca9d2 100644 --- a/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/route/InMemoryRouteDefinitionRepository.java +++ b/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/route/InMemoryRouteDefinitionRepository.java @@ -23,6 +23,7 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import org.springframework.cloud.gateway.support.NotFoundException; +import org.springframework.util.StringUtils; import static java.util.Collections.synchronizedMap; @@ -37,6 +38,9 @@ public class InMemoryRouteDefinitionRepository implements RouteDefinitionReposit @Override public Mono save(Mono route) { return route.flatMap(r -> { + if (StringUtils.isEmpty(r.getId())) { + return Mono.error(new IllegalArgumentException("id may not be empty")); + } routes.put(r.getId(), r); return Mono.empty(); }); diff --git a/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/route/RouteDefinition.java b/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/route/RouteDefinition.java index 8c4e2aff..ba7b699c 100644 --- a/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/route/RouteDefinition.java +++ b/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/route/RouteDefinition.java @@ -20,7 +20,6 @@ import java.net.URI; import java.util.ArrayList; import java.util.List; import java.util.Objects; -import java.util.UUID; import javax.validation.Valid; import javax.validation.ValidationException; @@ -39,8 +38,7 @@ import static org.springframework.util.StringUtils.tokenizeToStringArray; @Validated public class RouteDefinition { - @NotEmpty - private String id = UUID.randomUUID().toString(); + private String id; @NotEmpty @Valid diff --git a/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/route/RouteDefinitionDefaultIdTests.java b/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/route/RouteDefinitionDefaultIdTests.java new file mode 100644 index 00000000..8e28bad5 --- /dev/null +++ b/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/route/RouteDefinitionDefaultIdTests.java @@ -0,0 +1,61 @@ +/* + * Copyright 2013-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.cloud.gateway.route; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringBootConfiguration; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cloud.gateway.config.GatewayProperties; +import org.springframework.cloud.gateway.test.BaseWebClientTests; +import org.springframework.context.annotation.Import; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.web.bind.annotation.RestController; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; + +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = RANDOM_PORT) +@DirtiesContext +@ActiveProfiles("defaultid") +public class RouteDefinitionDefaultIdTests { + + @Autowired + private GatewayProperties properties; + + @Test + public void testDefaultIdWorks() { + assertThat(properties.getRoutes()).hasSize(1); + RouteDefinition routeDefinition = properties.getRoutes().get(0); + assertThat(routeDefinition.getId()).isNotNull(); + } + + @EnableAutoConfiguration + @SpringBootConfiguration + @Import(BaseWebClientTests.DefaultTestConfig.class) + @RestController + public static class TestConfig { + + } + +} diff --git a/spring-cloud-gateway-core/src/test/resources/application-defaultid.yml b/spring-cloud-gateway-core/src/test/resources/application-defaultid.yml new file mode 100644 index 00000000..ecb94e4c --- /dev/null +++ b/spring-cloud-gateway-core/src/test/resources/application-defaultid.yml @@ -0,0 +1,11 @@ +spring: + cloud: + gateway: + default-filters: + - PrefixPath=/httpbin + routes: + - uri: https://defaultrouteid.example.org + order: 10000 + predicates: + - Path=/defaultrouteid/** +