[java-metadata-aggregator] branch master updated: MDA-181 - Review date and time handling for Java 8

Ian Young ian at iay.org.uk
Wed Mar 20 12:19:33 EDT 2019


This is an automated email from the git hooks/post-receive script.

iay pushed a commit to branch master
in repository java-metadata-aggregator.

View the commit online:
http://git.shibboleth.net/view/?p=java-metadata-aggregator.git;a=commit;h=188b7d451ef95ddd5d98847dc73605cec728ed74

The following commit(s) were added to refs/heads/master by this push:
       new  188b7d4   MDA-181 - Review date and time handling for Java 8
188b7d4 is described below

commit 188b7d451ef95ddd5d98847dc73605cec728ed74
Author: Ian Young <ian at iay.org.uk>
AuthorDate: Wed Mar 20 16:19:26 2019 +0000

    MDA-181 - Review date and time handling for Java 8
---
 .../dom/saml/PullUpCacheDurationStage.java         | 58 +++++++++--------
 .../metadata/dom/saml/PullUpValidUntilStage.java   | 75 +++++++++++-----------
 .../metadata/dom/saml/SetCacheDurationStage.java   | 36 ++++++-----
 .../metadata/dom/saml/SetValidUntilStage.java      | 39 ++++++-----
 .../metadata/dom/saml/ValidateValidUntilStage.java | 49 +++++++-------
 .../dom/saml/PullUpCacheDurationStageTest.java     | 17 ++---
 .../dom/saml/PullUpValidUntilStageTest.java        | 24 +++----
 .../dom/saml/SetCacheDurationStageSpringTest.java  |  5 +-
 .../dom/saml/SetCacheDurationStageTest.java        | 50 +++++++++++----
 .../dom/saml/SetValidUntilStageSpringTest.java     |  5 +-
 .../metadata/dom/saml/SetValidUntilStageTest.java  | 55 ++++++++++++----
 .../dom/saml/ValidateValidUntilStageTest.java      | 23 ++++---
 .../SetCacheDurationStageSpringTest-config.xml     |  4 +-
 .../saml/SetValidUntilStageSpringTest-config.xml   |  4 +-
 14 files changed, 263 insertions(+), 181 deletions(-)

diff --git a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/PullUpCacheDurationStage.java b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/PullUpCacheDurationStage.java
index 2bb2e02..d77b686 100644
--- a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/PullUpCacheDurationStage.java
+++ b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/PullUpCacheDurationStage.java
@@ -17,6 +17,7 @@
 
 package net.shibboleth.metadata.dom.saml;
 
+import java.time.Duration;
 import java.util.List;
 
 import javax.annotation.Nonnull;
@@ -43,17 +44,17 @@ import net.shibboleth.utilities.java.support.xml.ElementSupport;
 public class PullUpCacheDurationStage extends AbstractIteratingStage<Element> {
 
     /** The minimum cache duration in milliseconds. Default value: <code>0</code> */
-    private long minCacheDuration;
+    private Duration minCacheDuration = Duration.ZERO;
 
     /** The maximum cache duration in milliseconds. Default value: {@value java.lang.Long#MAX_VALUE} */
-    private long maxCacheDuration = Long.MAX_VALUE;
+    private Duration maxCacheDuration = Duration.ofMillis(Long.MAX_VALUE);
 
     /**
-     * Gets the minimum cache duration in milliseconds.
+     * Gets the minimum cache duration.
      * 
-     * @return minimum cache duration in milliseconds, always 0 or greater
+     * @return minimum cache duration, always 0 or greater
      */
-    public long getMinimumCacheDuration() {
+    public Duration getMinimumCacheDuration() {
         return minCacheDuration;
     }
 
@@ -62,43 +63,43 @@ public class PullUpCacheDurationStage extends AbstractIteratingStage<Element> {
      * 
      * @param duration the minimum cache duration in milliseconds
      */
-    public synchronized void setMinimumCacheDuration(final long duration) {
+    public synchronized void setMinimumCacheDuration(final Duration duration) {
         ComponentSupport.ifDestroyedThrowDestroyedComponentException(this);
         ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
 
-        if (duration < 0) {
-            minCacheDuration = 0;
+        if (duration.isNegative()) {
+            minCacheDuration = Duration.ZERO;
         } else {
             minCacheDuration = duration;
         }
     }
 
     /**
-     * Gets the maximum cache duration in milliseconds.
+     * Gets the maximum cache duration.
      * 
-     * @return maximum cache duration in milliseconds, always greater than 0
+     * @return maximum cache duration, always greater than 0
      */
-    public long getMaximumCacheDuration() {
+    public Duration getMaximumCacheDuration() {
         return maxCacheDuration;
     }
 
     /**
-     * Sets the maximum cache duration in milliseconds.
+     * Sets the maximum cache duration.
      * 
-     * @param duration maximum cache duration in milliseconds, must be greater than 0
+     * @param duration maximum cache duration, must be greater than 0
      */
-    public synchronized void setMaximumCacheDuration(final long duration) {
+    public synchronized void setMaximumCacheDuration(final Duration duration) {
         ComponentSupport.ifDestroyedThrowDestroyedComponentException(this);
         ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
 
-        Constraint.isGreaterThan(0, duration, "Maximum cache duration must be greater than 0");
+        Constraint.isGreaterThan(0, duration.toMillis(), "Maximum cache duration must be greater than 0");
         maxCacheDuration = duration;
     }
 
     @Override
     protected void doExecute(@Nonnull final Item<Element> item) throws StageProcessingException {
         final Element descriptor = item.unwrap();
-        final Long cacheDuration = getShortestCacheDuration(descriptor);
+        final Duration cacheDuration = getShortestCacheDuration(descriptor);
         setCacheDuration(descriptor, cacheDuration);
     }
 
@@ -110,18 +111,19 @@ public class PullUpCacheDurationStage extends AbstractIteratingStage<Element> {
      * @return the shortest cache duration from the descriptor and its descendants or null if the descriptor does not
      *         contain a cache duration
      */
-    protected Long getShortestCacheDuration(@Nonnull final Element descriptor) {
-        Long shortestCacheDuration = null;
+    protected Duration getShortestCacheDuration(@Nonnull final Element descriptor) {
+        Duration shortestCacheDuration = null;
         if (!SAMLMetadataSupport.isEntityOrEntitiesDescriptor(descriptor)) {
             return shortestCacheDuration;
         }
 
-        Long cacheDuration = null;
+        Duration cacheDuration = null;
         final List<Element> entitiesDescriptors =
                 ElementSupport.getChildElements(descriptor, SAMLMetadataSupport.ENTITIES_DESCRIPTOR_NAME);
         for (final Element entitiesDescriptor : entitiesDescriptors) {
             cacheDuration = getShortestCacheDuration(entitiesDescriptor);
-            if (cacheDuration != null && (shortestCacheDuration == null || (cacheDuration < shortestCacheDuration))) {
+            if (cacheDuration != null &&
+                    (shortestCacheDuration == null || (cacheDuration.compareTo(shortestCacheDuration) < 0))) {
                 shortestCacheDuration = cacheDuration;
             }
         }
@@ -130,7 +132,8 @@ public class PullUpCacheDurationStage extends AbstractIteratingStage<Element> {
                 ElementSupport.getChildElements(descriptor, SAMLMetadataSupport.ENTITY_DESCRIPTOR_NAME);
         for (final Element entityDescriptor : entityDescriptors) {
             cacheDuration = getShortestCacheDuration(entityDescriptor);
-            if (cacheDuration != null && (shortestCacheDuration == null || (cacheDuration < shortestCacheDuration))) {
+            if (cacheDuration != null &&
+                    (shortestCacheDuration == null || (cacheDuration.compareTo(shortestCacheDuration) < 0))) {
                 shortestCacheDuration = cacheDuration;
             }
         }
@@ -138,8 +141,9 @@ public class PullUpCacheDurationStage extends AbstractIteratingStage<Element> {
         final Attr cacheDurationAttr =
                 AttributeSupport.getAttribute(descriptor, SAMLMetadataSupport.CACHE_DURATION_ATTRIB_NAME);
         if (cacheDurationAttr != null) {
-            cacheDuration = AttributeSupport.getDurationAttributeValueAsLong(cacheDurationAttr);
-            if (cacheDuration != null && (shortestCacheDuration == null || (cacheDuration < shortestCacheDuration))) {
+            cacheDuration = AttributeSupport.getDurationAttributeValue(cacheDurationAttr);
+            if (cacheDuration != null &&
+                    (shortestCacheDuration == null || (cacheDuration.compareTo(shortestCacheDuration) < 0))) {
                 shortestCacheDuration = cacheDuration;
             }
 
@@ -158,15 +162,15 @@ public class PullUpCacheDurationStage extends AbstractIteratingStage<Element> {
      * @param descriptor entity or entities descriptor to receive the cache duration, never null
      * @param cacheDuration cache duration to be set, may be null
      */
-    protected void setCacheDuration(@Nonnull final Element descriptor, @Nullable final Long cacheDuration) {
-        if (cacheDuration == null || cacheDuration <= 0) {
+    protected void setCacheDuration(@Nonnull final Element descriptor, @Nullable final Duration cacheDuration) {
+        if (cacheDuration == null || cacheDuration.isNegative() || cacheDuration.isZero()) {
             return;
         }
 
-        if (cacheDuration < minCacheDuration) {
+        if (cacheDuration.compareTo(minCacheDuration) < 0) {
             AttributeSupport.appendDurationAttribute(descriptor, SAMLMetadataSupport.CACHE_DURATION_ATTRIB_NAME,
                     minCacheDuration);
-        } else if (cacheDuration > maxCacheDuration) {
+        } else if (cacheDuration.compareTo(maxCacheDuration) > 0) {
             AttributeSupport.appendDurationAttribute(descriptor, SAMLMetadataSupport.CACHE_DURATION_ATTRIB_NAME,
                     maxCacheDuration);
         } else {
diff --git a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/PullUpValidUntilStage.java b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/PullUpValidUntilStage.java
index be5a978..f279dca 100644
--- a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/PullUpValidUntilStage.java
+++ b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/PullUpValidUntilStage.java
@@ -17,6 +17,8 @@
 
 package net.shibboleth.metadata.dom.saml;
 
+import java.time.Duration;
+import java.time.Instant;
 import java.util.List;
 
 import javax.annotation.Nonnull;
@@ -42,89 +44,89 @@ import net.shibboleth.utilities.java.support.xml.ElementSupport;
 @ThreadSafe
 public class PullUpValidUntilStage extends AbstractIteratingStage<Element> {
 
-    /** The minimum amount of time, in milliseconds, a descriptor may be valid . Default value: 0 */
-    private long minValidityDuration;
+    /** The minimum amount of time a descriptor may be valid. Default value: 0 */
+    private Duration minValidityDuration = Duration.ZERO;
 
     /**
-     * The maximum amount of time, in milliseconds, a descriptor may be valid. Default value:
+     * The maximum amount of time a descriptor may be valid. Default value:
      * {@value java.lang.Long#MAX_VALUE}
      */
-    private long maxValidityDuration = Long.MAX_VALUE;
+    private Duration maxValidityDuration = Duration.ofMillis(Long.MAX_VALUE);
 
     /**
-     * Gets the minimum amount of time, in milliseconds, a descriptor may be valid.
+     * Gets the minimum amount of time a descriptor may be valid.
      * 
-     * @return minimum amount of time, in milliseconds, a descriptor may be valid, always 0 or greater
+     * @return minimum amount of time a descriptor may be valid, always 0 or greater
      */
-    public long getMinimumValidityDuration() {
+    public Duration getMinimumValidityDuration() {
         return minValidityDuration;
     }
 
     /**
-     * Sets the minimum amount of time, in milliseconds, a descriptor may be valid.
+     * Sets the minimum amount of time a descriptor may be valid.
      * 
-     * @param duration minimum amount of time, in milliseconds, a descriptor may be valid
+     * @param duration minimum amount of time a descriptor may be valid
      */
-    public synchronized void setMinimumValidityDuration(final long duration) {
+    public synchronized void setMinimumValidityDuration(@Nonnull final Duration duration) {
         ComponentSupport.ifDestroyedThrowDestroyedComponentException(this);
         ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
 
-        if (duration < 0) {
-            minValidityDuration = 0;
+        if (duration.isNegative()) {
+            minValidityDuration = Duration.ZERO;
         } else {
             minValidityDuration = duration;
         }
     }
 
     /**
-     * Gets the maximum amount of time, in milliseconds, a descriptor may be valid.
+     * Gets the maximum amount of time a descriptor may be valid.
      * 
-     * @return maximum maximum amount of time, in milliseconds, a descriptor may be valid, always greater than 0
+     * @return maximum maximum amount of time a descriptor may be valid, always greater than 0
      */
-    public long getMaximumValidityDuration() {
+    public Duration getMaximumValidityDuration() {
         return maxValidityDuration;
     }
 
     /**
-     * Sets the maximum amount of time, in milliseconds, a descriptor may be valid.
+     * Sets the maximum amount of time a descriptor may be valid.
      * 
-     * @param duration maximum amount of time, in milliseconds, a descriptor may be valid, must be greater than 0
+     * @param duration maximum amount of time a descriptor may be valid, must be greater than 0
      */
-    public synchronized void setMaximumValidityDuration(final long duration) {
+    public synchronized void setMaximumValidityDuration(@Nonnull final Duration duration) {
         ComponentSupport.ifDestroyedThrowDestroyedComponentException(this);
         ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
 
-        Constraint.isGreaterThan(0, duration, "Maximum validity duration must be greater than 0");
+        Constraint.isGreaterThan(0, duration.toMillis(), "Maximum validity duration must be greater than 0");
         maxValidityDuration = duration;
     }
 
     @Override
     protected void doExecute(@Nonnull final Item<Element> item) throws StageProcessingException {
         final Element descriptor = item.unwrap();
-        final Long nearestValidUntil = getNearestValidUntil(descriptor);
+        final Instant nearestValidUntil = getNearestValidUntil(descriptor);
         setValidUntil(descriptor, nearestValidUntil);
     }
 
     /**
-     * Gets the shorts cache duration for a given entity and entities descriptor an all its descendant descriptors.
+     * Gets the shortest cache duration for a given entity and entities descriptor and all its descendant descriptors.
      * 
      * @param descriptor descriptor from which to get the shortest cache duration
      * 
      * @return the shortest cache duration from the descriptor and its descendants or null if the descriptor does not
      *         contain a cache duration
      */
-    protected Long getNearestValidUntil(@Nonnull final Element descriptor) {
-        Long nearestValidUntil = null;
+    protected Instant getNearestValidUntil(@Nonnull final Element descriptor) {
+        Instant nearestValidUntil = null;
         if (!SAMLMetadataSupport.isEntityOrEntitiesDescriptor(descriptor)) {
             return nearestValidUntil;
         }
 
-        Long validUntil;
+        Instant validUntil;
         final List<Element> entitiesDescriptors =
                 ElementSupport.getChildElements(descriptor, SAMLMetadataSupport.ENTITIES_DESCRIPTOR_NAME);
         for (final Element entitiesDescriptor : entitiesDescriptors) {
             validUntil = getNearestValidUntil(entitiesDescriptor);
-            if (validUntil != null && (nearestValidUntil == null || (validUntil < nearestValidUntil))) {
+            if (validUntil != null && (nearestValidUntil == null || (validUntil.isBefore(nearestValidUntil)))) {
                 nearestValidUntil = validUntil;
             }
         }
@@ -133,7 +135,7 @@ public class PullUpValidUntilStage extends AbstractIteratingStage<Element> {
                 ElementSupport.getChildElements(descriptor, SAMLMetadataSupport.ENTITY_DESCRIPTOR_NAME);
         for (final Element entityDescriptor : entityDescriptors) {
             validUntil = getNearestValidUntil(entityDescriptor);
-            if (validUntil != null && (nearestValidUntil == null || (validUntil < nearestValidUntil))) {
+            if (validUntil != null && (nearestValidUntil == null || (validUntil.isBefore(nearestValidUntil)))) {
                 nearestValidUntil = validUntil;
             }
         }
@@ -141,8 +143,8 @@ public class PullUpValidUntilStage extends AbstractIteratingStage<Element> {
         final Attr validUntilAttr =
                 descriptor.getAttributeNodeNS(null, SAMLMetadataSupport.VALID_UNTIL_ATTRIB_NAME.getLocalPart());
         if (validUntilAttr != null) {
-            validUntil = AttributeSupport.getDateTimeAttributeAsLong(validUntilAttr);
-            if (validUntil != null && (nearestValidUntil == null || (validUntil < nearestValidUntil))) {
+            validUntil = AttributeSupport.getDateTimeAttribute(validUntilAttr);
+            if (validUntil != null && (nearestValidUntil == null || (validUntil.isBefore(nearestValidUntil)))) {
                 nearestValidUntil = validUntil;
             }
 
@@ -161,22 +163,19 @@ public class PullUpValidUntilStage extends AbstractIteratingStage<Element> {
      * @param descriptor entity or entities descriptor to receive the validUntil, never null
      * @param validUntil validUntil time to be set on the given descriptor
      */
-    protected void setValidUntil(@Nonnull final Element descriptor, @Nullable final Long validUntil) {
+    protected void setValidUntil(@Nonnull final Element descriptor, @Nullable final Instant validUntil) {
         if (validUntil == null) {
             return;
         }
 
-        final long now = System.currentTimeMillis();
-        final long minValidUntil = now + minValidityDuration;
-        long maxValidUntil = now + maxValidityDuration;
-        if (maxValidUntil < 0) {
-            maxValidUntil = Long.MAX_VALUE;
-        }
+        final Instant now = Instant.now();
+        final Instant minValidUntil = now.plus(minValidityDuration);
+        final Instant maxValidUntil = now.plus(maxValidityDuration);
 
-        final long boundedValidUntil;
-        if (validUntil < minValidUntil) {
+        final Instant boundedValidUntil;
+        if (validUntil.isBefore(minValidUntil)) {
             boundedValidUntil = minValidUntil;
-        } else if (validUntil > maxValidUntil) {
+        } else if (validUntil.isAfter(maxValidUntil)) {
             boundedValidUntil = maxValidUntil;
         } else {
             boundedValidUntil = validUntil;
diff --git a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/SetCacheDurationStage.java b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/SetCacheDurationStage.java
index aea8e61..f118542 100644
--- a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/SetCacheDurationStage.java
+++ b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/SetCacheDurationStage.java
@@ -17,6 +17,8 @@
 
 package net.shibboleth.metadata.dom.saml;
 
+import java.time.Duration;
+
 import javax.annotation.Nonnull;
 import javax.annotation.concurrent.ThreadSafe;
 
@@ -25,8 +27,7 @@ import org.w3c.dom.Element;
 import net.shibboleth.metadata.Item;
 import net.shibboleth.metadata.pipeline.AbstractIteratingStage;
 import net.shibboleth.metadata.pipeline.StageProcessingException;
-import net.shibboleth.utilities.java.support.annotation.Duration;
-import net.shibboleth.utilities.java.support.annotation.constraint.Positive;
+import net.shibboleth.utilities.java.support.annotation.constraint.NonnullAfterInit;
 import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
 import net.shibboleth.utilities.java.support.component.ComponentSupport;
 import net.shibboleth.utilities.java.support.logic.Constraint;
@@ -44,29 +45,32 @@ import net.shibboleth.utilities.java.support.xml.AttributeSupport;
 @ThreadSafe
 public class SetCacheDurationStage extends AbstractIteratingStage<Element> {
 
-    /** Cache duration, in milliseconds, that will be set on each metadata element. */
-    @Duration
-    private long cacheDuration;
+    /** Cache duration that will be set on each metadata element. */
+    @NonnullAfterInit private Duration cacheDuration;
 
     /**
-     * Gets the cache duration, in milliseconds, that will be set on each metadata element.
+     * Gets the cache duration that will be set on each metadata element.
      * 
-     * @return cache duration, in milliseconds
+     * @return cache duration
      */
-    public long getCacheDuration() {
+    public Duration getCacheDuration() {
         return cacheDuration;
     }
 
     /**
-     * Sets the cache duration, in milliseconds, that will be set on each metadata element.
+     * Sets the cache duration that will be set on each metadata element.
      * 
-     * @param duration cache duration, in milliseconds
+     * @param duration cache duration
      */
-    public synchronized void setCacheDuration(@Duration @Positive final long duration) {
+    public synchronized void setCacheDuration(@Nonnull final Duration duration) {
         ComponentSupport.ifDestroyedThrowDestroyedComponentException(this);
         ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
 
-        cacheDuration = Constraint.isGreaterThan(0, duration, "cache duration must be greater than 0");
+        Constraint.isNotNull(duration, "cache duration cannot be null");
+        Constraint.isFalse(duration.isZero(), "cache duration cannot be zero");
+        Constraint.isFalse(duration.isNegative(), "cache duration cannot be negative");
+
+        cacheDuration = duration;
     }
 
     @Override
@@ -79,12 +83,12 @@ public class SetCacheDurationStage extends AbstractIteratingStage<Element> {
         }
     }
 
-    /** {@inheritDoc} */
-    @Override protected void doInitialize() throws ComponentInitializationException {
+    @Override
+    protected void doInitialize() throws ComponentInitializationException {
         super.doInitialize();
 
-        if (cacheDuration <= 0) {
-            throw new ComponentInitializationException("cache duration must be greater than 0");
+        if (cacheDuration == null) {
+            throw new ComponentInitializationException("cache duration must be set");
         }
     }
 }
diff --git a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/SetValidUntilStage.java b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/SetValidUntilStage.java
index b5d4ad5..3392668 100644
--- a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/SetValidUntilStage.java
+++ b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/SetValidUntilStage.java
@@ -17,6 +17,9 @@
 
 package net.shibboleth.metadata.dom.saml;
 
+import java.time.Duration;
+import java.time.Instant;
+
 import javax.annotation.Nonnull;
 import javax.annotation.concurrent.ThreadSafe;
 
@@ -25,8 +28,7 @@ import org.w3c.dom.Element;
 import net.shibboleth.metadata.Item;
 import net.shibboleth.metadata.pipeline.AbstractIteratingStage;
 import net.shibboleth.metadata.pipeline.StageProcessingException;
-import net.shibboleth.utilities.java.support.annotation.Duration;
-import net.shibboleth.utilities.java.support.annotation.constraint.Positive;
+import net.shibboleth.utilities.java.support.annotation.constraint.NonnullAfterInit;
 import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
 import net.shibboleth.utilities.java.support.component.ComponentSupport;
 import net.shibboleth.utilities.java.support.logic.Constraint;
@@ -44,29 +46,32 @@ import net.shibboleth.utilities.java.support.xml.AttributeSupport;
 @ThreadSafe
 public class SetValidUntilStage extends AbstractIteratingStage<Element> {
 
-    /** Amount of time the descriptors will be valid, expressed in milliseconds. */
-    @Duration
-    private long validityDuration;
+    /** Amount of time the descriptors will be valid. */
+    @NonnullAfterInit private Duration validityDuration;
 
     /**
-     * Gets the amount of time the descriptors will be valid, expressed in milliseconds.
+     * Gets the amount of time the descriptors will be valid.
      * 
-     * @return amount of time the descriptors will be valid, expressed in milliseconds
+     * @return amount of time the descriptors will be valid
      */
-    public long getValidityDuration() {
+    public Duration getValidityDuration() {
         return validityDuration;
     }
 
     /**
-     * Sets the amount of time the descriptors will be valid, expressed in milliseconds.
+     * Sets the amount of time the descriptors will be valid.
      * 
-     * @param duration amount of time the descriptors will be valid, expressed in milliseconds
+     * @param duration amount of time the descriptors will be valid
      */
-    public synchronized void setValidityDuration(@Duration @Positive final long duration) {
+    public synchronized void setValidityDuration(@Nonnull final Duration duration) {
         ComponentSupport.ifDestroyedThrowDestroyedComponentException(this);
         ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
 
-        validityDuration = Constraint.isGreaterThan(0, duration, "validity duration must be greater than 0");
+        Constraint.isNotNull(duration, "validity duration cannot be null");
+        Constraint.isFalse(duration.isZero(), "validity duration cannot be zero");
+        Constraint.isFalse(duration.isNegative(), "validity duration cannot be negative");
+
+        validityDuration = duration;
     }
 
     @Override
@@ -75,16 +80,16 @@ public class SetValidUntilStage extends AbstractIteratingStage<Element> {
         if (SAMLMetadataSupport.isEntityOrEntitiesDescriptor(descriptor)) {
             AttributeSupport.removeAttribute(descriptor, SAMLMetadataSupport.VALID_UNTIL_ATTRIB_NAME);
             AttributeSupport.appendDateTimeAttribute(descriptor, SAMLMetadataSupport.VALID_UNTIL_ATTRIB_NAME,
-                    System.currentTimeMillis() + validityDuration);
+                    Instant.now().plus(validityDuration));
         }
     }
 
-    /** {@inheritDoc} */
-    @Override protected void doInitialize() throws ComponentInitializationException {
+    @Override
+    protected void doInitialize() throws ComponentInitializationException {
         super.doInitialize();
 
-        if (validityDuration <= 0) {
-            throw new ComponentInitializationException("validity duration must be greater than 0");
+        if (validityDuration == null) {
+            throw new ComponentInitializationException("validity duration must be set");
         }
     }
 }
diff --git a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/ValidateValidUntilStage.java b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/ValidateValidUntilStage.java
index 017ef26..5758294 100644
--- a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/ValidateValidUntilStage.java
+++ b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/ValidateValidUntilStage.java
@@ -17,6 +17,9 @@
 
 package net.shibboleth.metadata.dom.saml;
 
+import java.time.Duration;
+import java.time.Instant;
+
 import javax.annotation.Nonnull;
 import javax.annotation.concurrent.ThreadSafe;
 
@@ -26,8 +29,8 @@ import net.shibboleth.metadata.ErrorStatus;
 import net.shibboleth.metadata.Item;
 import net.shibboleth.metadata.pipeline.AbstractIteratingStage;
 import net.shibboleth.metadata.pipeline.StageProcessingException;
-import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
 import net.shibboleth.utilities.java.support.component.ComponentSupport;
+import net.shibboleth.utilities.java.support.logic.Constraint;
 import net.shibboleth.utilities.java.support.xml.AttributeSupport;
 
 /**
@@ -41,10 +44,10 @@ public class ValidateValidUntilStage extends AbstractIteratingStage<Element> {
     private boolean requireValidUntil = true;
 
     /**
-     * Interval, in milliseconds, from now within which the validUntil date must fall. A value of 0 indicates that no
+     * Interval from now within which the validUntil date must fall. A value of 0 indicates that no
      * maximum interval is checked. Default value: 1 week
      */
-    private long maxValidityInterval = 1000 * 60 * 60 * 24 * 7;
+    @Nonnull private Duration maxValidityInterval = Duration.ofDays(7);
 
     /**
      * Gets whether the item is required to have a validUntil attribute.
@@ -68,25 +71,28 @@ public class ValidateValidUntilStage extends AbstractIteratingStage<Element> {
     }
 
     /**
-     * Gets the interval, in milliseconds, from now within which the validUntil date must fall.
+     * Gets the interval from now within which the validUntil date must fall.
      * 
-     * @return Interval, in milliseconds, from now within which the validUntil date must fall
+     * @return Interval from now within which the validUntil date must fall
      */
-    public long getMaxValidityInterval() {
+    public Duration getMaxValidityInterval() {
         return maxValidityInterval;
     }
 
     /**
-     * Sets the interval, in milliseconds, from now within which the validUntil date must fall. A value of 0 indicates
+     * Sets the interval from now within which the validUntil date must fall. A value of 0 indicates
      * that there is no check on the upper bound of the validity period.
      * 
-     * @param interval interval, in milliseconds, from now within which the validUntil date must fall; must be greater
+     * @param interval interval from now within which the validUntil date must fall; must be greater
      *            than or equal to 0
      */
-    public synchronized void setMaxValidityInterval(final long interval) {
+    public synchronized void setMaxValidityInterval(@Nonnull final Duration interval) {
         ComponentSupport.ifDestroyedThrowDestroyedComponentException(this);
         ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
 
+        Constraint.isNotNull(interval, "max validity interval can not be null");
+        Constraint.isFalse(interval.isNegative(), "max validity interval can not be negative");
+
         maxValidityInterval = interval;
     }
 
@@ -98,35 +104,26 @@ public class ValidateValidUntilStage extends AbstractIteratingStage<Element> {
             return;
         }
 
-        final Long validUntil =
-                AttributeSupport.getDateTimeAttributeAsLong(AttributeSupport.getAttribute(element,
+        final Instant validUntil =
+                AttributeSupport.getDateTimeAttribute(AttributeSupport.getAttribute(element,
                         SAMLMetadataSupport.VALID_UNTIL_ATTRIB_NAME));
         if (validUntil == null) {
             if (requireValidUntil) {
                 item.getItemMetadata().put(new ErrorStatus(getId(), "Item does not include a validUntil attribute"));
             }
         } else {
-            final long lowerBound = System.currentTimeMillis();
-            if (validUntil < lowerBound) {
+            final var lowerBound = Instant.now();
+            if (validUntil.isBefore(lowerBound)) {
                 item.getItemMetadata().put(new ErrorStatus(getId(), "Item has a validUntil prior to the current time"));
             }
 
-            if (maxValidityInterval > 0) {
-                final long upperBound = lowerBound + maxValidityInterval;
-                if (validUntil > upperBound) {
+            if (!maxValidityInterval.isZero()) {
+                final var upperBound = lowerBound.plus(maxValidityInterval);
+                if (validUntil.isAfter(upperBound)) {
                     item.getItemMetadata().put(
                             new ErrorStatus(getId(), "Item has validUntil larger than the maximum validity interval"));
                 }
             }
         }
     }
-
-    /** {@inheritDoc} */
-    @Override protected void doInitialize() throws ComponentInitializationException {
-        super.doInitialize();
-
-        if (maxValidityInterval < 0) {
-            throw new ComponentInitializationException("Max validity interval must be greater than or equal to 0");
-        }
-    }
-}
\ No newline at end of file
+}
diff --git a/aggregator-pipeline/src/test/java/net/shibboleth/metadata/dom/saml/PullUpCacheDurationStageTest.java b/aggregator-pipeline/src/test/java/net/shibboleth/metadata/dom/saml/PullUpCacheDurationStageTest.java
index d7e55ef..f207a97 100644
--- a/aggregator-pipeline/src/test/java/net/shibboleth/metadata/dom/saml/PullUpCacheDurationStageTest.java
+++ b/aggregator-pipeline/src/test/java/net/shibboleth/metadata/dom/saml/PullUpCacheDurationStageTest.java
@@ -17,6 +17,7 @@
 
 package net.shibboleth.metadata.dom.saml;
 
+import java.time.Duration;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -56,8 +57,8 @@ public class PullUpCacheDurationStageTest extends BaseDOMTest {
                 .getAttribute(entitiesDescriptor, SAMLMetadataSupport.CACHE_DURATION_ATTRIB_NAME);
         Assert.assertNotNull(durationAttr);
 
-        long duration = AttributeSupport.getDurationAttributeValueAsLong(durationAttr);
-        Assert.assertEquals(duration, 1000 * 60 * 60);
+        final var duration = AttributeSupport.getDurationAttributeValue(durationAttr);
+        Assert.assertEquals(duration, Duration.ofHours(1));
 
         List<Element> entityDescriptors = ElementSupport.getChildElements(entitiesDescriptor,
                 SAMLMetadataSupport.ENTITY_DESCRIPTOR_NAME);
@@ -77,7 +78,7 @@ public class PullUpCacheDurationStageTest extends BaseDOMTest {
 
         PullUpCacheDurationStage stage = new PullUpCacheDurationStage();
         stage.setId("test");
-        stage.setMinimumCacheDuration(1000 * 60 * 60 * 2);
+        stage.setMinimumCacheDuration(Duration.ofHours(2));
         stage.initialize();
         
         stage.execute(metadataCollection);
@@ -87,8 +88,8 @@ public class PullUpCacheDurationStageTest extends BaseDOMTest {
                 .getAttribute(entitiesDescriptor, SAMLMetadataSupport.CACHE_DURATION_ATTRIB_NAME);
         Assert.assertNotNull(durationAttr);
 
-        long duration = AttributeSupport.getDurationAttributeValueAsLong(durationAttr);
-        Assert.assertEquals(duration, 1000 * 60 * 60 * 2);
+        final var duration = AttributeSupport.getDurationAttributeValue(durationAttr);
+        Assert.assertEquals(duration, Duration.ofHours(2));
     }
 
     /** Test that the maximum cache duration is used when the shortest duration is greater than it. */
@@ -99,7 +100,7 @@ public class PullUpCacheDurationStageTest extends BaseDOMTest {
 
         PullUpCacheDurationStage stage = new PullUpCacheDurationStage();
         stage.setId("test");
-        stage.setMaximumCacheDuration(1000 * 60 * 30);
+        stage.setMaximumCacheDuration(Duration.ofMinutes(30));
         stage.initialize();
         
         stage.execute(metadataCollection);
@@ -109,7 +110,7 @@ public class PullUpCacheDurationStageTest extends BaseDOMTest {
                 .getAttribute(entitiesDescriptor, SAMLMetadataSupport.CACHE_DURATION_ATTRIB_NAME);
         Assert.assertNotNull(durationAttr);
 
-        long duration = AttributeSupport.getDurationAttributeValueAsLong(durationAttr);
-        Assert.assertEquals(duration, 1000 * 60 * 30);
+        final var duration = AttributeSupport.getDurationAttributeValue(durationAttr);
+        Assert.assertEquals(duration, Duration.ofMinutes(30));
     }
 }
\ No newline at end of file
diff --git a/aggregator-pipeline/src/test/java/net/shibboleth/metadata/dom/saml/PullUpValidUntilStageTest.java b/aggregator-pipeline/src/test/java/net/shibboleth/metadata/dom/saml/PullUpValidUntilStageTest.java
index cd30a05..ada0260 100644
--- a/aggregator-pipeline/src/test/java/net/shibboleth/metadata/dom/saml/PullUpValidUntilStageTest.java
+++ b/aggregator-pipeline/src/test/java/net/shibboleth/metadata/dom/saml/PullUpValidUntilStageTest.java
@@ -17,6 +17,8 @@
 
 package net.shibboleth.metadata.dom.saml;
 
+import java.time.Duration;
+import java.time.Instant;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -56,8 +58,8 @@ public class PullUpValidUntilStageTest extends BaseDOMTest {
                 .getAttribute(entitiesDescriptor, SAMLMetadataSupport.VALID_UNTIL_ATTRIB_NAME);
         Assert.assertNotNull(validUntilAttr);
 
-        long validUntil = AttributeSupport.getDateTimeAttributeAsLong(validUntilAttr);
-        Assert.assertEquals(validUntil, 2429913600000L);
+        final var validUntil = AttributeSupport.getDateTimeAttribute(validUntilAttr);
+        Assert.assertEquals(validUntil.toEpochMilli(), 2429913600000L);
 
         List<Element> entityDescriptors = ElementSupport.getChildElements(entitiesDescriptor,
                 SAMLMetadataSupport.ENTITY_DESCRIPTOR_NAME);
@@ -75,7 +77,7 @@ public class PullUpValidUntilStageTest extends BaseDOMTest {
         final ArrayList<Item<Element>> metadataCollection = new ArrayList<>();
         metadataCollection.add(new DOMElementItem(readXMLData("in.xml")));
 
-        long hundredYears = 1000L * 60 * 60 * 24 * 365 * 100;
+        final var hundredYears = Duration.ofDays(365 * 100);
         
         PullUpValidUntilStage stage = new PullUpValidUntilStage();
         stage.setId("test");
@@ -89,8 +91,8 @@ public class PullUpValidUntilStageTest extends BaseDOMTest {
                 .getAttribute(entitiesDescriptor, SAMLMetadataSupport.VALID_UNTIL_ATTRIB_NAME);
         Assert.assertNotNull(validUntilAttr);
 
-        long validUntil = AttributeSupport.getDateTimeAttributeAsLong(validUntilAttr);
-        Assert.assertTrue(validUntil > System.currentTimeMillis() + hundredYears - 1000*60);
+        var validUntil = AttributeSupport.getDateTimeAttribute(validUntilAttr);
+        Assert.assertTrue(validUntil.isAfter(Instant.now().plus(hundredYears).minus(Duration.ofMinutes(1))));
     }
 
     /** Test that the maximum validUntil is used when the nearest validUntil is later than max duration + now. */
@@ -99,8 +101,8 @@ public class PullUpValidUntilStageTest extends BaseDOMTest {
         final ArrayList<Item<Element>> metadataCollection = new ArrayList<>();
         metadataCollection.add(new DOMElementItem(readXMLData("in.xml")));
 
-        long twoYears = 1000L * 60 * 60 * 24 * 365 * 2;
-        long twoYearsFromNow = twoYears + System.currentTimeMillis();
+        final var twoYears = Duration.ofDays(365 * 2);
+        final var twoYearsFromNow = Instant.now().plus(twoYears);
         
         PullUpValidUntilStage stage = new PullUpValidUntilStage();
         stage.setId("test");
@@ -114,10 +116,10 @@ public class PullUpValidUntilStageTest extends BaseDOMTest {
                 .getAttribute(entitiesDescriptor, SAMLMetadataSupport.VALID_UNTIL_ATTRIB_NAME);
         Assert.assertNotNull(validUntilAttr);
 
-        long validUntil = AttributeSupport.getDateTimeAttributeAsLong(validUntilAttr);
+        final var validUntil = AttributeSupport.getDateTimeAttribute(validUntilAttr);
 
-        long delta = 1000 * 10; // ten seconds permitted either side to allow for test execution time
-        Assert.assertTrue(validUntil < twoYearsFromNow + delta);
-        Assert.assertTrue(validUntil > twoYearsFromNow - delta);
+        final var delta = Duration.ofSeconds(10); // ten seconds permitted either side to allow for test execution time
+        Assert.assertTrue(validUntil.isBefore(twoYearsFromNow.plus(delta)));
+        Assert.assertTrue(validUntil.isAfter(twoYearsFromNow.minus(delta)));
     }
 }
\ No newline at end of file
diff --git a/aggregator-pipeline/src/test/java/net/shibboleth/metadata/dom/saml/SetCacheDurationStageSpringTest.java b/aggregator-pipeline/src/test/java/net/shibboleth/metadata/dom/saml/SetCacheDurationStageSpringTest.java
index d752f79..b1289f4 100644
--- a/aggregator-pipeline/src/test/java/net/shibboleth/metadata/dom/saml/SetCacheDurationStageSpringTest.java
+++ b/aggregator-pipeline/src/test/java/net/shibboleth/metadata/dom/saml/SetCacheDurationStageSpringTest.java
@@ -17,6 +17,8 @@
 
 package net.shibboleth.metadata.dom.saml;
 
+import java.time.Duration;
+
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.test.context.ContextConfiguration;
 import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
@@ -32,7 +34,8 @@ public class SetCacheDurationStageSpringTest extends AbstractTestNGSpringContext
     @Test
     public void testDuration() throws Exception {
         // one day, 17 hours, 34 minutes and 19 seconds = P1DT17H34M19S
-        Assert.assertEquals(stage.getCacheDuration(), 1000L * (86400 + 17*3600 + 34*60 + 19));
+        final var expectedDuration = Duration.ofDays(1).plusHours(17).plusMinutes(34).plusSeconds(19);
+        Assert.assertEquals(stage.getCacheDuration(), expectedDuration);
     }
 
 }
diff --git a/aggregator-pipeline/src/test/java/net/shibboleth/metadata/dom/saml/SetCacheDurationStageTest.java b/aggregator-pipeline/src/test/java/net/shibboleth/metadata/dom/saml/SetCacheDurationStageTest.java
index 3a571ef..41982cb 100644
--- a/aggregator-pipeline/src/test/java/net/shibboleth/metadata/dom/saml/SetCacheDurationStageTest.java
+++ b/aggregator-pipeline/src/test/java/net/shibboleth/metadata/dom/saml/SetCacheDurationStageTest.java
@@ -17,6 +17,7 @@
 
 package net.shibboleth.metadata.dom.saml;
 
+import java.time.Duration;
 import java.util.ArrayList;
 import java.util.Date;
 
@@ -46,19 +47,19 @@ public class SetCacheDurationStageTest extends BaseDOMTest {
     }
 
     /**
-     * Helper method to extract the value of a descriptor's XML duration attribute in milliseconds.
+     * Helper method to extract the value of a descriptor's XML duration attribute.
      * 
      * @param descriptor EntitiesDescriptor or EntityDescriptor to pull the attribute from
-     * @return the cache duration attribute value converted to milliseconds
+     * @return the cache duration attribute value converted to a {@link Duration}
      * @throws DatatypeConfigurationException if a {@link DatatypeFactory} can't be constructed
      */
-    private long fetchDuration(Element descriptor) throws DatatypeConfigurationException {
+    private Duration fetchDuration(Element descriptor) throws DatatypeConfigurationException {
         final Date baseDate = new Date(0);
         final DatatypeFactory dtf = DatatypeFactory.newInstance();
         final Attr cacheDurationAttr = AttributeSupport.getAttribute(descriptor,
                 SAMLMetadataSupport.CACHE_DURATION_ATTRIB_NAME);
         Assert.assertNotNull(cacheDurationAttr);
-        return dtf.newDuration(cacheDurationAttr.getValue()).getTimeInMillis(baseDate);
+        return Duration.ofMillis(dtf.newDuration(cacheDurationAttr.getValue()).getTimeInMillis(baseDate));
     }
     
     /**
@@ -76,7 +77,7 @@ public class SetCacheDurationStageTest extends BaseDOMTest {
         final ArrayList<Item<Element>> metadataCollection = new ArrayList<>();
         metadataCollection.add(item);
 
-        long duration = 123456;
+        final var duration = Duration.ofMillis(123456);
         SetCacheDurationStage stage = new SetCacheDurationStage();
         stage.setId("test");
         stage.setCacheDuration(duration);
@@ -97,7 +98,7 @@ public class SetCacheDurationStageTest extends BaseDOMTest {
         final Element entitiesDescriptor = readXMLData("in.xml");
         final Item<Element> item = new DOMElementItem(entitiesDescriptor);
         
-        final long originalDuration = 987654;
+        final var originalDuration = Duration.ofMillis(987654);
         AttributeSupport.appendDurationAttribute(entitiesDescriptor, SAMLMetadataSupport.CACHE_DURATION_ATTRIB_NAME,
                 originalDuration);
 
@@ -107,7 +108,7 @@ public class SetCacheDurationStageTest extends BaseDOMTest {
         final ArrayList<Item<Element>> metadataCollection = new ArrayList<>();
         metadataCollection.add(item);
 
-        long duration = 123456;
+        final var duration = Duration.ofMillis(123456);
         SetCacheDurationStage stage = new SetCacheDurationStage();
         stage.setId("test");
         stage.setCacheDuration(duration);
@@ -135,7 +136,7 @@ public class SetCacheDurationStageTest extends BaseDOMTest {
         final ArrayList<Item<Element>> metadataCollection = new ArrayList<>();
         metadataCollection.add(new DOMElementItem(root));
 
-        long duration = 123456;
+        final var duration = Duration.ofMillis(123456);
         SetCacheDurationStage stage = new SetCacheDurationStage();
         stage.setId("test");
         stage.setCacheDuration(duration);
@@ -150,16 +151,43 @@ public class SetCacheDurationStageTest extends BaseDOMTest {
     /** Tests that the stage properly rejects negative durations. */
     @Test
     public void testNegativeDuration() {
-
-        long duration = -987654;
         SetCacheDurationStage stage = new SetCacheDurationStage();
         stage.setId("test");
 
         try {
-            stage.setCacheDuration(duration);
+            stage.setCacheDuration(Duration.ofMillis(-987654));
+            Assert.fail();
+        } catch (ConstraintViolationException e) {
+            // expected this
+        }
+    }
+
+    /** Tests that the stage properly rejects zero durations. */
+    @Test
+    public void testZeroDuration() {
+        final var stage = new SetCacheDurationStage();
+        stage.setId("test");
+
+        try {
+            stage.setCacheDuration(Duration.ZERO);
             Assert.fail();
         } catch (ConstraintViolationException e) {
             // expected this
         }
     }
+
+    /** Tests that the stage properly rejects null durations. */
+    @Test
+    public void testNullDuration() {
+        final var stage = new SetCacheDurationStage();
+        stage.setId("test");
+
+        try {
+            stage.setCacheDuration(null);
+            Assert.fail();
+        } catch (ConstraintViolationException e) {
+            // expected this
+        }
+    }
+
 }
\ No newline at end of file
diff --git a/aggregator-pipeline/src/test/java/net/shibboleth/metadata/dom/saml/SetValidUntilStageSpringTest.java b/aggregator-pipeline/src/test/java/net/shibboleth/metadata/dom/saml/SetValidUntilStageSpringTest.java
index 1d9a965..20a0f19 100644
--- a/aggregator-pipeline/src/test/java/net/shibboleth/metadata/dom/saml/SetValidUntilStageSpringTest.java
+++ b/aggregator-pipeline/src/test/java/net/shibboleth/metadata/dom/saml/SetValidUntilStageSpringTest.java
@@ -17,6 +17,8 @@
 
 package net.shibboleth.metadata.dom.saml;
 
+import java.time.Duration;
+
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.test.context.ContextConfiguration;
 import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
@@ -32,7 +34,8 @@ public class SetValidUntilStageSpringTest extends AbstractTestNGSpringContextTes
     @Test
     public void testDuration() throws Exception {
         // one day, 17 hours, 34 minutes and 19 seconds = P1DT17H34M19S
-        Assert.assertEquals(stage.getValidityDuration(), 1000L * (86400 + 17*3600 + 34*60 + 19));
+        final var expectedDuration = Duration.ofDays(1).plusHours(17).plusMinutes(34).plusSeconds(19);
+        Assert.assertEquals(stage.getValidityDuration(), expectedDuration);
     }
 
 }
diff --git a/aggregator-pipeline/src/test/java/net/shibboleth/metadata/dom/saml/SetValidUntilStageTest.java b/aggregator-pipeline/src/test/java/net/shibboleth/metadata/dom/saml/SetValidUntilStageTest.java
index 1345fdd..fb59ca0 100644
--- a/aggregator-pipeline/src/test/java/net/shibboleth/metadata/dom/saml/SetValidUntilStageTest.java
+++ b/aggregator-pipeline/src/test/java/net/shibboleth/metadata/dom/saml/SetValidUntilStageTest.java
@@ -17,6 +17,8 @@
 
 package net.shibboleth.metadata.dom.saml;
 
+import java.time.Duration;
+import java.time.Instant;
 import java.util.ArrayList;
 
 import net.shibboleth.metadata.Item;
@@ -57,8 +59,8 @@ public class SetValidUntilStageTest extends BaseDOMTest {
         final ArrayList<Item<Element>> metadataCollection = new ArrayList<>();
         metadataCollection.add(new DOMElementItem(entitiesDescriptor));
 
-        long duration = 123456;
-        long now = System.currentTimeMillis();
+        final var duration = Duration.ofMillis(123456);
+        final var now = Instant.now();
         SetValidUntilStage stage = new SetValidUntilStage();
         stage.setId("test");
         stage.setValidityDuration(duration);
@@ -69,9 +71,9 @@ public class SetValidUntilStageTest extends BaseDOMTest {
         Attr validUntilAttr = AttributeSupport.getAttribute(metadataCollection.iterator().next().unwrap(), SAMLMetadataSupport.VALID_UNTIL_ATTRIB_NAME);
         Assert.assertNotNull(validUntilAttr);
 
-        long validUntil = AttributeSupport.getDateTimeAttributeAsLong(validUntilAttr);
-        Assert.assertTrue(validUntil > now + duration - 100);
-        Assert.assertTrue(validUntil < now + duration + 100);
+        final var validUntil = AttributeSupport.getDateTimeAttribute(validUntilAttr);
+        Assert.assertTrue(validUntil.isAfter(now.plus(duration).minus(Duration.ofMillis(100))));
+        Assert.assertTrue(validUntil.isBefore(now.plus(duration).plus(Duration.ofMillis(100))));
     }
 
     /**
@@ -88,8 +90,8 @@ public class SetValidUntilStageTest extends BaseDOMTest {
         final ArrayList<Item<Element>> metadataCollection = new ArrayList<>();
         metadataCollection.add(new DOMElementItem(entitiesDescriptor));
 
-        long duration = 123456;
-        long now = System.currentTimeMillis();
+        final var duration = Duration.ofMillis(123456);
+        final var now = Instant.now();
         SetValidUntilStage stage = new SetValidUntilStage();
         stage.setId("test");
         stage.setValidityDuration(duration);
@@ -100,9 +102,9 @@ public class SetValidUntilStageTest extends BaseDOMTest {
         Attr validUntilAttr = AttributeSupport.getAttribute(metadataCollection.iterator().next().unwrap(), SAMLMetadataSupport.VALID_UNTIL_ATTRIB_NAME);
         Assert.assertNotNull(validUntilAttr);
 
-        long validUntil = AttributeSupport.getDateTimeAttributeAsLong(validUntilAttr);
-        Assert.assertTrue(validUntil > (now + duration - 100));
-        Assert.assertTrue(validUntil < (now + duration + 100));
+        final var validUntil = AttributeSupport.getDateTimeAttribute(validUntilAttr);
+        Assert.assertTrue(validUntil.isAfter(now.plus(duration).minus(Duration.ofMillis(100))));
+        Assert.assertTrue(validUntil.isBefore(now.plus(duration).plus(Duration.ofMillis(100))));
     }
 
     /**
@@ -122,7 +124,7 @@ public class SetValidUntilStageTest extends BaseDOMTest {
         final ArrayList<Item<Element>> metadataCollection = new ArrayList<>();
         metadataCollection.add(new DOMElementItem(root));
 
-        long duration = 123456;
+        final var duration = Duration.ofMillis(123456);
         SetValidUntilStage stage = new SetValidUntilStage();
         stage.setId("test");
         stage.setValidityDuration(duration);
@@ -138,7 +140,7 @@ public class SetValidUntilStageTest extends BaseDOMTest {
     @Test
     public void testNegativeDuration() {
 
-        long duration = -987654;
+        final var duration = Duration.ofMillis(-987654);
         SetValidUntilStage stage = new SetValidUntilStage();
         stage.setId("test");
 
@@ -149,4 +151,33 @@ public class SetValidUntilStageTest extends BaseDOMTest {
             // expected this
         }
     }
+
+    /** Tests that the stage properly rejects zero durations. */
+    @Test
+    public void testZeroDuration() {
+        final var stage = new SetValidUntilStage();
+        stage.setId("test");
+
+        try {
+            stage.setValidityDuration(Duration.ZERO);
+            Assert.fail();
+        } catch (ConstraintViolationException e) {
+            // expected this
+        }
+    }
+
+    /** Tests that the stage properly rejects null durations. */
+    @Test
+    public void testNullDuration() {
+        final var stage = new SetValidUntilStage();
+        stage.setId("test");
+
+        try {
+            stage.setValidityDuration(null);
+            Assert.fail();
+        } catch (ConstraintViolationException e) {
+            // expected this
+        }
+    }
+
 }
\ No newline at end of file
diff --git a/aggregator-pipeline/src/test/java/net/shibboleth/metadata/dom/saml/ValidateValidUntilStageTest.java b/aggregator-pipeline/src/test/java/net/shibboleth/metadata/dom/saml/ValidateValidUntilStageTest.java
index fdee08e..db55efe 100644
--- a/aggregator-pipeline/src/test/java/net/shibboleth/metadata/dom/saml/ValidateValidUntilStageTest.java
+++ b/aggregator-pipeline/src/test/java/net/shibboleth/metadata/dom/saml/ValidateValidUntilStageTest.java
@@ -22,6 +22,11 @@ import net.shibboleth.metadata.dom.BaseDOMTest;
 import net.shibboleth.metadata.dom.DOMElementItem;
 import net.shibboleth.utilities.java.support.xml.AttributeSupport;
 
+import java.time.Duration;
+import java.time.Instant;
+
+import javax.annotation.Nonnull;
+
 import org.testng.Assert;
 import org.testng.annotations.Test;
 import org.w3c.dom.Element;
@@ -42,7 +47,7 @@ public class ValidateValidUntilStageTest extends BaseDOMTest {
         stage.setRequireValidUntil(false);
         stage.initialize();
 
-        DOMElementItem item = buildDomElementItem(0);
+        DOMElementItem item = buildDomElementItem(Duration.ZERO);
         stage.doExecute(item);
         Assert.assertFalse(item.getItemMetadata().containsKey(ErrorStatus.class));
 
@@ -51,7 +56,7 @@ public class ValidateValidUntilStageTest extends BaseDOMTest {
         stage.setRequireValidUntil(true);
         stage.initialize();
         
-        item = buildDomElementItem(0);
+        item = buildDomElementItem(Duration.ZERO);
         stage.doExecute(item);
         Assert.assertTrue(item.getItemMetadata().containsKey(ErrorStatus.class));
     }
@@ -64,15 +69,15 @@ public class ValidateValidUntilStageTest extends BaseDOMTest {
         stage.setRequireValidUntil(false);
         stage.initialize();
 
-        DOMElementItem item = buildDomElementItem(10000);
+        DOMElementItem item = buildDomElementItem(Duration.ofSeconds(10));
         stage.doExecute(item);
         Assert.assertFalse(item.getItemMetadata().containsKey(ErrorStatus.class));
 
-        item = buildDomElementItem(-10000);
+        item = buildDomElementItem(Duration.ofSeconds(-10));
         stage.doExecute(item);
         Assert.assertTrue(item.getItemMetadata().containsKey(ErrorStatus.class));
 
-        item = buildDomElementItem(1000 * 60 * 60 * 24 * 8);
+        item = buildDomElementItem(Duration.ofDays(8));
         stage.doExecute(item);
         Assert.assertTrue(item.getItemMetadata().containsKey(ErrorStatus.class));
     }
@@ -85,14 +90,14 @@ public class ValidateValidUntilStageTest extends BaseDOMTest {
      * 
      * @return the created Item
      */
-    private DOMElementItem buildDomElementItem(long validUntilInterval) throws Exception {
+    private DOMElementItem buildDomElementItem(@Nonnull final Duration validUntilInterval) throws Exception {
         Element descriptor = readXMLData("in.xml");
-        if (validUntilInterval != 0) {
+        if (!validUntilInterval.isZero()) {
             AttributeSupport.appendDateTimeAttribute(descriptor, SAMLMetadataSupport.VALID_UNTIL_ATTRIB_NAME,
-                    System.currentTimeMillis() + validUntilInterval);
+                    Instant.now().plus(validUntilInterval));
         }else{
             AttributeSupport.removeAttribute(descriptor, SAMLMetadataSupport.VALID_UNTIL_ATTRIB_NAME);
         }
         return new DOMElementItem(descriptor.getOwnerDocument());
     }
-}
\ No newline at end of file
+}
diff --git a/aggregator-pipeline/src/test/resources/net/shibboleth/metadata/dom/saml/SetCacheDurationStageSpringTest-config.xml b/aggregator-pipeline/src/test/resources/net/shibboleth/metadata/dom/saml/SetCacheDurationStageSpringTest-config.xml
index 97c0c4d..3e8f4f7 100644
--- a/aggregator-pipeline/src/test/resources/net/shibboleth/metadata/dom/saml/SetCacheDurationStageSpringTest-config.xml
+++ b/aggregator-pipeline/src/test/resources/net/shibboleth/metadata/dom/saml/SetCacheDurationStageSpringTest-config.xml
@@ -16,10 +16,10 @@
     <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
         <property name="converters">
             <set>
-                <bean class="net.shibboleth.ext.spring.config.DurationToLongConverter" />
-                <bean class="net.shibboleth.ext.spring.config.StringToIPRangeConverter" />
                 <bean class="net.shibboleth.ext.spring.config.BooleanToPredicateConverter" />
                 <bean class="net.shibboleth.ext.spring.config.StringBooleanToPredicateConverter" />
+                <bean class="net.shibboleth.ext.spring.config.StringToDurationConverter" />
+                <bean class="net.shibboleth.ext.spring.config.StringToIPRangeConverter" />
                 <bean class="net.shibboleth.ext.spring.config.StringToResourceConverter" />
             </set>
         </property>
diff --git a/aggregator-pipeline/src/test/resources/net/shibboleth/metadata/dom/saml/SetValidUntilStageSpringTest-config.xml b/aggregator-pipeline/src/test/resources/net/shibboleth/metadata/dom/saml/SetValidUntilStageSpringTest-config.xml
index d2b1f32..72f41e8 100644
--- a/aggregator-pipeline/src/test/resources/net/shibboleth/metadata/dom/saml/SetValidUntilStageSpringTest-config.xml
+++ b/aggregator-pipeline/src/test/resources/net/shibboleth/metadata/dom/saml/SetValidUntilStageSpringTest-config.xml
@@ -16,10 +16,10 @@
     <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
         <property name="converters">
             <set>
-                <bean class="net.shibboleth.ext.spring.config.DurationToLongConverter" />
-                <bean class="net.shibboleth.ext.spring.config.StringToIPRangeConverter" />
                 <bean class="net.shibboleth.ext.spring.config.BooleanToPredicateConverter" />
                 <bean class="net.shibboleth.ext.spring.config.StringBooleanToPredicateConverter" />
+                <bean class="net.shibboleth.ext.spring.config.StringToDurationConverter" />
+                <bean class="net.shibboleth.ext.spring.config.StringToIPRangeConverter" />
                 <bean class="net.shibboleth.ext.spring.config.StringToResourceConverter" />
             </set>
         </property>

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the commits mailing list