You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by be...@apache.org on 2022/08/28 12:37:10 UTC
[tapestry-5] branch master updated: TAP5-2736: CookieBuilder maxAge java.time.Duration support
This is an automated email from the ASF dual-hosted git repository.
benw pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/tapestry-5.git
The following commit(s) were added to refs/heads/master by this push:
new 71638e9cf TAP5-2736: CookieBuilder maxAge java.time.Duration support
71638e9cf is described below
commit 71638e9cfef0ab598fc7c8e86f7db0c10d07150e
Author: Ben Weidig <be...@netzgut.net>
AuthorDate: Sun Aug 28 14:36:51 2022 +0200
TAP5-2736: CookieBuilder maxAge java.time.Duration support
---
.../commons/internal/BasicTypeCoercions.java | 10 +++++
.../java/org/apache/tapestry5/CookieBuilder.java | 33 +++++++++++++++
.../tapestry5/internal/services/CookiesImpl.java | 3 +-
.../internal/services/CookieBuilderSpec.groovy | 47 ++++++++++++++++++++++
.../test/groovy/ioc/specs/TypeCoercerSpec.groovy | 6 ++-
5 files changed, 97 insertions(+), 2 deletions(-)
diff --git a/commons/src/main/java/org/apache/tapestry5/commons/internal/BasicTypeCoercions.java b/commons/src/main/java/org/apache/tapestry5/commons/internal/BasicTypeCoercions.java
index ea5c7ed76..88251bfb6 100644
--- a/commons/src/main/java/org/apache/tapestry5/commons/internal/BasicTypeCoercions.java
+++ b/commons/src/main/java/org/apache/tapestry5/commons/internal/BasicTypeCoercions.java
@@ -33,6 +33,7 @@ import java.time.YearMonth;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
+import java.time.temporal.ChronoUnit;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
@@ -457,6 +458,15 @@ public class BasicTypeCoercions
{
add(configuration, Duration.class, Long.class, Duration::toNanos);
add(configuration, Long.class, Duration.class, Duration::ofNanos);
+ add(configuration, Duration.class, TimeInterval.class, input -> {
+ // Duration.toMillis() is Java 9+, so we need to do it ourselves
+ long millisFromSeconds = input.getSeconds() * 1_000L;
+ long millisFromNanos = input.getNano() / 1_000_000L;
+ return new TimeInterval(millisFromSeconds + millisFromNanos);
+ });
+ add(configuration, TimeInterval.class, Duration.class, input -> {
+ return Duration.ofMillis(input.milliseconds());
+ });
}
{
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/CookieBuilder.java b/tapestry-core/src/main/java/org/apache/tapestry5/CookieBuilder.java
index 076f41b21..5bcbba681 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/CookieBuilder.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/CookieBuilder.java
@@ -14,6 +14,8 @@
package org.apache.tapestry5;
+import java.time.Duration;
+
import org.apache.tapestry5.http.services.Request;
/**
@@ -87,6 +89,37 @@ public abstract class CookieBuilder
return this;
}
+
+ /**
+ * Set how long the cookie should live. A value of <code>java.time.Duration.ZERO</code> deletes a cookie,
+ * a negative value deletes a cookie upon closing the browser. The default is defined by
+ * the symbol <code>org.apache.tapestry5.default-cookie-max-age</code>. The factory default for
+ * this value is the equivalent of one week.
+ *
+ * @param maxAge
+ * the cookie's maximum age in seconds
+ * @return the modified {@link CookieBuilder}
+ *
+ * @since 5.8.3
+ */
+ public CookieBuilder setMaxAge(Duration duration)
+ {
+ long maxAgeAsLong = duration.getSeconds();
+ if (maxAgeAsLong < 0L)
+ {
+ this.maxAge = -1;
+ }
+ else if (maxAgeAsLong >= Integer.MAX_VALUE) {
+ this.maxAge = Integer.MAX_VALUE;
+ }
+ else
+ {
+ this.maxAge = (int) maxAgeAsLong;
+ }
+
+ return this;
+ }
+
/**
* Set the cookie's secure mode. Defaults to {@link Request#isSecure()}.
*
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/CookiesImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/CookiesImpl.java
index 5d898a5cc..cccda7de5 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/CookiesImpl.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/CookiesImpl.java
@@ -17,6 +17,7 @@ package org.apache.tapestry5.internal.services;
import javax.servlet.http.Cookie;
import org.apache.tapestry5.CookieBuilder;
+import org.apache.tapestry5.SymbolConstants;
import org.apache.tapestry5.commons.util.TimeInterval;
import org.apache.tapestry5.http.TapestryHttpSymbolConstants;
import org.apache.tapestry5.http.services.Request;
@@ -56,7 +57,7 @@ public class CookiesImpl implements Cookies
@Symbol(TapestryHttpSymbolConstants.CONTEXT_PATH)
String contextPath,
- @Symbol("tapestry.default-cookie-max-age") @IntermediateType(TimeInterval.class)
+ @Symbol(SymbolConstants.COOKIE_MAX_AGE) @IntermediateType(TimeInterval.class)
long defaultMaxAge)
{
this.request = request;
diff --git a/tapestry-core/src/test/groovy/org/apache/tapestry5/internal/services/CookieBuilderSpec.groovy b/tapestry-core/src/test/groovy/org/apache/tapestry5/internal/services/CookieBuilderSpec.groovy
new file mode 100644
index 000000000..568a623b2
--- /dev/null
+++ b/tapestry-core/src/test/groovy/org/apache/tapestry5/internal/services/CookieBuilderSpec.groovy
@@ -0,0 +1,47 @@
+package org.apache.tapestry5.internal.services
+
+import java.time.Duration
+
+import org.apache.tapestry5.internal.test.TestableRequestImpl
+
+import spock.lang.Specification
+
+class CookieBuilderSpec extends Specification {
+
+ static String CONTEXT_PATH = "/ctx"
+
+ def createCookiesFixture(cookies)
+ {
+
+ return new CookiesImpl(
+ new TestableRequestImpl(CONTEXT_PATH),
+ null,
+ [ addCookie: { cookies << it } ] as CookieSink,
+ CONTEXT_PATH,
+ 1_000L * 1_000L)
+ }
+
+ def "write Cookie with maxAge as Duration"()
+ {
+ given:
+ def cookies = []
+ def cookiesFixture = createCookiesFixture(cookies)
+
+ when:
+ def builder = cookiesFixture.getBuilder("name", "value")
+ builder.maxAge = maxAge
+ builder.write()
+
+ then:
+ cookies.size() == 1
+ cookies[0].maxAge == expectedMaxAge
+
+ where:
+ maxAge | expectedMaxAge
+ Duration.ZERO | 0
+ Duration.ofMillis(-2) | -1
+ Duration.ofHours(2L) | 60 * 60 * 2
+ Duration.ofSeconds(Integer.MAX_VALUE + 1L) | Integer.MAX_VALUE
+ }
+
+}
diff --git a/tapestry-ioc/src/test/groovy/ioc/specs/TypeCoercerSpec.groovy b/tapestry-ioc/src/test/groovy/ioc/specs/TypeCoercerSpec.groovy
index c9e358343..26f657727 100644
--- a/tapestry-ioc/src/test/groovy/ioc/specs/TypeCoercerSpec.groovy
+++ b/tapestry-ioc/src/test/groovy/ioc/specs/TypeCoercerSpec.groovy
@@ -180,7 +180,11 @@ class TypeCoercerSpec extends AbstractSharedRegistrySpecification {
"P12Y1M7D" | Period | Period.of(12, 1, 7)
ZonedDateTime.of(LocalDate.of(2020, 11, 29), LocalTime.of(13, 32, 12, 0), ZoneId.of("Europe/Berlin")).toEpochSecond() * 1_000 | Date | new Date(1606653132000L)
-
+
+ Duration.ofDays(7L) | TimeInterval | new TimeInterval("7 d");
+ Duration.ofMillis(1234L) | TimeInterval | new TimeInterval("1234 ms");
+ new TimeInterval("1d 3h 12ms") | Duration | Duration.ofDays(1L).plusHours(3L).plusMillis(12)
+
inputTypeName = PlasticUtils.toTypeName(input.getClass())
typeName = PlasticUtils.toTypeName(type)
}