From 345329674e21556990b6e59459e8d6c6927bd89b Mon Sep 17 00:00:00 2001 From: Spencer Gibb Date: Fri, 20 Jan 2017 18:51:44 -0700 Subject: [PATCH] Add BetweenRoutePredicate --- .../config/GatewayAutoConfiguration.java | 6 + .../predicate/BetweenRoutePredicate.java | 46 ++++++++ .../predicate/BetweenRoutePredicateTests.java | 105 ++++++++++++++++++ 3 files changed, 157 insertions(+) create mode 100644 src/main/java/org/springframework/cloud/gateway/handler/predicate/BetweenRoutePredicate.java create mode 100644 src/test/java/org/springframework/cloud/gateway/handler/predicate/BetweenRoutePredicateTests.java diff --git a/src/main/java/org/springframework/cloud/gateway/config/GatewayAutoConfiguration.java b/src/main/java/org/springframework/cloud/gateway/config/GatewayAutoConfiguration.java index 85cc634e..9a73e6b1 100644 --- a/src/main/java/org/springframework/cloud/gateway/config/GatewayAutoConfiguration.java +++ b/src/main/java/org/springframework/cloud/gateway/config/GatewayAutoConfiguration.java @@ -33,6 +33,7 @@ import org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping; import org.springframework.cloud.gateway.handler.RoutingWebHandler; import org.springframework.cloud.gateway.handler.predicate.AfterRoutePredicate; import org.springframework.cloud.gateway.handler.predicate.BeforeRoutePredicate; +import org.springframework.cloud.gateway.handler.predicate.BetweenRoutePredicate; import org.springframework.cloud.gateway.handler.predicate.CookieRoutePredicate; import org.springframework.cloud.gateway.handler.predicate.HeaderRoutePredicate; import org.springframework.cloud.gateway.handler.predicate.HostRoutePredicate; @@ -130,6 +131,11 @@ public class GatewayAutoConfiguration { return new BeforeRoutePredicate(); } + @Bean(name = "BetweenRoutePredicate") + public BetweenRoutePredicate betweenRoutePredicate() { + return new BetweenRoutePredicate(); + } + @Bean(name = "CookieRoutePredicate") public CookieRoutePredicate cookieRoutePredicate() { return new CookieRoutePredicate(); diff --git a/src/main/java/org/springframework/cloud/gateway/handler/predicate/BetweenRoutePredicate.java b/src/main/java/org/springframework/cloud/gateway/handler/predicate/BetweenRoutePredicate.java new file mode 100644 index 00000000..22404ae5 --- /dev/null +++ b/src/main/java/org/springframework/cloud/gateway/handler/predicate/BetweenRoutePredicate.java @@ -0,0 +1,46 @@ +package org.springframework.cloud.gateway.handler.predicate; + +import java.time.Instant; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.util.function.Predicate; + +import org.springframework.util.Assert; +import org.springframework.web.server.ServerWebExchange; + +/** + * @author Spencer Gibb + */ +public class BetweenRoutePredicate implements RoutePredicate { + + @Override + public Predicate apply(String dateString, String[] args) { + validate(args, 1); + + //TODO: is ZonedDateTime the right thing to use? + final ZonedDateTime dateTime1 = parseZonedDateTime(dateString); + final ZonedDateTime dateTime2 = parseZonedDateTime(args[0]); + Assert.isTrue(dateTime1.isBefore(dateTime2)); + + return exchange -> { + final ZonedDateTime now = ZonedDateTime.now(); + return now.isAfter(dateTime1) && now.isBefore(dateTime2); + }; + } + + public static ZonedDateTime parseZonedDateTime(String dateString) { + ZonedDateTime dateTime; + try { + long epoch = Long.parseLong(dateString); + + dateTime = Instant.ofEpochMilli(epoch).atOffset(ZoneOffset.ofTotalSeconds(0)) + .toZonedDateTime(); + } catch (NumberFormatException e) { + // try ZonedDateTime instead + dateTime = ZonedDateTime.parse(dateString); + } + + return dateTime; + } + +} diff --git a/src/test/java/org/springframework/cloud/gateway/handler/predicate/BetweenRoutePredicateTests.java b/src/test/java/org/springframework/cloud/gateway/handler/predicate/BetweenRoutePredicateTests.java new file mode 100644 index 00000000..d76a36a7 --- /dev/null +++ b/src/test/java/org/springframework/cloud/gateway/handler/predicate/BetweenRoutePredicateTests.java @@ -0,0 +1,105 @@ +package org.springframework.cloud.gateway.handler.predicate; + +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; + +import org.junit.Test; +import org.springframework.mock.http.server.reactive.MockServerHttpRequest; +import org.springframework.mock.http.server.reactive.MockServerHttpResponse; +import org.springframework.web.server.ServerWebExchange; +import org.springframework.web.server.adapter.DefaultServerWebExchange; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author Spencer Gibb + */ +public class BetweenRoutePredicateTests { + + @Test + public void beforeStringWorks() { + String dateString1 = plusHours(1); + String dateString2 = plusHours(2); + + final boolean result = runPredicate(dateString1, dateString2); + + assertThat(result).as("Now is not before %s", dateString1).isFalse(); + } + + @Test + public void betweenStringWorks() { + String dateString1 = minusHours(1); + String dateString2 = plusHours(1); + + final boolean result = runPredicate(dateString1, dateString2); + + assertThat(result).as("Now is not between %s and %s", dateString1, dateString2).isTrue(); + } + + @Test + public void afterStringWorks() { + String dateString1 = minusHours(2); + String dateString2 = minusHours(1); + + final boolean result = runPredicate(dateString1, dateString2); + + assertThat(result).as("Now is not after %s", dateString2).isFalse(); + } + + @Test + public void beforeEpochWorks() { + String dateString1 = plusHoursMillis(1); + String dateString2 = plusHoursMillis(2); + + final boolean result = runPredicate(dateString1, dateString2); + + assertThat(result).as("Now is not before %s", dateString1).isFalse(); + } + + @Test + public void betweenEpochWorks() { + String dateString1 = minusHoursMillis(1); + String dateString2 = plusHoursMillis(1); + + final boolean result = runPredicate(dateString1, dateString2); + + assertThat(result).as("Now is not between %s and %s", dateString1, dateString2).isTrue(); + } + + @Test + public void afterEpochWorks() { + String dateString1 = minusHoursMillis(2); + String dateString2 = minusHoursMillis(1); + + final boolean result = runPredicate(dateString1, dateString2); + + assertThat(result).as("Now is not after %s", dateString1).isFalse(); + } + + boolean runPredicate(String dateString1, String dateString2) { + return new BetweenRoutePredicate().apply(dateString1, new String[]{dateString2}).test(getExchange()); + } + + static String minusHoursMillis(int hours) { + final int millis = hours * 1000 * 60 * 60; + return String.valueOf(System.currentTimeMillis() - millis); + } + + static String plusHoursMillis(int hours) { + final int millis = hours * 1000 * 60 * 60; + return String.valueOf(System.currentTimeMillis() + millis); + } + + static String minusHours(int hours) { + return ZonedDateTime.now().minusHours(hours).format(DateTimeFormatter.ISO_ZONED_DATE_TIME); + } + + static String plusHours(int hours) { + return ZonedDateTime.now().plusHours(hours).format(DateTimeFormatter.ISO_ZONED_DATE_TIME); + } + + static ServerWebExchange getExchange() { + final MockServerHttpRequest request = MockServerHttpRequest.get("http://example.com").build(); + return new DefaultServerWebExchange(request, new MockServerHttpResponse()); + } +}