Jelajahi Sumber

TimeDuration refactoring

jrivard@gmail.com 6 tahun lalu
induk
melakukan
90e156bdbc
82 mengubah file dengan 475 tambahan dan 674 penghapusan
  1. 1 2
      data-service/src/main/java/password/pwm/receiver/Settings.java
  2. 1 2
      data-service/src/main/java/password/pwm/receiver/TelemetryViewerServlet.java
  3. 0 65
      rest-test-server/pom.xml
  4. 2 3
      server/src/main/java/password/pwm/PwmEnvironment.java
  5. 2 2
      server/src/main/java/password/pwm/config/function/UserMatchViewerFunction.java
  6. 1 2
      server/src/main/java/password/pwm/config/profile/LdapProfile.java
  7. 4 5
      server/src/main/java/password/pwm/config/profile/NewUserProfile.java
  8. 4 5
      server/src/main/java/password/pwm/config/profile/UpdateProfileProfile.java
  9. 1 2
      server/src/main/java/password/pwm/config/stored/StoredConfigurationImpl.java
  10. 2 2
      server/src/main/java/password/pwm/health/CertificateChecker.java
  11. 5 6
      server/src/main/java/password/pwm/health/HealthMonitor.java
  12. 15 32
      server/src/main/java/password/pwm/health/HealthMonitorSettings.java
  13. 1 2
      server/src/main/java/password/pwm/health/LDAPStatusChecker.java
  14. 6 6
      server/src/main/java/password/pwm/http/ContextManager.java
  15. 13 14
      server/src/main/java/password/pwm/http/IdleTimeoutCalculator.java
  16. 3 2
      server/src/main/java/password/pwm/http/PwmSessionWrapper.java
  17. 3 0
      server/src/main/java/password/pwm/http/bean/SetupResponsesBean.java
  18. 1 1
      server/src/main/java/password/pwm/http/filter/ConfigAccessFilter.java
  19. 2 1
      server/src/main/java/password/pwm/http/filter/RequestInitializationFilter.java
  20. 1 1
      server/src/main/java/password/pwm/http/filter/SessionFilter.java
  21. 1 1
      server/src/main/java/password/pwm/http/servlet/ClientApiServlet.java
  22. 2 3
      server/src/main/java/password/pwm/http/servlet/admin/AdminServlet.java
  23. 1 1
      server/src/main/java/password/pwm/http/servlet/admin/ReportStatusBean.java
  24. 2 2
      server/src/main/java/password/pwm/http/servlet/changepw/ChangePasswordServlet.java
  25. 1 2
      server/src/main/java/password/pwm/http/servlet/configmanager/DebugItemGenerator.java
  26. 7 5
      server/src/main/java/password/pwm/http/servlet/helpdesk/HelpdeskServlet.java
  27. 6 71
      server/src/main/java/password/pwm/http/servlet/helpdesk/HelpdeskVerificationRequestBean.java
  28. 3 16
      server/src/main/java/password/pwm/http/servlet/helpdesk/HelpdeskVerificationResponseBean.java
  29. 16 14
      server/src/main/java/password/pwm/http/servlet/helpdesk/HelpdeskVerificationStateBean.java
  30. 1 1
      server/src/main/java/password/pwm/http/servlet/newuser/NewUserServlet.java
  31. 1 2
      server/src/main/java/password/pwm/http/state/CryptoCookieBeanImpl.java
  32. 1 2
      server/src/main/java/password/pwm/http/state/CryptoCookieLoginImpl.java
  33. 1 2
      server/src/main/java/password/pwm/ldap/LdapOperationsHelper.java
  34. 12 12
      server/src/main/java/password/pwm/ldap/PasswordChangeProgressChecker.java
  35. 2 2
      server/src/main/java/password/pwm/ldap/UserInfoReader.java
  36. 5 6
      server/src/main/java/password/pwm/ldap/auth/LDAPAuthenticationRequest.java
  37. 2 2
      server/src/main/java/password/pwm/ldap/search/UserSearchEngine.java
  38. 1 1
      server/src/main/java/password/pwm/svc/cache/CachePolicy.java
  39. 2 2
      server/src/main/java/password/pwm/svc/cache/CacheService.java
  40. 2 2
      server/src/main/java/password/pwm/svc/cluster/ClusterMachine.java
  41. 6 8
      server/src/main/java/password/pwm/svc/cluster/ClusterSettings.java
  42. 5 3
      server/src/main/java/password/pwm/svc/email/EmailService.java
  43. 1 1
      server/src/main/java/password/pwm/svc/event/AuditService.java
  44. 1 1
      server/src/main/java/password/pwm/svc/event/LocalDbAuditVault.java
  45. 2 2
      server/src/main/java/password/pwm/svc/event/SyslogAuditService.java
  46. 13 13
      server/src/main/java/password/pwm/svc/intruder/IntruderManager.java
  47. 6 7
      server/src/main/java/password/pwm/svc/pwnotify/PwNotifyEngine.java
  48. 3 3
      server/src/main/java/password/pwm/svc/pwnotify/PwNotifyService.java
  49. 3 4
      server/src/main/java/password/pwm/svc/pwnotify/PwNotifySettings.java
  50. 5 5
      server/src/main/java/password/pwm/svc/report/ReportService.java
  51. 2 2
      server/src/main/java/password/pwm/svc/report/ReportSettings.java
  52. 2 2
      server/src/main/java/password/pwm/svc/report/ReportSummaryData.java
  53. 2 2
      server/src/main/java/password/pwm/svc/stats/EventRateMeter.java
  54. 4 4
      server/src/main/java/password/pwm/svc/stats/StatisticsManager.java
  55. 2 2
      server/src/main/java/password/pwm/svc/telemetry/TelemetryService.java
  56. 2 2
      server/src/main/java/password/pwm/svc/token/TokenService.java
  57. 1 2
      server/src/main/java/password/pwm/svc/token/TokenUtil.java
  58. 1 1
      server/src/main/java/password/pwm/svc/wordlist/AbstractWordlist.java
  59. 7 9
      server/src/main/java/password/pwm/svc/wordlist/Populator.java
  60. 7 7
      server/src/main/java/password/pwm/svc/wordlist/SharedHistoryManager.java
  61. 4 4
      server/src/main/java/password/pwm/util/ProgressInfo.java
  62. 8 10
      server/src/main/java/password/pwm/util/TransactionSizeCalculator.java
  63. 6 7
      server/src/main/java/password/pwm/util/java/ConditionalTaskExecutor.java
  64. 1 1
      server/src/main/java/password/pwm/util/java/JavaHelper.java
  65. 119 208
      server/src/main/java/password/pwm/util/java/TimeDuration.java
  66. 1 1
      server/src/main/java/password/pwm/util/localdb/LocalDBFactory.java
  67. 2 2
      server/src/main/java/password/pwm/util/localdb/LocalDBStoredQueue.java
  68. 1 2
      server/src/main/java/password/pwm/util/localdb/LocalDBUtility.java
  69. 13 14
      server/src/main/java/password/pwm/util/localdb/WorkQueueProcessor.java
  70. 3 5
      server/src/main/java/password/pwm/util/localdb/XodusLocalDB.java
  71. 1 1
      server/src/main/java/password/pwm/util/logging/LocalDBLogger.java
  72. 7 5
      server/src/main/java/password/pwm/util/logging/LocalDBLoggerSettings.java
  73. 1 1
      server/src/main/java/password/pwm/util/logging/LocalDBSearchResults.java
  74. 1 1
      server/src/main/java/password/pwm/util/macro/StandardMacros.java
  75. 2 2
      server/src/main/java/password/pwm/util/operations/OtpService.java
  76. 3 4
      server/src/main/java/password/pwm/util/operations/PasswordUtility.java
  77. 14 14
      server/src/main/java/password/pwm/util/operations/cr/NMASCrOperator.java
  78. 5 3
      server/src/main/java/password/pwm/util/queue/SmsQueueManager.java
  79. 1 1
      server/src/main/java/password/pwm/util/secure/SecureEngine.java
  80. 1 2
      server/src/main/java/password/pwm/ws/server/rest/RestFormSigningServer.java
  81. 67 0
      server/src/test/java/password/pwm/util/java/TimeDurationTest.java
  82. 2 2
      webapp/src/main/webapp/public/reference/timezones.jsp

+ 1 - 2
data-service/src/main/java/password/pwm/receiver/Settings.java

@@ -35,7 +35,6 @@ import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Map;
 import java.util.Properties;
 import java.util.Properties;
-import java.util.concurrent.TimeUnit;
 
 
 public class Settings
 public class Settings
 {
 {
@@ -47,7 +46,7 @@ public class Settings
         ftpPassword( null ),
         ftpPassword( null ),
         ftpReadPath( null ),
         ftpReadPath( null ),
         storagePath( null ),
         storagePath( null ),
-        maxInstanceSeconds( Long.toString( new TimeDuration( 14, TimeUnit.DAYS ).getTotalSeconds() ) ),;
+        maxInstanceSeconds( Long.toString( TimeDuration.of( 14, TimeDuration.Unit.DAYS ).as( TimeDuration.Unit.SECONDS ) ) ),;
 
 
         private final String defaultValue;
         private final String defaultValue;
 
 

+ 1 - 2
data-service/src/main/java/password/pwm/receiver/TelemetryViewerServlet.java

@@ -31,7 +31,6 @@ import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
 import java.io.IOException;
-import java.util.concurrent.TimeUnit;
 
 
 @WebServlet(
 @WebServlet(
         name = "TelemetryViewer",
         name = "TelemetryViewer",
@@ -65,7 +64,7 @@ public class TelemetryViewerServlet extends HttpServlet
         }
         }
 
 
         final Storage storage = app.getStorage();
         final Storage storage = app.getStorage();
-        final SummaryBean summaryBean = SummaryBean.fromStorage( storage, new TimeDuration( days, TimeUnit.DAYS ) );
+        final SummaryBean summaryBean = SummaryBean.fromStorage( storage, TimeDuration.of( days, TimeDuration.Unit.DAYS ) );
         req.setAttribute( SUMMARY_ATTR, summaryBean );
         req.setAttribute( SUMMARY_ATTR, summaryBean );
         req.getServletContext().getRequestDispatcher( "/WEB-INF/jsp/telemetry-viewer.jsp" ).forward( req, resp );
         req.getServletContext().getRequestDispatcher( "/WEB-INF/jsp/telemetry-viewer.jsp" ).forward( req, resp );
     }
     }

+ 0 - 65
rest-test-server/pom.xml

@@ -1,65 +0,0 @@
-<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-
-    <modelVersion>4.0.0</modelVersion>
-
-    <groupId>org.pwm-project</groupId>
-    <artifactId>pwm-parent</artifactId>
-    <version>1.8.0-SNAPSHOT</version>
-    <packaging>pom</packaging>
-
-    <name>PWM Password Self Service</name>
-
-    <licenses>
-        <license>
-            <name>The GNU General Public License (GPL) Version 2</name>
-            <url>http://www.gnu.org/licenses/gpl-2.0.html</url>
-            <distribution>repo</distribution>
-        </license>
-    </licenses>
-
-    <organization>
-        <name>PWM Project</name>
-        <url>http://www.pwm-project.org</url>
-    </organization>
-
-    <properties>
-        <warArtifactID>pwm-${project.version}.war</warArtifactID>
-        <build.number>0</build.number>  <!-- default in case not set on command line -->
-        <build.revision>0</build.revision>  <!-- default in case not set on command line -->
-        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-        <pwm.minimum.maven.version>3.2</pwm.minimum.maven.version>
-        <timestamp.iso>${maven.build.timestamp}</timestamp.iso>
-    </properties>
-
-    <modules>
-        <module>client</module>
-        <module>server</module>
-        <module>onejar</module>
-        <module>docker</module>
-    </modules>
-
-    <build>
-        <plugins>
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-enforcer-plugin</artifactId>
-                <version>3.0.0-M1</version>
-                <executions>
-                    <execution>
-                        <id>enforce-maven</id>
-                        <goals>
-                            <goal>enforce</goal>
-                        </goals>
-                        <configuration>
-                            <rules>
-                                <requireMavenVersion>
-                                    <version>${pwm.minimum.maven.version}</version>
-                                </requireMavenVersion>
-                            </rules>
-                        </configuration>
-                    </execution>
-                </executions>
-            </plugin>
-        </plugins>
-    </build>
-</project>

+ 2 - 3
server/src/main/java/password/pwm/PwmEnvironment.java

@@ -49,7 +49,6 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.List;
 import java.util.Map;
 import java.util.Map;
 import java.util.Properties;
 import java.util.Properties;
-import java.util.concurrent.TimeUnit;
 
 
 public class PwmEnvironment
 public class PwmEnvironment
 {
 {
@@ -565,9 +564,9 @@ public class PwmEnvironment
                 ? 1
                 ? 1
                 : Integer.parseInt( getConfig().readAppProperty( AppProperty.APPLICATION_FILELOCK_WAIT_SECONDS ) );
                 : Integer.parseInt( getConfig().readAppProperty( AppProperty.APPLICATION_FILELOCK_WAIT_SECONDS ) );
         final Instant startTime = Instant.now();
         final Instant startTime = Instant.now();
-        final TimeDuration attemptInterval = new TimeDuration( 5021, TimeUnit.MILLISECONDS );
+        final TimeDuration attemptInterval = TimeDuration.of( 5021, TimeDuration.Unit.MILLISECONDS );
 
 
-        while ( !this.isFileLocked() && TimeDuration.fromCurrent( startTime ).isShorterThan( maxWaitSeconds, TimeUnit.SECONDS ) )
+        while ( !this.isFileLocked() && TimeDuration.fromCurrent( startTime ).isShorterThan( maxWaitSeconds, TimeDuration.Unit.SECONDS ) )
         {
         {
             attemptFileLock();
             attemptFileLock();
 
 

+ 2 - 2
server/src/main/java/password/pwm/config/function/UserMatchViewerFunction.java

@@ -47,8 +47,8 @@ import password.pwm.util.java.TimeDuration;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.logging.PwmLogger;
 
 
 import java.io.Serializable;
 import java.io.Serializable;
+import java.time.Instant;
 import java.util.Collection;
 import java.util.Collection;
-import java.util.Date;
 import java.util.LinkedHashSet;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.List;
 import java.util.Set;
 import java.util.Set;
@@ -68,7 +68,7 @@ public class UserMatchViewerFunction implements SettingUIFunction
     {
     {
         final PwmApplication pwmApplication = pwmRequest.getPwmApplication();
         final PwmApplication pwmApplication = pwmRequest.getPwmApplication();
 
 
-        final Date startSearchTime = new Date();
+        final Instant startSearchTime = Instant.now();
         final int maxResultSize = Integer.parseInt( pwmApplication.getConfig().readAppProperty( AppProperty.CONFIG_EDITOR_QUERY_FILTER_TEST_LIMIT ) );
         final int maxResultSize = Integer.parseInt( pwmApplication.getConfig().readAppProperty( AppProperty.CONFIG_EDITOR_QUERY_FILTER_TEST_LIMIT ) );
         final Collection<UserIdentity> users = discoverMatchingUsers( pwmApplication, maxResultSize, storedConfiguration, setting, profile );
         final Collection<UserIdentity> users = discoverMatchingUsers( pwmApplication, maxResultSize, storedConfiguration, setting, profile );
         final TimeDuration searchDuration = TimeDuration.fromCurrent( startSearchTime );
         final TimeDuration searchDuration = TimeDuration.fromCurrent( startSearchTime );

+ 1 - 2
server/src/main/java/password/pwm/config/profile/LdapProfile.java

@@ -47,7 +47,6 @@ import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.List;
 import java.util.Locale;
 import java.util.Locale;
 import java.util.Map;
 import java.util.Map;
-import java.util.concurrent.TimeUnit;
 
 
 public class LdapProfile extends AbstractProfile implements Profile
 public class LdapProfile extends AbstractProfile implements Profile
 {
 {
@@ -166,7 +165,7 @@ public class LdapProfile extends AbstractProfile implements Profile
                 if ( enableCanonicalCache )
                 if ( enableCanonicalCache )
                 {
                 {
                     final long cacheSeconds = Long.parseLong( pwmApplication.getConfig().readAppProperty( AppProperty.LDAP_CACHE_CANONICAL_SECONDS ) );
                     final long cacheSeconds = Long.parseLong( pwmApplication.getConfig().readAppProperty( AppProperty.LDAP_CACHE_CANONICAL_SECONDS ) );
-                    final CachePolicy cachePolicy = CachePolicy.makePolicyWithExpiration( new TimeDuration( cacheSeconds, TimeUnit.SECONDS ) );
+                    final CachePolicy cachePolicy = CachePolicy.makePolicyWithExpiration( TimeDuration.of( cacheSeconds, TimeDuration.Unit.SECONDS ) );
                     pwmApplication.getCacheService().put( cacheKey, cachePolicy, canonicalValue );
                     pwmApplication.getCacheService().put( cacheKey, cachePolicy, canonicalValue );
                 }
                 }
 
 

+ 4 - 5
server/src/main/java/password/pwm/config/profile/NewUserProfile.java

@@ -43,7 +43,6 @@ import java.time.Instant;
 import java.util.HashMap;
 import java.util.HashMap;
 import java.util.Locale;
 import java.util.Locale;
 import java.util.Map;
 import java.util.Map;
-import java.util.concurrent.TimeUnit;
 
 
 public class NewUserProfile extends AbstractProfile
 public class NewUserProfile extends AbstractProfile
 {
 {
@@ -160,9 +159,9 @@ public class NewUserProfile extends AbstractProfile
         if ( newUserDuration < 1 )
         if ( newUserDuration < 1 )
         {
         {
             final long defaultDuration = configuration.readSettingAsLong( PwmSetting.TOKEN_LIFETIME );
             final long defaultDuration = configuration.readSettingAsLong( PwmSetting.TOKEN_LIFETIME );
-            return new TimeDuration( defaultDuration, TimeUnit.SECONDS );
+            return TimeDuration.of( defaultDuration, TimeDuration.Unit.SECONDS );
         }
         }
-        return new TimeDuration( newUserDuration, TimeUnit.SECONDS );
+        return TimeDuration.of( newUserDuration, TimeDuration.Unit.SECONDS );
     }
     }
 
 
     public TimeDuration getTokenDurationSMS( final Configuration configuration )
     public TimeDuration getTokenDurationSMS( final Configuration configuration )
@@ -171,8 +170,8 @@ public class NewUserProfile extends AbstractProfile
         if ( newUserDuration < 1 )
         if ( newUserDuration < 1 )
         {
         {
             final long defaultDuration = configuration.readSettingAsLong( PwmSetting.TOKEN_LIFETIME );
             final long defaultDuration = configuration.readSettingAsLong( PwmSetting.TOKEN_LIFETIME );
-            return new TimeDuration( defaultDuration, TimeUnit.SECONDS );
+            return TimeDuration.of( defaultDuration, TimeDuration.Unit.SECONDS );
         }
         }
-        return new TimeDuration( newUserDuration, TimeUnit.SECONDS );
+        return TimeDuration.of( newUserDuration, TimeDuration.Unit.SECONDS );
     }
     }
 }
 }

+ 4 - 5
server/src/main/java/password/pwm/config/profile/UpdateProfileProfile.java

@@ -30,7 +30,6 @@ import password.pwm.util.java.TimeDuration;
 
 
 import java.util.Locale;
 import java.util.Locale;
 import java.util.Map;
 import java.util.Map;
-import java.util.concurrent.TimeUnit;
 
 
 public class UpdateProfileProfile extends AbstractProfile implements Profile
 public class UpdateProfileProfile extends AbstractProfile implements Profile
 {
 {
@@ -67,9 +66,9 @@ public class UpdateProfileProfile extends AbstractProfile implements Profile
         if ( duration < 1 )
         if ( duration < 1 )
         {
         {
             final long defaultDuration = configuration.readSettingAsLong( PwmSetting.TOKEN_LIFETIME );
             final long defaultDuration = configuration.readSettingAsLong( PwmSetting.TOKEN_LIFETIME );
-            return new TimeDuration( defaultDuration, TimeUnit.SECONDS );
+            return TimeDuration.of( defaultDuration, TimeDuration.Unit.SECONDS );
         }
         }
-        return new TimeDuration( duration, TimeUnit.SECONDS );
+        return TimeDuration.of( duration, TimeDuration.Unit.SECONDS );
     }
     }
 
 
     public TimeDuration getTokenDurationSMS( final Configuration configuration )
     public TimeDuration getTokenDurationSMS( final Configuration configuration )
@@ -78,8 +77,8 @@ public class UpdateProfileProfile extends AbstractProfile implements Profile
         if ( duration < 1 )
         if ( duration < 1 )
         {
         {
             final long defaultDuration = configuration.readSettingAsLong( PwmSetting.TOKEN_LIFETIME );
             final long defaultDuration = configuration.readSettingAsLong( PwmSetting.TOKEN_LIFETIME );
-            return new TimeDuration( defaultDuration, TimeUnit.SECONDS );
+            return TimeDuration.of( defaultDuration, TimeDuration.Unit.SECONDS );
         }
         }
-        return new TimeDuration( duration, TimeUnit.SECONDS );
+        return TimeDuration.of( duration, TimeDuration.Unit.SECONDS );
     }
     }
 }
 }

+ 1 - 2
server/src/main/java/password/pwm/config/stored/StoredConfigurationImpl.java

@@ -75,7 +75,6 @@ import java.time.Instant;
 import java.util.ArrayList;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Collections;
-import java.util.Date;
 import java.util.HashMap;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Iterator;
@@ -1003,7 +1002,7 @@ public class StoredConfigurationImpl implements StoredConfiguration
     public String settingChecksum( )
     public String settingChecksum( )
             throws PwmUnrecoverableException
             throws PwmUnrecoverableException
     {
     {
-        final Date startTime = new Date();
+        final Instant startTime = Instant.now();
 
 
         final List<SettingValueRecord> modifiedSettings = modifiedSettings();
         final List<SettingValueRecord> modifiedSettings = modifiedSettings();
         final StringBuilder sb = new StringBuilder();
         final StringBuilder sb = new StringBuilder();

+ 2 - 2
server/src/main/java/password/pwm/health/CertificateChecker.java

@@ -44,9 +44,9 @@ import password.pwm.util.logging.PwmLogger;
 
 
 import java.security.cert.CertificateException;
 import java.security.cert.CertificateException;
 import java.security.cert.X509Certificate;
 import java.security.cert.X509Certificate;
+import java.time.Instant;
 import java.util.ArrayList;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Collections;
-import java.util.Date;
 import java.util.List;
 import java.util.List;
 
 
 public class CertificateChecker implements HealthChecker
 public class CertificateChecker implements HealthChecker
@@ -181,7 +181,7 @@ public class CertificateChecker implements HealthChecker
             throw new PwmOperationalException( errorInformation );
             throw new PwmOperationalException( errorInformation );
         }
         }
 
 
-        final Date expireDate = certificate.getNotAfter();
+        final Instant expireDate = certificate.getNotAfter().toInstant();
         final TimeDuration durationUntilExpire = TimeDuration.fromCurrent( expireDate );
         final TimeDuration durationUntilExpire = TimeDuration.fromCurrent( expireDate );
         if ( durationUntilExpire.isShorterThan( warnDurationMs ) )
         if ( durationUntilExpire.isShorterThan( warnDurationMs ) )
         {
         {

+ 5 - 6
server/src/main/java/password/pwm/health/HealthMonitor.java

@@ -35,7 +35,6 @@ import java.time.Instant;
 import java.util.ArrayList;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Collections;
-import java.util.Date;
 import java.util.HashMap;
 import java.util.HashMap;
 import java.util.List;
 import java.util.List;
 import java.util.Map;
 import java.util.Map;
@@ -160,7 +159,7 @@ public class HealthMonitor implements PwmService
                 ) );
                 ) );
 
 
 
 
-        executorService.scheduleAtFixedRate( new ScheduledUpdater(), 0, settings.getNominalCheckInterval().getTotalMilliseconds(), TimeUnit.MILLISECONDS );
+        executorService.scheduleAtFixedRate( new ScheduledUpdater(), 0, settings.getNominalCheckInterval().asMillis(), TimeUnit.MILLISECONDS );
 
 
         status = STATUS.OPEN;
         status = STATUS.OPEN;
     }
     }
@@ -179,7 +178,7 @@ public class HealthMonitor implements PwmService
             if ( timeliness == CheckTimeliness.Immediate || ( timeliness == CheckTimeliness.CurrentButNotAncient && recordsAreStale ) )
             if ( timeliness == CheckTimeliness.Immediate || ( timeliness == CheckTimeliness.CurrentButNotAncient && recordsAreStale ) )
             {
             {
                 final ScheduledFuture updateTask = executorService.schedule( new ImmediateUpdater(), 0, TimeUnit.NANOSECONDS );
                 final ScheduledFuture updateTask = executorService.schedule( new ImmediateUpdater(), 0, TimeUnit.NANOSECONDS );
-                final Date beginWaitTime = new Date();
+                final Instant beginWaitTime = Instant.now();
                 while ( !updateTask.isDone() && TimeDuration.fromCurrent( beginWaitTime ).isShorterThan( settings.getMaximumForceCheckWait() ) )
                 while ( !updateTask.isDone() && TimeDuration.fromCurrent( beginWaitTime ).isShorterThan( settings.getMaximumForceCheckWait() ) )
                 {
                 {
                     JavaHelper.pause( 500 );
                     JavaHelper.pause( 500 );
@@ -219,7 +218,7 @@ public class HealthMonitor implements PwmService
         }
         }
 
 
         final TimeDuration timeSinceLastUpdate = TimeDuration.fromCurrent( lastHealthCheckTime );
         final TimeDuration timeSinceLastUpdate = TimeDuration.fromCurrent( lastHealthCheckTime );
-        if ( timeSinceLastUpdate.isShorterThan( settings.getMinimumCheckInterval().getTotalMilliseconds(), TimeUnit.MILLISECONDS ) )
+        if ( timeSinceLastUpdate.isShorterThan( settings.getMinimumCheckInterval().asMillis(), TimeDuration.Unit.MILLISECONDS ) )
         {
         {
             return;
             return;
         }
         }
@@ -285,7 +284,7 @@ public class HealthMonitor implements PwmService
         public void run( )
         public void run( )
         {
         {
             final TimeDuration timeSinceLastRequest = TimeDuration.fromCurrent( lastRequestedUpdateTime );
             final TimeDuration timeSinceLastRequest = TimeDuration.fromCurrent( lastRequestedUpdateTime );
-            if ( timeSinceLastRequest.isShorterThan( settings.getNominalCheckInterval().getTotalMilliseconds() + 1000, TimeUnit.MILLISECONDS ) )
+            if ( timeSinceLastRequest.isShorterThan( settings.getNominalCheckInterval().asMillis() + 1000, TimeDuration.Unit.MILLISECONDS ) )
             {
             {
                 try
                 try
                 {
                 {
@@ -306,7 +305,7 @@ public class HealthMonitor implements PwmService
         public void run( )
         public void run( )
         {
         {
             final TimeDuration timeSinceLastUpdate = TimeDuration.fromCurrent( lastHealthCheckTime );
             final TimeDuration timeSinceLastUpdate = TimeDuration.fromCurrent( lastHealthCheckTime );
-            if ( timeSinceLastUpdate.isLongerThan( settings.getMinimumCheckInterval().getTotalMilliseconds(), TimeUnit.MILLISECONDS ) )
+            if ( timeSinceLastUpdate.isLongerThan( settings.getMinimumCheckInterval().asMillis(), TimeDuration.Unit.MILLISECONDS ) )
             {
             {
                 try
                 try
                 {
                 {

+ 15 - 32
server/src/main/java/password/pwm/health/HealthMonitorSettings.java

@@ -22,47 +22,30 @@
 
 
 package password.pwm.health;
 package password.pwm.health;
 
 
+import lombok.Builder;
+import lombok.Value;
 import password.pwm.AppProperty;
 import password.pwm.AppProperty;
 import password.pwm.config.Configuration;
 import password.pwm.config.Configuration;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.java.TimeDuration;
 
 
 import java.io.Serializable;
 import java.io.Serializable;
-import java.util.concurrent.TimeUnit;
 
 
+@Value
+@Builder
 class HealthMonitorSettings implements Serializable
 class HealthMonitorSettings implements Serializable
 {
 {
-    private TimeDuration nominalCheckInterval = new TimeDuration( 1, TimeUnit.MINUTES );
-    private TimeDuration minimumCheckInterval = new TimeDuration( 30, TimeUnit.SECONDS );
-    private TimeDuration maximumRecordAge = new TimeDuration( 5, TimeUnit.MINUTES );
-    private TimeDuration maximumForceCheckWait = new TimeDuration( 30, TimeUnit.SECONDS );
+    private TimeDuration nominalCheckInterval;
+    private TimeDuration minimumCheckInterval;
+    private TimeDuration maximumRecordAge;
+    private TimeDuration maximumForceCheckWait;
 
 
-    public TimeDuration getMaximumRecordAge( )
+    static HealthMonitorSettings fromConfiguration( final Configuration config )
     {
     {
-        return maximumRecordAge;
-    }
-
-    public TimeDuration getMinimumCheckInterval( )
-    {
-        return minimumCheckInterval;
-    }
-
-    public TimeDuration getNominalCheckInterval( )
-    {
-        return nominalCheckInterval;
-    }
-
-    public TimeDuration getMaximumForceCheckWait( )
-    {
-        return maximumForceCheckWait;
-    }
-
-    public static HealthMonitorSettings fromConfiguration( final Configuration config )
-    {
-        final HealthMonitorSettings settings = new HealthMonitorSettings();
-        settings.nominalCheckInterval = new TimeDuration( Long.parseLong( config.readAppProperty( AppProperty.HEALTHCHECK_NOMINAL_CHECK_INTERVAL ) ), TimeUnit.SECONDS );
-        settings.minimumCheckInterval = new TimeDuration( Long.parseLong( config.readAppProperty( AppProperty.HEALTHCHECK_MIN_CHECK_INTERVAL ) ), TimeUnit.SECONDS );
-        settings.maximumRecordAge = new TimeDuration( Long.parseLong( config.readAppProperty( AppProperty.HEALTHCHECK_MAX_RECORD_AGE ) ), TimeUnit.SECONDS );
-        settings.maximumForceCheckWait = new TimeDuration( Long.parseLong( config.readAppProperty( AppProperty.HEALTHCHECK_MAX_FORCE_WAIT ) ), TimeUnit.SECONDS );
-        return settings;
+        return HealthMonitorSettings.builder()
+                .nominalCheckInterval( TimeDuration.of( Long.parseLong( config.readAppProperty( AppProperty.HEALTHCHECK_NOMINAL_CHECK_INTERVAL ) ), TimeDuration.Unit.SECONDS ) )
+                .minimumCheckInterval( TimeDuration.of( Long.parseLong( config.readAppProperty( AppProperty.HEALTHCHECK_MIN_CHECK_INTERVAL ) ), TimeDuration.Unit.SECONDS ) )
+                .maximumRecordAge( TimeDuration.of( Long.parseLong( config.readAppProperty( AppProperty.HEALTHCHECK_MAX_RECORD_AGE ) ), TimeDuration.Unit.SECONDS ) )
+                .maximumForceCheckWait( TimeDuration.of( Long.parseLong( config.readAppProperty( AppProperty.HEALTHCHECK_MAX_FORCE_WAIT ) ), TimeDuration.Unit.SECONDS ) )
+                .build();
     }
     }
 }
 }

+ 1 - 2
server/src/main/java/password/pwm/health/LDAPStatusChecker.java

@@ -79,7 +79,6 @@ import java.util.List;
 import java.util.Locale;
 import java.util.Locale;
 import java.util.Map;
 import java.util.Map;
 import java.util.Set;
 import java.util.Set;
-import java.util.concurrent.TimeUnit;
 
 
 public class LDAPStatusChecker implements HealthChecker
 public class LDAPStatusChecker implements HealthChecker
 {
 {
@@ -495,7 +494,7 @@ public class LDAPStatusChecker implements HealthChecker
                     final Instant passwordExpireDate = adminEntry.readPasswordExpirationDate();
                     final Instant passwordExpireDate = adminEntry.readPasswordExpirationDate();
                     final TimeDuration maxPwExpireTime = TimeDuration.of(
                     final TimeDuration maxPwExpireTime = TimeDuration.of(
                             Integer.parseInt( config.readAppProperty( AppProperty.HEALTH_LDAP_PROXY_WARN_PW_EXPIRE_SECONDS ) ),
                             Integer.parseInt( config.readAppProperty( AppProperty.HEALTH_LDAP_PROXY_WARN_PW_EXPIRE_SECONDS ) ),
-                            TimeUnit.SECONDS );
+                            TimeDuration.Unit.SECONDS );
                     final TimeDuration expirationDuration = TimeDuration.fromCurrent( passwordExpireDate  );
                     final TimeDuration expirationDuration = TimeDuration.fromCurrent( passwordExpireDate  );
                     if ( maxPwExpireTime.isLongerThan( expirationDuration ) )
                     if ( maxPwExpireTime.isLongerThan( expirationDuration ) )
                     {
                     {

+ 6 - 6
server/src/main/java/password/pwm/http/ContextManager.java

@@ -72,7 +72,7 @@ public class ContextManager implements Serializable
     private ErrorInformation startupErrorInformation;
     private ErrorInformation startupErrorInformation;
 
 
     private AtomicInteger restartCount = new AtomicInteger( 0 );
     private AtomicInteger restartCount = new AtomicInteger( 0 );
-    private TimeDuration readApplicationLockMaxWait = new TimeDuration( 5, TimeUnit.SECONDS );
+    private TimeDuration readApplicationLockMaxWait = TimeDuration.of( 5, TimeDuration.Unit.SECONDS );
     private final String instanceGuid;
     private final String instanceGuid;
     private final Lock reloadLock = new ReentrantLock();
     private final Lock reloadLock = new ReentrantLock();
 
 
@@ -144,7 +144,7 @@ public class ContextManager implements Serializable
         {
         {
             try
             try
             {
             {
-                final boolean hasLock = reloadLock.tryLock( readApplicationLockMaxWait.getTotalMilliseconds(), TimeUnit.MICROSECONDS );
+                final boolean hasLock = reloadLock.tryLock( readApplicationLockMaxWait.asMillis(), TimeUnit.MILLISECONDS );
                 if ( hasLock )
                 if ( hasLock )
                 {
                 {
                     return pwmApplication;
                     return pwmApplication;
@@ -264,9 +264,9 @@ public class ContextManager implements Serializable
                 reloadOnChange = Boolean.parseBoolean( pwmApplication.getConfig().readAppProperty( AppProperty.CONFIG_RELOAD_ON_CHANGE ) );
                 reloadOnChange = Boolean.parseBoolean( pwmApplication.getConfig().readAppProperty( AppProperty.CONFIG_RELOAD_ON_CHANGE ) );
                 fileScanFrequencyMs = Long.parseLong( pwmApplication.getConfig().readAppProperty( AppProperty.CONFIG_FILE_SCAN_FREQUENCY ) );
                 fileScanFrequencyMs = Long.parseLong( pwmApplication.getConfig().readAppProperty( AppProperty.CONFIG_FILE_SCAN_FREQUENCY ) );
 
 
-                this.readApplicationLockMaxWait = new TimeDuration(
+                this.readApplicationLockMaxWait = TimeDuration.of(
                         Long.parseLong( pwmApplication.getConfig().readAppProperty( AppProperty.APPLICATION_READ_APP_LOCK_MAX_WAIT_MS ) ),
                         Long.parseLong( pwmApplication.getConfig().readAppProperty( AppProperty.APPLICATION_READ_APP_LOCK_MAX_WAIT_MS ) ),
-                        TimeUnit.MILLISECONDS
+                        TimeDuration.Unit.MILLISECONDS
                 );
                 );
             }
             }
             if ( reloadOnChange )
             if ( reloadOnChange )
@@ -458,7 +458,7 @@ public class ContextManager implements Serializable
             final Instant startTime = Instant.now();
             final Instant startTime = Instant.now();
             final TimeDuration maxRequestWaitTime = TimeDuration.of(
             final TimeDuration maxRequestWaitTime = TimeDuration.of(
                     Integer.parseInt( pwmApplication.getConfig().readAppProperty( AppProperty.APPLICATION_RESTART_MAX_REQUEST_WAIT_MS ) ),
                     Integer.parseInt( pwmApplication.getConfig().readAppProperty( AppProperty.APPLICATION_RESTART_MAX_REQUEST_WAIT_MS ) ),
-                    TimeUnit.SECONDS );
+                    TimeDuration.Unit.SECONDS );
             final int startingRequetsInProgress = pwmApplication.getInprogressRequests().get();
             final int startingRequetsInProgress = pwmApplication.getInprogressRequests().get();
 
 
             if ( startingRequetsInProgress == 0 )
             if ( startingRequetsInProgress == 0 )
@@ -469,7 +469,7 @@ public class ContextManager implements Serializable
             LOGGER.trace( "waiting up to " + maxRequestWaitTime.asCompactString()
             LOGGER.trace( "waiting up to " + maxRequestWaitTime.asCompactString()
                     + " for " + startingRequetsInProgress  + " requests to complete." );
                     + " for " + startingRequetsInProgress  + " requests to complete." );
             JavaHelper.pause(
             JavaHelper.pause(
-                    maxRequestWaitTime.getTotalMilliseconds(),
+                    maxRequestWaitTime.asMillis(),
                     10,
                     10,
                     o -> pwmApplication.getInprogressRequests().get() == 0
                     o -> pwmApplication.getInprogressRequests().get() == 0
             );
             );

+ 13 - 14
server/src/main/java/password/pwm/http/IdleTimeoutCalculator.java

@@ -45,7 +45,6 @@ import java.util.Collections;
 import java.util.Set;
 import java.util.Set;
 import java.util.SortedSet;
 import java.util.SortedSet;
 import java.util.TreeSet;
 import java.util.TreeSet;
-import java.util.concurrent.TimeUnit;
 
 
 public class IdleTimeoutCalculator
 public class IdleTimeoutCalculator
 {
 {
@@ -60,7 +59,7 @@ public class IdleTimeoutCalculator
             final long idleSetting = configuration.readSettingAsLong( PwmSetting.IDLE_TIMEOUT_SECONDS );
             final long idleSetting = configuration.readSettingAsLong( PwmSetting.IDLE_TIMEOUT_SECONDS );
             results.add( new MaxIdleTimeoutResult(
             results.add( new MaxIdleTimeoutResult(
                     MaxIdleTimeoutResult.reasonFor( PwmSetting.IDLE_TIMEOUT_SECONDS, null ),
                     MaxIdleTimeoutResult.reasonFor( PwmSetting.IDLE_TIMEOUT_SECONDS, null ),
-                    new TimeDuration( idleSetting, TimeUnit.SECONDS ) ) );
+                    TimeDuration.of( idleSetting, TimeDuration.Unit.SECONDS ) ) );
         }
         }
 
 
         if ( !pwmSession.isAuthenticated() )
         if ( !pwmSession.isAuthenticated() )
@@ -70,7 +69,7 @@ public class IdleTimeoutCalculator
                 final long configGuideIdleTimeout = Long.parseLong( configuration.readAppProperty( AppProperty.CONFIG_GUIDE_IDLE_TIMEOUT ) );
                 final long configGuideIdleTimeout = Long.parseLong( configuration.readAppProperty( AppProperty.CONFIG_GUIDE_IDLE_TIMEOUT ) );
                 results.add( new MaxIdleTimeoutResult(
                 results.add( new MaxIdleTimeoutResult(
                         "Configuration Guide Idle Timeout",
                         "Configuration Guide Idle Timeout",
-                        new TimeDuration( configGuideIdleTimeout, TimeUnit.SECONDS ) ) );
+                        TimeDuration.of( configGuideIdleTimeout, TimeDuration.Unit.SECONDS ) ) );
             }
             }
 
 
             if ( configuration.readSettingAsBoolean( PwmSetting.PEOPLE_SEARCH_ENABLE_PUBLIC ) )
             if ( configuration.readSettingAsBoolean( PwmSetting.PEOPLE_SEARCH_ENABLE_PUBLIC ) )
@@ -80,7 +79,7 @@ public class IdleTimeoutCalculator
                 {
                 {
                     results.add( new MaxIdleTimeoutResult(
                     results.add( new MaxIdleTimeoutResult(
                             MaxIdleTimeoutResult.reasonFor( PwmSetting.PEOPLE_SEARCH_IDLE_TIMEOUT_SECONDS, null ),
                             MaxIdleTimeoutResult.reasonFor( PwmSetting.PEOPLE_SEARCH_IDLE_TIMEOUT_SECONDS, null ),
-                            new TimeDuration( peopleSearchIdleTimeout, TimeUnit.SECONDS ) ) );
+                            TimeDuration.of( peopleSearchIdleTimeout, TimeDuration.Unit.SECONDS ) ) );
                 }
                 }
             }
             }
 
 
@@ -106,10 +105,10 @@ public class IdleTimeoutCalculator
     {
     {
         final Set<MaxIdleTimeoutResult> results = new TreeSet<>();
         final Set<MaxIdleTimeoutResult> results = new TreeSet<>();
         {
         {
-            final long idleSetting = configuration.readSettingAsLong( PwmSetting.IDLE_TIMEOUT_SECONDS );
+            final long idleSecondsSetting = configuration.readSettingAsLong( PwmSetting.IDLE_TIMEOUT_SECONDS );
             results.add( new MaxIdleTimeoutResult(
             results.add( new MaxIdleTimeoutResult(
                     MaxIdleTimeoutResult.reasonFor( PwmSetting.IDLE_TIMEOUT_SECONDS, null ),
                     MaxIdleTimeoutResult.reasonFor( PwmSetting.IDLE_TIMEOUT_SECONDS, null ),
-                    new TimeDuration( idleSetting, TimeUnit.SECONDS ) ) );
+                    TimeDuration.of( idleSecondsSetting, TimeDuration.Unit.SECONDS ) ) );
         }
         }
 
 
         if ( configuration.readSettingAsBoolean( PwmSetting.HELPDESK_ENABLE ) )
         if ( configuration.readSettingAsBoolean( PwmSetting.HELPDESK_ENABLE ) )
@@ -121,7 +120,7 @@ public class IdleTimeoutCalculator
                 final long helpdeskIdleTimeout = helpdeskProfile.readSettingAsLong( PwmSetting.HELPDESK_IDLE_TIMEOUT_SECONDS );
                 final long helpdeskIdleTimeout = helpdeskProfile.readSettingAsLong( PwmSetting.HELPDESK_IDLE_TIMEOUT_SECONDS );
                 results.add( new MaxIdleTimeoutResult(
                 results.add( new MaxIdleTimeoutResult(
                         MaxIdleTimeoutResult.reasonFor( PwmSetting.HELPDESK_IDLE_TIMEOUT_SECONDS, helpdeskProfileID ),
                         MaxIdleTimeoutResult.reasonFor( PwmSetting.HELPDESK_IDLE_TIMEOUT_SECONDS, helpdeskProfileID ),
-                        new TimeDuration( helpdeskIdleTimeout, TimeUnit.SECONDS ) ) );
+                        TimeDuration.of( helpdeskIdleTimeout, TimeDuration.Unit.SECONDS ) ) );
             }
             }
         }
         }
 
 
@@ -132,7 +131,7 @@ public class IdleTimeoutCalculator
             {
             {
                 results.add( new MaxIdleTimeoutResult(
                 results.add( new MaxIdleTimeoutResult(
                         MaxIdleTimeoutResult.reasonFor( PwmSetting.PEOPLE_SEARCH_IDLE_TIMEOUT_SECONDS, null ),
                         MaxIdleTimeoutResult.reasonFor( PwmSetting.PEOPLE_SEARCH_IDLE_TIMEOUT_SECONDS, null ),
-                        new TimeDuration( peopleSearchIdleTimeout, TimeUnit.SECONDS ) ) );
+                        TimeDuration.of( peopleSearchIdleTimeout, TimeDuration.Unit.SECONDS ) ) );
             }
             }
         }
         }
 
 
@@ -141,7 +140,7 @@ public class IdleTimeoutCalculator
             final long configEditorIdleTimeout = Long.parseLong( configuration.readAppProperty( AppProperty.CONFIG_EDITOR_IDLE_TIMEOUT ) );
             final long configEditorIdleTimeout = Long.parseLong( configuration.readAppProperty( AppProperty.CONFIG_EDITOR_IDLE_TIMEOUT ) );
             results.add( new MaxIdleTimeoutResult(
             results.add( new MaxIdleTimeoutResult(
                     "Config Editor Idle Timeout",
                     "Config Editor Idle Timeout",
-                    new TimeDuration( configEditorIdleTimeout, TimeUnit.SECONDS ) ) );
+                    TimeDuration.of( configEditorIdleTimeout, TimeDuration.Unit.SECONDS ) ) );
         }
         }
 
 
         return Collections.unmodifiableSet( results );
         return Collections.unmodifiableSet( results );
@@ -190,7 +189,7 @@ public class IdleTimeoutCalculator
                     final long helpdeskIdleTimeout = helpdeskProfile.readSettingAsLong( PwmSetting.HELPDESK_IDLE_TIMEOUT_SECONDS );
                     final long helpdeskIdleTimeout = helpdeskProfile.readSettingAsLong( PwmSetting.HELPDESK_IDLE_TIMEOUT_SECONDS );
                     if ( helpdeskIdleTimeout > 0 )
                     if ( helpdeskIdleTimeout > 0 )
                     {
                     {
-                        return new TimeDuration( helpdeskIdleTimeout, TimeUnit.SECONDS );
+                        return TimeDuration.of( helpdeskIdleTimeout, TimeDuration.Unit.SECONDS );
                     }
                     }
                 }
                 }
             }
             }
@@ -209,7 +208,7 @@ public class IdleTimeoutCalculator
                 final long peopleSearchIdleTimeout = config.readSettingAsLong( PwmSetting.PEOPLE_SEARCH_IDLE_TIMEOUT_SECONDS );
                 final long peopleSearchIdleTimeout = config.readSettingAsLong( PwmSetting.PEOPLE_SEARCH_IDLE_TIMEOUT_SECONDS );
                 if ( peopleSearchIdleTimeout > 0 )
                 if ( peopleSearchIdleTimeout > 0 )
                 {
                 {
-                    return new TimeDuration( peopleSearchIdleTimeout, TimeUnit.SECONDS );
+                    return TimeDuration.of( peopleSearchIdleTimeout, TimeDuration.Unit.SECONDS );
                 }
                 }
             }
             }
         }
         }
@@ -223,7 +222,7 @@ public class IdleTimeoutCalculator
                     final long configEditorIdleTimeout = Long.parseLong( config.readAppProperty( AppProperty.CONFIG_EDITOR_IDLE_TIMEOUT ) );
                     final long configEditorIdleTimeout = Long.parseLong( config.readAppProperty( AppProperty.CONFIG_EDITOR_IDLE_TIMEOUT ) );
                     if ( configEditorIdleTimeout > 0 )
                     if ( configEditorIdleTimeout > 0 )
                     {
                     {
-                        return new TimeDuration( configEditorIdleTimeout, TimeUnit.SECONDS );
+                        return TimeDuration.of( configEditorIdleTimeout, TimeDuration.Unit.SECONDS );
                     }
                     }
                 }
                 }
             }
             }
@@ -240,12 +239,12 @@ public class IdleTimeoutCalculator
                 final long configGuideIdleTimeout = Long.parseLong( config.readAppProperty( AppProperty.CONFIG_GUIDE_IDLE_TIMEOUT ) );
                 final long configGuideIdleTimeout = Long.parseLong( config.readAppProperty( AppProperty.CONFIG_GUIDE_IDLE_TIMEOUT ) );
                 if ( configGuideIdleTimeout > 0 )
                 if ( configGuideIdleTimeout > 0 )
                 {
                 {
-                    return new TimeDuration( configGuideIdleTimeout, TimeUnit.SECONDS );
+                    return TimeDuration.of( configGuideIdleTimeout, TimeDuration.Unit.SECONDS );
                 }
                 }
             }
             }
         }
         }
 
 
         final long idleTimeout = config.readSettingAsLong( PwmSetting.IDLE_TIMEOUT_SECONDS );
         final long idleTimeout = config.readSettingAsLong( PwmSetting.IDLE_TIMEOUT_SECONDS );
-        return new TimeDuration( idleTimeout, TimeUnit.SECONDS );
+        return TimeDuration.of( idleTimeout, TimeDuration.Unit.SECONDS );
     }
     }
 }
 }

+ 3 - 2
server/src/main/java/password/pwm/http/PwmSessionWrapper.java

@@ -27,6 +27,7 @@ import password.pwm.PwmConstants;
 import password.pwm.error.ErrorInformation;
 import password.pwm.error.ErrorInformation;
 import password.pwm.error.PwmError;
 import password.pwm.error.PwmError;
 import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.error.PwmUnrecoverableException;
+import password.pwm.util.java.TimeDuration;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.logging.PwmLogger;
 
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletRequest;
@@ -83,9 +84,9 @@ public class PwmSessionWrapper
             throws PwmUnrecoverableException
             throws PwmUnrecoverableException
     {
     {
         final IdleTimeoutCalculator.MaxIdleTimeoutResult result = IdleTimeoutCalculator.figureMaxSessionTimeout( pwmApplication, pwmSession );
         final IdleTimeoutCalculator.MaxIdleTimeoutResult result = IdleTimeoutCalculator.figureMaxSessionTimeout( pwmApplication, pwmSession );
-        if ( httpSession.getMaxInactiveInterval() != result.getIdleTimeout().getTotalSeconds() )
+        if ( httpSession.getMaxInactiveInterval() != result.getIdleTimeout().as( TimeDuration.Unit.SECONDS ) )
         {
         {
-            httpSession.setMaxInactiveInterval( ( int ) result.getIdleTimeout().getTotalSeconds() );
+            httpSession.setMaxInactiveInterval( ( int ) result.getIdleTimeout().as( TimeDuration.Unit.SECONDS ) );
             LOGGER.trace( pwmSession, "setting java servlet session timeout to " + result.getIdleTimeout().asCompactString()
             LOGGER.trace( pwmSession, "setting java servlet session timeout to " + result.getIdleTimeout().asCompactString()
                     + " due to " + result.getReason() );
                     + " due to " + result.getReason() );
         }
         }

+ 3 - 0
server/src/main/java/password/pwm/http/bean/SetupResponsesBean.java

@@ -25,6 +25,7 @@ package password.pwm.http.bean;
 import com.novell.ldapchai.cr.Challenge;
 import com.novell.ldapchai.cr.Challenge;
 import com.novell.ldapchai.cr.ChallengeSet;
 import com.novell.ldapchai.cr.ChallengeSet;
 import lombok.Data;
 import lombok.Data;
+import lombok.EqualsAndHashCode;
 import password.pwm.config.option.SessionBeanMode;
 import password.pwm.config.option.SessionBeanMode;
 
 
 import java.io.Serializable;
 import java.io.Serializable;
@@ -34,6 +35,7 @@ import java.util.Map;
 import java.util.Set;
 import java.util.Set;
 
 
 @Data
 @Data
+@EqualsAndHashCode( callSuper = false )
 public class SetupResponsesBean extends PwmSessionBean
 public class SetupResponsesBean extends PwmSessionBean
 {
 {
     private boolean hasExistingResponses;
     private boolean hasExistingResponses;
@@ -50,6 +52,7 @@ public class SetupResponsesBean extends PwmSessionBean
     }
     }
 
 
     @Data
     @Data
+    @EqualsAndHashCode( callSuper = false )
     public static class SetupData implements Serializable
     public static class SetupData implements Serializable
     {
     {
         private ChallengeSet challengeSet;
         private ChallengeSet challengeSet;

+ 1 - 1
server/src/main/java/password/pwm/http/filter/ConfigAccessFilter.java

@@ -300,7 +300,7 @@ public class ConfigAccessFilter extends AbstractPwmFilter
             throws ServletException, PwmUnrecoverableException, IOException
             throws ServletException, PwmUnrecoverableException, IOException
     {
     {
         final int persistentSeconds = figureMaxLoginSeconds( pwmRequest );
         final int persistentSeconds = figureMaxLoginSeconds( pwmRequest );
-        final String time = new TimeDuration( persistentSeconds * 1000 ).asLongString( pwmRequest.getLocale() );
+        final String time = TimeDuration.of( persistentSeconds, TimeDuration.Unit.SECONDS ).asLongString( pwmRequest.getLocale() );
 
 
         final ConfigLoginHistory configLoginHistory = readConfigLoginHistory( pwmRequest );
         final ConfigLoginHistory configLoginHistory = readConfigLoginHistory( pwmRequest );
 
 

+ 2 - 1
server/src/main/java/password/pwm/http/filter/RequestInitializationFilter.java

@@ -651,7 +651,8 @@ public class RequestInitializationFilter implements Filter
             {
             {
                 final Long maxSessionSeconds = pwmRequest.getConfig().readSettingAsLong( PwmSetting.SESSION_MAX_SECONDS );
                 final Long maxSessionSeconds = pwmRequest.getConfig().readSettingAsLong( PwmSetting.SESSION_MAX_SECONDS );
                 final TimeDuration sessionAge = TimeDuration.fromCurrent( ssBean.getSessionCreationTime() );
                 final TimeDuration sessionAge = TimeDuration.fromCurrent( ssBean.getSessionCreationTime() );
-                if ( sessionAge.getTotalSeconds() > maxSessionSeconds )
+                final int sessionSecondAge = (int) sessionAge.as( TimeDuration.Unit.SECONDS );
+                if ( sessionSecondAge > maxSessionSeconds )
                 {
                 {
                     final String errorMsg = "session age (" + sessionAge.asCompactString() + ") is longer than maximum permitted age";
                     final String errorMsg = "session age (" + sessionAge.asCompactString() + ") is longer than maximum permitted age";
                     final ErrorInformation errorInformation = new ErrorInformation( PwmError.ERROR_SECURITY_VIOLATION, errorMsg );
                     final ErrorInformation errorInformation = new ErrorInformation( PwmError.ERROR_SECURITY_VIOLATION, errorMsg );

+ 1 - 1
server/src/main/java/password/pwm/http/filter/SessionFilter.java

@@ -417,7 +417,7 @@ public class SessionFilter extends AbstractPwmFilter
             return false;
             return false;
         }
         }
 
 
-        if ( TimeDuration.fromCurrent( currentPageLeaveNotice ).getTotalSeconds() <= configuredSeconds )
+        if ( TimeDuration.fromCurrent( currentPageLeaveNotice ).as( TimeDuration.Unit.SECONDS ) <= configuredSeconds )
         {
         {
             return false;
             return false;
         }
         }

+ 1 - 1
server/src/main/java/password/pwm/http/servlet/ClientApiServlet.java

@@ -353,7 +353,7 @@ public class ClientApiServlet extends ControlledPwmServlet
                 {
                 {
                     final PwmURL pwmURL = new PwmURL( new URI( pageUrl ), request.getContextPath() );
                     final PwmURL pwmURL = new PwmURL( new URI( pageUrl ), request.getContextPath() );
                     final TimeDuration maxIdleTime = IdleTimeoutCalculator.idleTimeoutForRequest( pwmURL, pwmApplication, pwmSession );
                     final TimeDuration maxIdleTime = IdleTimeoutCalculator.idleTimeoutForRequest( pwmURL, pwmApplication, pwmSession );
-                    idleSeconds = maxIdleTime.getTotalSeconds();
+                    idleSeconds = maxIdleTime.as( TimeDuration.Unit.SECONDS );
                 }
                 }
                 catch ( Exception e )
                 catch ( Exception e )
                 {
                 {

+ 2 - 3
server/src/main/java/password/pwm/http/servlet/admin/AdminServlet.java

@@ -98,7 +98,6 @@ import java.util.List;
 import java.util.Locale;
 import java.util.Locale;
 import java.util.Map;
 import java.util.Map;
 import java.util.TreeMap;
 import java.util.TreeMap;
-import java.util.concurrent.TimeUnit;
 import java.util.zip.GZIPOutputStream;
 import java.util.zip.GZIPOutputStream;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipOutputStream;
 import java.util.zip.ZipOutputStream;
@@ -474,7 +473,7 @@ public class AdminServlet extends ControlledPwmServlet
             throws PwmUnrecoverableException, IOException
             throws PwmUnrecoverableException, IOException
     {
     {
         final Instant startTime = Instant.now();
         final Instant startTime = Instant.now();
-        final TimeDuration maxSearchTime = new TimeDuration( 10, TimeUnit.SECONDS );
+        final TimeDuration maxSearchTime = TimeDuration.SECONDS_10;
         final int max = readMaxParameter( pwmRequest, 100, 10 * 1000 );
         final int max = readMaxParameter( pwmRequest, 100, 10 * 1000 );
         final AuditEvent.Type auditDataType = AuditEvent.Type.valueOf( pwmRequest.readParameterAsString( "type", AuditEvent.Type.USER.name() ) );
         final AuditEvent.Type auditDataType = AuditEvent.Type.valueOf( pwmRequest.readParameterAsString( "type", AuditEvent.Type.USER.name() ) );
         final ArrayList<AuditRecord> records = new ArrayList<>();
         final ArrayList<AuditRecord> records = new ArrayList<>();
@@ -830,7 +829,7 @@ public class AdminServlet extends ControlledPwmServlet
         {
         {
             final Map<String, String> inputMap = pwmRequest.readBodyAsJsonStringMap( PwmHttpRequestWrapper.Flag.BypassValidation );
             final Map<String, String> inputMap = pwmRequest.readBodyAsJsonStringMap( PwmHttpRequestWrapper.Flag.BypassValidation );
             final int eventCount = Integer.parseInt( inputMap.getOrDefault( "count", "0" ) );
             final int eventCount = Integer.parseInt( inputMap.getOrDefault( "count", "0" ) );
-            final TimeDuration maxTimeSeconds = new TimeDuration( Integer.parseInt( inputMap.getOrDefault( "maxTime", "5" ) ), TimeUnit.SECONDS );
+            final TimeDuration maxTimeSeconds = TimeDuration.of( Integer.parseInt( inputMap.getOrDefault( "maxTime", "5" ) ), TimeDuration.Unit.SECONDS );
             final String username = inputMap.getOrDefault( "username", "" );
             final String username = inputMap.getOrDefault( "username", "" );
             final String text = inputMap.getOrDefault( "text", "" );
             final String text = inputMap.getOrDefault( "text", "" );
             final PwmLogLevel logLevel = JavaHelper.readEnumFromString( PwmLogLevel.class, PwmLogLevel.TRACE, inputMap.get( "level" ) );
             final PwmLogLevel logLevel = JavaHelper.readEnumFromString( PwmLogLevel.class, PwmLogLevel.TRACE, inputMap.get( "level" ) );

+ 1 - 1
server/src/main/java/password/pwm/http/servlet/admin/ReportStatusBean.java

@@ -91,7 +91,7 @@ public class ReportStatusBean implements Serializable
                     {
                     {
                         final int usersRemaining = reportService.getWorkQueueSize();
                         final int usersRemaining = reportService.getWorkQueueSize();
                         final float secondsRemaining = usersRemaining / eventRate.floatValue();
                         final float secondsRemaining = usersRemaining / eventRate.floatValue();
-                        final TimeDuration remainingDuration = new TimeDuration( ( ( int ) secondsRemaining ) * 1000 );
+                        final TimeDuration remainingDuration = TimeDuration.of( ( int ) secondsRemaining, TimeDuration.Unit.SECONDS );
                         presentableMap.add( new DisplayElement( "timeRemaining", DisplayElement.Type.string, "Estimated Time Remaining",
                         presentableMap.add( new DisplayElement( "timeRemaining", DisplayElement.Type.string, "Estimated Time Remaining",
                                 remainingDuration.asLongString( locale ) ) );
                                 remainingDuration.asLongString( locale ) ) );
                     }
                     }

+ 2 - 2
server/src/main/java/password/pwm/http/servlet/changepw/ChangePasswordServlet.java

@@ -366,7 +366,7 @@ public abstract class ChangePasswordServlet extends ControlledPwmServlet
                 final TimeDuration totalTime = TimeDuration.fromCurrent( progressTracker.getBeginTime() );
                 final TimeDuration totalTime = TimeDuration.fromCurrent( progressTracker.getBeginTime() );
                 try
                 try
                 {
                 {
-                    pwmRequest.getPwmApplication().getStatisticsManager().updateAverageValue( Statistic.AVG_PASSWORD_SYNC_TIME, totalTime.getTotalMilliseconds() );
+                    pwmRequest.getPwmApplication().getStatisticsManager().updateAverageValue( Statistic.AVG_PASSWORD_SYNC_TIME, totalTime.asMillis() );
                     LOGGER.trace( pwmRequest, "password sync process marked completed (" + totalTime.asCompactString() + ")" );
                     LOGGER.trace( pwmRequest, "password sync process marked completed (" + totalTime.asCompactString() + ")" );
                 }
                 }
                 catch ( Exception e )
                 catch ( Exception e )
@@ -503,7 +503,7 @@ public abstract class ChangePasswordServlet extends ControlledPwmServlet
         final Instant maxCompleteTime = changePasswordBean.getChangePasswordMaxCompletion();
         final Instant maxCompleteTime = changePasswordBean.getChangePasswordMaxCompletion();
         pwmRequest.setAttribute(
         pwmRequest.setAttribute(
                 PwmRequestAttribute.ChangePassword_MaxWaitSeconds,
                 PwmRequestAttribute.ChangePassword_MaxWaitSeconds,
-                maxCompleteTime == null ? 30 : TimeDuration.fromCurrent( maxCompleteTime ).getTotalSeconds()
+                maxCompleteTime == null ? 30 : TimeDuration.fromCurrent( maxCompleteTime ).as( TimeDuration.Unit.SECONDS )
         );
         );
 
 
         pwmRequest.setAttribute(
         pwmRequest.setAttribute(

+ 1 - 2
server/src/main/java/password/pwm/http/servlet/configmanager/DebugItemGenerator.java

@@ -78,7 +78,6 @@ import java.util.Properties;
 import java.util.Set;
 import java.util.Set;
 import java.util.TreeMap;
 import java.util.TreeMap;
 import java.util.TreeSet;
 import java.util.TreeSet;
-import java.util.concurrent.TimeUnit;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipOutputStream;
 import java.util.zip.ZipOutputStream;
 
 
@@ -521,7 +520,7 @@ public class DebugItemGenerator
             final LocalDBSearchQuery searchParameters = LocalDBSearchQuery.builder()
             final LocalDBSearchQuery searchParameters = LocalDBSearchQuery.builder()
                     .minimumLevel( PwmLogLevel.TRACE )
                     .minimumLevel( PwmLogLevel.TRACE )
                     .maxEvents( maxCount )
                     .maxEvents( maxCount )
-                    .maxQueryTime( new TimeDuration( maxSeconds, TimeUnit.SECONDS ) )
+                    .maxQueryTime( TimeDuration.of( maxSeconds, TimeDuration.Unit.SECONDS ) )
                     .build();
                     .build();
 
 
             final LocalDBSearchResults searchResults = pwmApplication.getLocalDBLogger().readStoredEvents(
             final LocalDBSearchResults searchResults = pwmApplication.getLocalDBLogger().readStoredEvents(

+ 7 - 5
server/src/main/java/password/pwm/http/servlet/helpdesk/HelpdeskServlet.java

@@ -101,7 +101,6 @@ import java.time.Instant;
 import java.util.ArrayList;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Collections;
-import java.util.Date;
 import java.util.HashMap;
 import java.util.HashMap;
 import java.util.List;
 import java.util.List;
 import java.util.Locale;
 import java.util.Locale;
@@ -790,7 +789,7 @@ public class HelpdeskServlet extends ControlledPwmServlet
 
 
         final HelpdeskVerificationRequestBean.TokenData tokenData = new HelpdeskVerificationRequestBean.TokenData();
         final HelpdeskVerificationRequestBean.TokenData tokenData = new HelpdeskVerificationRequestBean.TokenData();
         tokenData.setToken( tokenKey );
         tokenData.setToken( tokenKey );
-        tokenData.setIssueDate( new Date() );
+        tokenData.setIssueDate( Instant.now() );
 
 
         final SecureService secureService = pwmRequest.getPwmApplication().getSecureService();
         final SecureService secureService = pwmRequest.getPwmApplication().getSecureService();
         helpdeskVerificationRequestBean.setTokenData( secureService.encryptObjectToString( tokenData ) );
         helpdeskVerificationRequestBean.setTokenData( secureService.encryptObjectToString( tokenData ) );
@@ -834,9 +833,12 @@ public class HelpdeskServlet extends ControlledPwmServlet
             throw new PwmUnrecoverableException( new ErrorInformation( PwmError.ERROR_TOKEN_INCORRECT, errorMsg ) );
             throw new PwmUnrecoverableException( new ErrorInformation( PwmError.ERROR_TOKEN_INCORRECT, errorMsg ) );
         }
         }
 
 
-        final TimeDuration maxTokenAge = new TimeDuration( Long.parseLong( pwmRequest.getConfig().readAppProperty( AppProperty.HELPDESK_TOKEN_MAX_AGE ) ) * 1000 );
-        final Date maxTokenAgeTimestamp = new Date( System.currentTimeMillis() - maxTokenAge.getTotalMilliseconds() );
-        if ( tokenData.getIssueDate().before( maxTokenAgeTimestamp ) )
+        final TimeDuration maxTokenAge = TimeDuration.of(
+                Long.parseLong( pwmRequest.getConfig().readAppProperty( AppProperty.HELPDESK_TOKEN_MAX_AGE ) ),
+                TimeDuration.Unit.SECONDS
+        );
+        final Instant maxTokenAgeTimestamp = Instant.ofEpochMilli( System.currentTimeMillis() - maxTokenAge.asMillis() );
+        if ( tokenData.getIssueDate().isBefore( maxTokenAgeTimestamp ) )
         {
         {
             final String errorMsg = "token is older than maximum issue time (" + maxTokenAge.asCompactString() + ")";
             final String errorMsg = "token is older than maximum issue time (" + maxTokenAge.asCompactString() + ")";
             throw new PwmUnrecoverableException( new ErrorInformation( PwmError.ERROR_TOKEN_EXPIRED, errorMsg ) );
             throw new PwmUnrecoverableException( new ErrorInformation( PwmError.ERROR_TOKEN_EXPIRED, errorMsg ) );

+ 6 - 71
server/src/main/java/password/pwm/http/servlet/helpdesk/HelpdeskVerificationRequestBean.java

@@ -22,9 +22,12 @@
 
 
 package password.pwm.http.servlet.helpdesk;
 package password.pwm.http.servlet.helpdesk;
 
 
+import lombok.Data;
+
 import java.io.Serializable;
 import java.io.Serializable;
-import java.util.Date;
+import java.time.Instant;
 
 
+@Data
 public class HelpdeskVerificationRequestBean implements Serializable
 public class HelpdeskVerificationRequestBean implements Serializable
 {
 {
 
 
@@ -36,79 +39,11 @@ public class HelpdeskVerificationRequestBean implements Serializable
     private String tokenData;
     private String tokenData;
     private String verificationState;
     private String verificationState;
 
 
-    public String getDestination( )
-    {
-        return destination;
-    }
-
-    public void setDestination( final String destination )
-    {
-        this.destination = destination;
-    }
-
-    public String getUserKey( )
-    {
-        return userKey;
-    }
-
-    public void setUserKey( final String userKey )
-    {
-        this.userKey = userKey;
-    }
-
-    public String getCode( )
-    {
-        return code;
-    }
-
-    public void setCode( final String code )
-    {
-        this.code = code;
-    }
-
-    public String getTokenData( )
-    {
-        return tokenData;
-    }
-
-    public void setTokenData( final String tokenData )
-    {
-        this.tokenData = tokenData;
-    }
-
-    public String getVerificationState( )
-    {
-        return verificationState;
-    }
-
-    public void setVerificationState( final String verificationState )
-    {
-        this.verificationState = verificationState;
-    }
 
 
+    @Data
     static class TokenData implements Serializable
     static class TokenData implements Serializable
     {
     {
         private String token;
         private String token;
-        private Date issueDate;
-
-        public String getToken( )
-        {
-            return token;
-        }
-
-        public void setToken( final String token )
-        {
-            this.token = token;
-        }
-
-        public Date getIssueDate( )
-        {
-            return issueDate;
-        }
-
-        public void setIssueDate( final Date issueDate )
-        {
-            this.issueDate = issueDate;
-        }
+        private Instant issueDate;
     }
     }
 }
 }

+ 3 - 16
server/src/main/java/password/pwm/http/servlet/helpdesk/HelpdeskVerificationResponseBean.java

@@ -22,26 +22,13 @@
 
 
 package password.pwm.http.servlet.helpdesk;
 package password.pwm.http.servlet.helpdesk;
 
 
+import lombok.Value;
+
 import java.io.Serializable;
 import java.io.Serializable;
 
 
+@Value
 public class HelpdeskVerificationResponseBean implements Serializable
 public class HelpdeskVerificationResponseBean implements Serializable
 {
 {
     private boolean passed;
     private boolean passed;
     private String verificationState;
     private String verificationState;
-
-    public HelpdeskVerificationResponseBean( final boolean passed, final String verificationState )
-    {
-        this.passed = passed;
-        this.verificationState = verificationState;
-    }
-
-    public boolean isPassed( )
-    {
-        return passed;
-    }
-
-    public String getVerificationState( )
-    {
-        return verificationState;
-    }
 }
 }

+ 16 - 14
server/src/main/java/password/pwm/http/servlet/helpdesk/HelpdeskVerificationStateBean.java

@@ -39,26 +39,27 @@ import password.pwm.util.java.TimeDuration;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.logging.PwmLogger;
 
 
 import java.io.Serializable;
 import java.io.Serializable;
+import java.time.Instant;
 import java.util.ArrayList;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Collections;
-import java.util.Date;
 import java.util.Iterator;
 import java.util.Iterator;
 import java.util.List;
 import java.util.List;
 import java.util.Locale;
 import java.util.Locale;
 import java.util.Map;
 import java.util.Map;
 import java.util.TreeMap;
 import java.util.TreeMap;
-import java.util.concurrent.TimeUnit;
 
 
 class HelpdeskVerificationStateBean implements Serializable
 class HelpdeskVerificationStateBean implements Serializable
 {
 {
     private static final PwmLogger LOGGER = PwmLogger.forClass( HelpdeskVerificationStateBean.class );
     private static final PwmLogger LOGGER = PwmLogger.forClass( HelpdeskVerificationStateBean.class );
+    public static final String PARAMETER_VERIFICATION_STATE_KEY = "verificationState";
+
     private final UserIdentity actor;
     private final UserIdentity actor;
     private final List<HelpdeskValidationRecord> records = new ArrayList<>();
     private final List<HelpdeskValidationRecord> records = new ArrayList<>();
 
 
-    public static final String PARAMETER_VERIFICATION_STATE_KEY = "verificationState";
-
     private transient TimeDuration maximumAge;
     private transient TimeDuration maximumAge;
 
 
+
+
     private HelpdeskVerificationStateBean( final UserIdentity actor )
     private HelpdeskVerificationStateBean( final UserIdentity actor )
     {
     {
         this.actor = actor;
         this.actor = actor;
@@ -83,7 +84,7 @@ class HelpdeskVerificationStateBean implements Serializable
         {
         {
             records.remove( record );
             records.remove( record );
         }
         }
-        records.add( new HelpdeskValidationRecord( new Date(), identity, method ) );
+        records.add( new HelpdeskValidationRecord( Instant.now(), identity, method ) );
     }
     }
 
 
     public boolean hasRecord( final UserIdentity identity, final IdentityVerificationMethod method )
     public boolean hasRecord( final UserIdentity identity, final IdentityVerificationMethod method )
@@ -110,7 +111,7 @@ class HelpdeskVerificationStateBean implements Serializable
         for ( final Iterator<HelpdeskValidationRecord> iterator = records.iterator(); iterator.hasNext(); )
         for ( final Iterator<HelpdeskValidationRecord> iterator = records.iterator(); iterator.hasNext(); )
         {
         {
             final HelpdeskValidationRecord record = iterator.next();
             final HelpdeskValidationRecord record = iterator.next();
-            final Date timestamp = record.getTimestamp();
+            final Instant timestamp = record.getTimestamp();
             final TimeDuration age = TimeDuration.fromCurrent( timestamp );
             final TimeDuration age = TimeDuration.fromCurrent( timestamp );
             if ( age.isLongerThan( maximumAge ) )
             if ( age.isLongerThan( maximumAge ) )
             {
             {
@@ -125,7 +126,7 @@ class HelpdeskVerificationStateBean implements Serializable
     )
     )
             throws ChaiOperationException, ChaiUnavailableException, PwmUnrecoverableException
             throws ChaiOperationException, ChaiUnavailableException, PwmUnrecoverableException
     {
     {
-        final Map<Date, ViewableValidationRecord> returnRecords = new TreeMap<>();
+        final Map<Instant, ViewableValidationRecord> returnRecords = new TreeMap<>();
         for ( final HelpdeskValidationRecord record : records )
         for ( final HelpdeskValidationRecord record : records )
         {
         {
             final UserInfo userInfo = UserInfoFactory.newUserInfoUsingProxy( pwmApplication, SessionLabel.SYSTEM_LABEL, record.getIdentity(), PwmConstants.DEFAULT_LOCALE );
             final UserInfo userInfo = UserInfoFactory.newUserInfoUsingProxy( pwmApplication, SessionLabel.SYSTEM_LABEL, record.getIdentity(), PwmConstants.DEFAULT_LOCALE );
@@ -137,14 +138,15 @@ class HelpdeskVerificationStateBean implements Serializable
         return Collections.unmodifiableList( new ArrayList<>( returnRecords.values() ) );
         return Collections.unmodifiableList( new ArrayList<>( returnRecords.values() ) );
     }
     }
 
 
+
     static class ViewableValidationRecord implements Serializable
     static class ViewableValidationRecord implements Serializable
     {
     {
-        private Date timestamp;
+        private Instant timestamp;
         private String profile;
         private String profile;
         private String username;
         private String username;
         private String method;
         private String method;
 
 
-        ViewableValidationRecord( final Date timestamp, final String profile, final String username, final String method )
+        ViewableValidationRecord( final Instant timestamp, final String profile, final String username, final String method )
         {
         {
             this.timestamp = timestamp;
             this.timestamp = timestamp;
             this.profile = profile;
             this.profile = profile;
@@ -152,7 +154,7 @@ class HelpdeskVerificationStateBean implements Serializable
             this.method = method;
             this.method = method;
         }
         }
 
 
-        public Date getTimestamp( )
+        public Instant getTimestamp( )
         {
         {
             return timestamp;
             return timestamp;
         }
         }
@@ -175,18 +177,18 @@ class HelpdeskVerificationStateBean implements Serializable
 
 
     static class HelpdeskValidationRecord implements Serializable
     static class HelpdeskValidationRecord implements Serializable
     {
     {
-        private Date timestamp;
+        private Instant timestamp;
         private UserIdentity identity;
         private UserIdentity identity;
         private IdentityVerificationMethod method;
         private IdentityVerificationMethod method;
 
 
-        HelpdeskValidationRecord( final Date timestamp, final UserIdentity identity, final IdentityVerificationMethod method )
+        HelpdeskValidationRecord( final Instant timestamp, final UserIdentity identity, final IdentityVerificationMethod method )
         {
         {
             this.timestamp = timestamp;
             this.timestamp = timestamp;
             this.identity = identity;
             this.identity = identity;
             this.method = method;
             this.method = method;
         }
         }
 
 
-        public Date getTimestamp( )
+        public Instant getTimestamp( )
         {
         {
             return timestamp;
             return timestamp;
         }
         }
@@ -214,7 +216,7 @@ class HelpdeskVerificationStateBean implements Serializable
             throws PwmUnrecoverableException
             throws PwmUnrecoverableException
     {
     {
         final int maxAgeSeconds = Integer.parseInt( pwmRequest.getConfig().readAppProperty( AppProperty.HELPDESK_VERIFICATION_TIMEOUT_SECONDS ) );
         final int maxAgeSeconds = Integer.parseInt( pwmRequest.getConfig().readAppProperty( AppProperty.HELPDESK_VERIFICATION_TIMEOUT_SECONDS ) );
-        final TimeDuration maxAge = new TimeDuration( maxAgeSeconds, TimeUnit.SECONDS );
+        final TimeDuration maxAge = TimeDuration.of( maxAgeSeconds, TimeDuration.Unit.SECONDS );
         final UserIdentity actor = pwmRequest.getUserInfoIfLoggedIn();
         final UserIdentity actor = pwmRequest.getUserInfoIfLoggedIn();
 
 
         HelpdeskVerificationStateBean state = null;
         HelpdeskVerificationStateBean state = null;

+ 1 - 1
server/src/main/java/password/pwm/http/servlet/newuser/NewUserServlet.java

@@ -637,7 +637,7 @@ public class NewUserServlet extends ControlledPwmServlet
         {
         {
             final TimeDuration elapsedTime = TimeDuration.fromCurrent( startTime );
             final TimeDuration elapsedTime = TimeDuration.fromCurrent( startTime );
             complete = false;
             complete = false;
-            percentComplete = new Percent( elapsedTime.getTotalMilliseconds(), minWaitTime ).asBigDecimal();
+            percentComplete = new Percent( elapsedTime.asMillis(), minWaitTime ).asBigDecimal();
         }
         }
 
 
         final LinkedHashMap<String, Object> outputMap = new LinkedHashMap<>();
         final LinkedHashMap<String, Object> outputMap = new LinkedHashMap<>();

+ 1 - 2
server/src/main/java/password/pwm/http/state/CryptoCookieBeanImpl.java

@@ -37,7 +37,6 @@ import password.pwm.util.secure.PwmSecurityKey;
 import java.io.Serializable;
 import java.io.Serializable;
 import java.util.HashMap;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Map;
-import java.util.concurrent.TimeUnit;
 
 
 class CryptoCookieBeanImpl implements SessionBeanProvider
 class CryptoCookieBeanImpl implements SessionBeanProvider
 {
 {
@@ -113,7 +112,7 @@ class CryptoCookieBeanImpl implements SessionBeanProvider
 
 
             final TimeDuration cookieLifeDuration = TimeDuration.fromCurrent( cookieBean.getTimestamp() );
             final TimeDuration cookieLifeDuration = TimeDuration.fromCurrent( cookieBean.getTimestamp() );
             final long maxIdleSeconds = pwmRequest.getConfig().readSettingAsLong( PwmSetting.IDLE_TIMEOUT_SECONDS );
             final long maxIdleSeconds = pwmRequest.getConfig().readSettingAsLong( PwmSetting.IDLE_TIMEOUT_SECONDS );
-            if ( cookieLifeDuration.isLongerThan( maxIdleSeconds, TimeUnit.SECONDS ) )
+            if ( cookieLifeDuration.isLongerThan( maxIdleSeconds, TimeDuration.Unit.SECONDS ) )
             {
             {
                 LOGGER.trace( pwmRequest, "disregarded existing " + cookieName + " cookie bean due to outdated timestamp (" + cookieLifeDuration.asCompactString() + ")" );
                 LOGGER.trace( pwmRequest, "disregarded existing " + cookieName + " cookie bean due to outdated timestamp (" + cookieLifeDuration.asCompactString() + ")" );
                 return false;
                 return false;

+ 1 - 2
server/src/main/java/password/pwm/http/state/CryptoCookieLoginImpl.java

@@ -45,7 +45,6 @@ import password.pwm.util.java.TimeDuration;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.logging.PwmLogger;
 
 
 import java.time.Instant;
 import java.time.Instant;
-import java.util.concurrent.TimeUnit;
 
 
 class CryptoCookieLoginImpl implements SessionLoginProvider
 class CryptoCookieLoginImpl implements SessionLoginProvider
 {
 {
@@ -226,7 +225,7 @@ class CryptoCookieLoginImpl implements SessionLoginProvider
         {
         {
             final long sessionMaxSeconds = pwmRequest.getConfig().readSettingAsLong( PwmSetting.SESSION_MAX_SECONDS );
             final long sessionMaxSeconds = pwmRequest.getConfig().readSettingAsLong( PwmSetting.SESSION_MAX_SECONDS );
             final TimeDuration sessionTotalAge = TimeDuration.fromCurrent( loginInfoBean.getAuthTime() );
             final TimeDuration sessionTotalAge = TimeDuration.fromCurrent( loginInfoBean.getAuthTime() );
-            final TimeDuration sessionMaxAge = new TimeDuration( sessionMaxSeconds, TimeUnit.SECONDS );
+            final TimeDuration sessionMaxAge = TimeDuration.of( sessionMaxSeconds, TimeDuration.Unit.SECONDS );
             if ( sessionTotalAge.isLongerThan( sessionMaxAge ) )
             if ( sessionTotalAge.isLongerThan( sessionMaxAge ) )
             {
             {
                 final String errorMsg = "decrypted login cookie age ("
                 final String errorMsg = "decrypted login cookie age ("

+ 1 - 2
server/src/main/java/password/pwm/ldap/LdapOperationsHelper.java

@@ -75,7 +75,6 @@ import java.util.List;
 import java.util.Map;
 import java.util.Map;
 import java.util.Queue;
 import java.util.Queue;
 import java.util.Set;
 import java.util.Set;
-import java.util.concurrent.TimeUnit;
 
 
 public class LdapOperationsHelper
 public class LdapOperationsHelper
 {
 {
@@ -242,7 +241,7 @@ public class LdapOperationsHelper
         if ( enableCache )
         if ( enableCache )
         {
         {
             final long cacheSeconds = Long.parseLong( pwmApplication.getConfig().readAppProperty( AppProperty.LDAP_CACHE_USER_GUID_SECONDS ) );
             final long cacheSeconds = Long.parseLong( pwmApplication.getConfig().readAppProperty( AppProperty.LDAP_CACHE_USER_GUID_SECONDS ) );
-            final CachePolicy cachePolicy = CachePolicy.makePolicyWithExpiration( new TimeDuration( cacheSeconds, TimeUnit.SECONDS ) );
+            final CachePolicy cachePolicy = CachePolicy.makePolicyWithExpiration( TimeDuration.of( cacheSeconds, TimeDuration.Unit.SECONDS ) );
             final String cacheValue = existingValue == null
             final String cacheValue = existingValue == null
                     ? NULL_CACHE_GUID
                     ? NULL_CACHE_GUID
                     : existingValue;
                     : existingValue;

+ 12 - 12
server/src/main/java/password/pwm/ldap/PasswordChangeProgressChecker.java

@@ -184,8 +184,8 @@ public class PasswordChangeProgressChecker
 
 
         newItemProgress.putAll( figureItemProgresses( tracker ) );
         newItemProgress.putAll( figureItemProgresses( tracker ) );
         final Instant estimatedCompletion = figureEstimatedCompletion( tracker, newItemProgress.values() );
         final Instant estimatedCompletion = figureEstimatedCompletion( tracker, newItemProgress.values() );
-        final long elapsedMs = TimeDuration.fromCurrent( tracker.beginTime ).getTotalMilliseconds();
-        final long remainingMs = TimeDuration.fromCurrent( estimatedCompletion ).getTotalMilliseconds();
+        final long elapsedMs = TimeDuration.fromCurrent( tracker.beginTime ).asMillis();
+        final long remainingMs = TimeDuration.fromCurrent( estimatedCompletion ).asMillis();
 
 
         final Percent percentage;
         final Percent percentage;
         if ( Instant.now().isAfter( estimatedCompletion ) )
         if ( Instant.now().isAfter( estimatedCompletion ) )
@@ -194,7 +194,7 @@ public class PasswordChangeProgressChecker
         }
         }
         else
         else
         {
         {
-            final long totalMs = new TimeDuration( tracker.beginTime, estimatedCompletion ).getTotalMilliseconds();
+            final long totalMs = TimeDuration.between( tracker.beginTime, estimatedCompletion ).asMillis();
             percentage = new Percent( elapsedMs, totalMs + 1 );
             percentage = new Percent( elapsedMs, totalMs + 1 );
         }
         }
         tracker.itemCompletions.putAll( newItemProgress );
         tracker.itemCompletions.putAll( newItemProgress );
@@ -202,8 +202,8 @@ public class PasswordChangeProgressChecker
                 percentage.isComplete(),
                 percentage.isComplete(),
                 percentage.asBigDecimal( 2 ),
                 percentage.asBigDecimal( 2 ),
                 newItemProgress.values(),
                 newItemProgress.values(),
-                new TimeDuration( elapsedMs ).asLongString( locale ),
-                new TimeDuration( remainingMs ).asLongString( locale )
+                TimeDuration.of( elapsedMs, TimeDuration.Unit.MILLISECONDS ).asLongString( locale ),
+                TimeDuration.of( remainingMs, TimeDuration.Unit.MILLISECONDS ).asLongString( locale )
         );
         );
     }
     }
 
 
@@ -228,7 +228,7 @@ public class PasswordChangeProgressChecker
             /*
             /*
             final long randMs = PwmRandom.getInstance().nextInt(90 * 1000) + 30 * 1000;
             final long randMs = PwmRandom.getInstance().nextInt(90 * 1000) + 30 * 1000;
             //final long randMs = 75 * 1000;
             //final long randMs = 75 * 1000;
-            final long elapsedMs = TimeDuration.fromCurrent(tracker.beginTime).getTotalMilliseconds();
+            final long elapsedMs = TimeDuration.fromCurrent(tracker.beginTime).asMillis();
             final Percent percent = new Percent(elapsedMs,randMs);
             final Percent percent = new Percent(elapsedMs,randMs);
             final ProgressRecord record = new ProgressRecord();
             final ProgressRecord record = new ProgressRecord();
             record.key = "randomItem";
             record.key = "randomItem";
@@ -247,14 +247,14 @@ public class PasswordChangeProgressChecker
 
 
     public Instant maxCompletionTime( final ProgressTracker tracker )
     public Instant maxCompletionTime( final ProgressTracker tracker )
     {
     {
-        final TimeDuration maxWait = new TimeDuration( pwmApplication.getConfig().readSettingAsLong( PwmSetting.PASSWORD_SYNC_MAX_WAIT_TIME ) * 1000 );
-        return Instant.ofEpochMilli( tracker.beginTime.toEpochMilli() + maxWait.getTotalMilliseconds() );
+        final TimeDuration maxWait = TimeDuration.of( pwmApplication.getConfig().readSettingAsLong( PwmSetting.PASSWORD_SYNC_MAX_WAIT_TIME ), TimeDuration.Unit.SECONDS );
+        return Instant.ofEpochMilli( tracker.beginTime.toEpochMilli() + maxWait.asMillis() );
     }
     }
 
 
     private Instant minCompletionTime( final ProgressTracker tracker )
     private Instant minCompletionTime( final ProgressTracker tracker )
     {
     {
-        final TimeDuration minWait = new TimeDuration( pwmApplication.getConfig().readSettingAsLong( PwmSetting.PASSWORD_SYNC_MIN_WAIT_TIME ) * 1000 );
-        return Instant.ofEpochMilli( tracker.beginTime.toEpochMilli() + minWait.getTotalMilliseconds() );
+        final TimeDuration minWait = TimeDuration.of( pwmApplication.getConfig().readSettingAsLong( PwmSetting.PASSWORD_SYNC_MIN_WAIT_TIME ), TimeDuration.Unit.SECONDS );
+        return Instant.ofEpochMilli( tracker.beginTime.toEpochMilli() + minWait.asMillis() );
     }
     }
 
 
     private Instant figureEstimatedCompletion(
     private Instant figureEstimatedCompletion(
@@ -320,8 +320,8 @@ public class PasswordChangeProgressChecker
     {
     {
         final long initDelayMs = Long.parseLong( pwmApplication.getConfig().readAppProperty( AppProperty.LDAP_PASSWORD_REPLICA_CHECK_INIT_DELAY_MS ) );
         final long initDelayMs = Long.parseLong( pwmApplication.getConfig().readAppProperty( AppProperty.LDAP_PASSWORD_REPLICA_CHECK_INIT_DELAY_MS ) );
         final long cycleDelayMs = Long.parseLong( pwmApplication.getConfig().readAppProperty( AppProperty.LDAP_PASSWORD_REPLICA_CHECK_CYCLE_DELAY_MS ) );
         final long cycleDelayMs = Long.parseLong( pwmApplication.getConfig().readAppProperty( AppProperty.LDAP_PASSWORD_REPLICA_CHECK_CYCLE_DELAY_MS ) );
-        final TimeDuration initialReplicaDelay = new TimeDuration( initDelayMs );
-        final TimeDuration cycleReplicaDelay = new TimeDuration( cycleDelayMs );
+        final TimeDuration initialReplicaDelay = TimeDuration.of( initDelayMs, TimeDuration.Unit.MILLISECONDS );
+        final TimeDuration cycleReplicaDelay = TimeDuration.of( cycleDelayMs, TimeDuration.Unit.MILLISECONDS );
 
 
         if ( passwordSyncCheckMode == PasswordSyncCheckMode.DISABLED )
         if ( passwordSyncCheckMode == PasswordSyncCheckMode.DISABLED )
         {
         {

+ 2 - 2
server/src/main/java/password/pwm/ldap/UserInfoReader.java

@@ -280,7 +280,7 @@ public class UserInfoReader implements UserInfo
 
 
             // now check to see if the user's expire time is within the 'preExpireTime' setting.
             // now check to see if the user's expire time is within the 'preExpireTime' setting.
             final long preExpireMs = config.readSettingAsLong( PwmSetting.PASSWORD_EXPIRE_PRE_TIME ) * 1000;
             final long preExpireMs = config.readSettingAsLong( PwmSetting.PASSWORD_EXPIRE_PRE_TIME ) * 1000;
-            if ( diff.getTotalMilliseconds() > 0 && diff.getTotalMilliseconds() < preExpireMs )
+            if ( diff.asMillis() > 0 && diff.asMillis() < preExpireMs )
             {
             {
                 LOGGER.debug( sessionLabel, "user " + userDN + " password will expire within "
                 LOGGER.debug( sessionLabel, "user " + userDN + " password will expire within "
                         + diff.asCompactString()
                         + diff.asCompactString()
@@ -300,7 +300,7 @@ public class UserInfoReader implements UserInfo
             {
             {
                 if ( !( preWarnMs == 0 || preWarnMs < preExpireMs ) )
                 if ( !( preWarnMs == 0 || preWarnMs < preExpireMs ) )
                 {
                 {
-                    if ( diff.getTotalMilliseconds() > 0 && diff.getTotalMilliseconds() < preWarnMs )
+                    if ( diff.asMillis() > 0 && diff.asMillis() < preWarnMs )
                     {
                     {
                         LOGGER.debug( sessionLabel,
                         LOGGER.debug( sessionLabel,
                                 "user " + userDN + " password will expire within "
                                 "user " + userDN + " password will expire within "

+ 5 - 6
server/src/main/java/password/pwm/ldap/auth/LDAPAuthenticationRequest.java

@@ -67,7 +67,6 @@ import password.pwm.util.operations.PasswordUtility;
 
 
 import java.time.Instant;
 import java.time.Instant;
 import java.util.Collections;
 import java.util.Collections;
-import java.util.Date;
 import java.util.HashSet;
 import java.util.HashSet;
 import java.util.Set;
 import java.util.Set;
 
 
@@ -84,10 +83,10 @@ class LDAPAuthenticationRequest implements AuthenticationRequest
 
 
     private ChaiProvider userProvider;
     private ChaiProvider userProvider;
     private AuthenticationStrategy strategy = AuthenticationStrategy.BIND;
     private AuthenticationStrategy strategy = AuthenticationStrategy.BIND;
-    private Date startTime;
+    private Instant startTime;
 
 
     private static final AtomicLoopIntIncrementer OPERATION_COUNTER = new AtomicLoopIntIncrementer( 0 );
     private static final AtomicLoopIntIncrementer OPERATION_COUNTER = new AtomicLoopIntIncrementer( 0 );
-    private int operationNumber = 0;
+    private final int operationNumber;
 
 
 
 
     LDAPAuthenticationRequest(
     LDAPAuthenticationRequest(
@@ -190,7 +189,7 @@ class LDAPAuthenticationRequest implements AuthenticationRequest
     {
     {
         if ( startTime == null )
         if ( startTime == null )
         {
         {
-            startTime = new Date();
+            startTime = Instant.now();
         }
         }
 
 
         log( PwmLogLevel.DEBUG, "preparing to authenticate user using authenticationType=" + this.requestedAuthType + " using strategy " + this.strategy );
         log( PwmLogLevel.DEBUG, "preparing to authenticate user using authenticationType=" + this.requestedAuthType + " using strategy " + this.strategy );
@@ -277,7 +276,7 @@ class LDAPAuthenticationRequest implements AuthenticationRequest
         statisticsManager.incrementValue( Statistic.AUTHENTICATIONS );
         statisticsManager.incrementValue( Statistic.AUTHENTICATIONS );
         statisticsManager.updateEps( EpsStatistic.AUTHENTICATION, 1 );
         statisticsManager.updateEps( EpsStatistic.AUTHENTICATION, 1 );
         statisticsManager.updateAverageValue( Statistic.AVG_AUTHENTICATION_TIME,
         statisticsManager.updateAverageValue( Statistic.AVG_AUTHENTICATION_TIME,
-                TimeDuration.fromCurrent( startTime ).getTotalMilliseconds() );
+                TimeDuration.fromCurrent( startTime ).asMillis() );
 
 
         final AuthenticationType returnAuthType;
         final AuthenticationType returnAuthType;
         if ( !allowBindAsUser )
         if ( !allowBindAsUser )
@@ -339,7 +338,7 @@ class LDAPAuthenticationRequest implements AuthenticationRequest
         {
         {
             throw new IllegalStateException( "AuthenticationRequest can not be used more than once" );
             throw new IllegalStateException( "AuthenticationRequest can not be used more than once" );
         }
         }
-        startTime = new Date();
+        startTime = Instant.now();
     }
     }
 
 
     private void testCredentials(
     private void testCredentials(

+ 2 - 2
server/src/main/java/password/pwm/ldap/search/UserSearchEngine.java

@@ -95,7 +95,7 @@ public class UserSearchEngine implements PwmService
 
 
     private final ConditionalTaskExecutor debugOutputTask = new ConditionalTaskExecutor(
     private final ConditionalTaskExecutor debugOutputTask = new ConditionalTaskExecutor(
             ( ) -> periodicDebugOutput(),
             ( ) -> periodicDebugOutput(),
-            new ConditionalTaskExecutor.TimeDurationPredicate( 1, TimeUnit.MINUTES )
+            new ConditionalTaskExecutor.TimeDurationPredicate( 1, TimeDuration.Unit.MINUTES )
     );
     );
 
 
     public UserSearchEngine( )
     public UserSearchEngine( )
@@ -532,7 +532,7 @@ public class UserSearchEngine implements PwmService
 
 
         if ( pwmApplication.getStatisticsManager() != null && pwmApplication.getStatisticsManager().status() == PwmService.STATUS.OPEN )
         if ( pwmApplication.getStatisticsManager() != null && pwmApplication.getStatisticsManager().status() == PwmService.STATUS.OPEN )
         {
         {
-            pwmApplication.getStatisticsManager().updateAverageValue( Statistic.AVG_LDAP_SEARCH_TIME, searchDuration.getTotalMilliseconds() );
+            pwmApplication.getStatisticsManager().updateAverageValue( Statistic.AVG_LDAP_SEARCH_TIME, searchDuration.asMillis() );
         }
         }
 
 
         if ( results.isEmpty() )
         if ( results.isEmpty() )

+ 1 - 1
server/src/main/java/password/pwm/svc/cache/CachePolicy.java

@@ -49,7 +49,7 @@ public class CachePolicy implements Serializable
 
 
     public static CachePolicy makePolicyWithExpiration( final TimeDuration timeDuration )
     public static CachePolicy makePolicyWithExpiration( final TimeDuration timeDuration )
     {
     {
-        return makePolicyWithExpirationMS( timeDuration.getTotalMilliseconds() );
+        return makePolicyWithExpirationMS( timeDuration.asMillis() );
     }
     }
 
 
 }
 }

+ 2 - 2
server/src/main/java/password/pwm/svc/cache/CacheService.java

@@ -31,6 +31,7 @@ import password.pwm.health.HealthRecord;
 import password.pwm.svc.PwmService;
 import password.pwm.svc.PwmService;
 import password.pwm.util.java.ConditionalTaskExecutor;
 import password.pwm.util.java.ConditionalTaskExecutor;
 import password.pwm.util.java.JsonUtil;
 import password.pwm.util.java.JsonUtil;
+import password.pwm.util.java.TimeDuration;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.logging.PwmLogger;
 
 
 import java.io.Serializable;
 import java.io.Serializable;
@@ -42,7 +43,6 @@ import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.List;
 import java.util.Map;
 import java.util.Map;
 import java.util.TreeMap;
 import java.util.TreeMap;
-import java.util.concurrent.TimeUnit;
 
 
 public class CacheService implements PwmService
 public class CacheService implements PwmService
 {
 {
@@ -91,7 +91,7 @@ public class CacheService implements PwmService
         memoryCacheStore = new MemoryCacheStore( maxMemItems );
         memoryCacheStore = new MemoryCacheStore( maxMemItems );
         this.traceDebugOutputter = new ConditionalTaskExecutor(
         this.traceDebugOutputter = new ConditionalTaskExecutor(
                 ( ) -> outputTraceInfo(),
                 ( ) -> outputTraceInfo(),
-                new ConditionalTaskExecutor.TimeDurationPredicate( 1, TimeUnit.MINUTES )
+                new ConditionalTaskExecutor.TimeDurationPredicate( 1, TimeDuration.Unit.MINUTES )
         );
         );
         status = STATUS.OPEN;
         status = STATUS.OPEN;
     }
     }

+ 2 - 2
server/src/main/java/password/pwm/svc/cluster/ClusterMachine.java

@@ -68,7 +68,7 @@ class ClusterMachine
 
 
         this.executorService = JavaHelper.makeSingleThreadExecutorService( pwmApplication, ClusterMachine.class );
         this.executorService = JavaHelper.makeSingleThreadExecutorService( pwmApplication, ClusterMachine.class );
 
 
-        final long intervalSeconds = settings.getHeartbeatInterval().getTotalSeconds();
+        final long intervalSeconds = settings.getHeartbeatInterval().as( TimeDuration.Unit.SECONDS );
 
 
         this.executorService.scheduleAtFixedRate(
         this.executorService.scheduleAtFixedRate(
                 new HeartbeatProcess(),
                 new HeartbeatProcess(),
@@ -80,7 +80,7 @@ class ClusterMachine
 
 
     public void close( )
     public void close( )
     {
     {
-        JavaHelper.closeAndWaitExecutor( executorService, new TimeDuration( 1, TimeUnit.SECONDS ) );
+        JavaHelper.closeAndWaitExecutor( executorService, TimeDuration.SECOND );
     }
     }
 
 
 
 

+ 6 - 8
server/src/main/java/password/pwm/svc/cluster/ClusterSettings.java

@@ -29,8 +29,6 @@ import password.pwm.AppProperty;
 import password.pwm.config.Configuration;
 import password.pwm.config.Configuration;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.java.TimeDuration;
 
 
-import java.util.concurrent.TimeUnit;
-
 @Value
 @Value
 @AllArgsConstructor( access = AccessLevel.PRIVATE )
 @AllArgsConstructor( access = AccessLevel.PRIVATE )
 class ClusterSettings
 class ClusterSettings
@@ -42,18 +40,18 @@ class ClusterSettings
     static ClusterSettings fromConfigForDB( final Configuration configuration )
     static ClusterSettings fromConfigForDB( final Configuration configuration )
     {
     {
         return new ClusterSettings(
         return new ClusterSettings(
-                new TimeDuration( Integer.parseInt( configuration.readAppProperty( AppProperty.CLUSTER_DB_HEARTBEAT_SECONDS ) ), TimeUnit.SECONDS ),
-                new TimeDuration( Integer.parseInt( configuration.readAppProperty( AppProperty.CLUSTER_DB_NODE_TIMEOUT_SECONDS ) ), TimeUnit.SECONDS ),
-                new TimeDuration( Integer.parseInt( configuration.readAppProperty( AppProperty.CLUSTER_DB_NODE_PURGE_SECONDS ) ), TimeUnit.SECONDS )
+                TimeDuration.of( Integer.parseInt( configuration.readAppProperty( AppProperty.CLUSTER_DB_HEARTBEAT_SECONDS ) ), TimeDuration.Unit.SECONDS ),
+                TimeDuration.of( Integer.parseInt( configuration.readAppProperty( AppProperty.CLUSTER_DB_NODE_TIMEOUT_SECONDS ) ), TimeDuration.Unit.SECONDS ),
+                TimeDuration.of( Integer.parseInt( configuration.readAppProperty( AppProperty.CLUSTER_DB_NODE_PURGE_SECONDS ) ), TimeDuration.Unit.SECONDS )
         );
         );
     }
     }
 
 
     static ClusterSettings fromConfigForLDAP( final Configuration configuration )
     static ClusterSettings fromConfigForLDAP( final Configuration configuration )
     {
     {
         return new ClusterSettings(
         return new ClusterSettings(
-                new TimeDuration( Integer.parseInt( configuration.readAppProperty( AppProperty.CLUSTER_LDAP_HEARTBEAT_SECONDS ) ), TimeUnit.SECONDS ),
-                new TimeDuration( Integer.parseInt( configuration.readAppProperty( AppProperty.CLUSTER_LDAP_NODE_TIMEOUT_SECONDS ) ), TimeUnit.SECONDS ),
-                new TimeDuration( Integer.parseInt( configuration.readAppProperty( AppProperty.CLUSTER_LDAP_NODE_PURGE_SECONDS ) ), TimeUnit.SECONDS )
+                TimeDuration.of( Integer.parseInt( configuration.readAppProperty( AppProperty.CLUSTER_LDAP_HEARTBEAT_SECONDS ) ), TimeDuration.Unit.SECONDS ),
+                TimeDuration.of( Integer.parseInt( configuration.readAppProperty( AppProperty.CLUSTER_LDAP_NODE_TIMEOUT_SECONDS ) ), TimeDuration.Unit.SECONDS ),
+                TimeDuration.of( Integer.parseInt( configuration.readAppProperty( AppProperty.CLUSTER_LDAP_NODE_PURGE_SECONDS ) ), TimeDuration.Unit.SECONDS )
         );
         );
     }
     }
 }
 }

+ 5 - 3
server/src/main/java/password/pwm/svc/email/EmailService.java

@@ -64,7 +64,6 @@ import java.util.Map;
 import java.util.Optional;
 import java.util.Optional;
 import java.util.Set;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicInteger;
 
 
 /**
 /**
@@ -117,8 +116,11 @@ public class EmailService implements PwmService
 
 
         final WorkQueueProcessor.Settings settings = WorkQueueProcessor.Settings.builder()
         final WorkQueueProcessor.Settings settings = WorkQueueProcessor.Settings.builder()
                 .maxEvents( Integer.parseInt( pwmApplication.getConfig().readAppProperty( AppProperty.QUEUE_EMAIL_MAX_COUNT ) ) )
                 .maxEvents( Integer.parseInt( pwmApplication.getConfig().readAppProperty( AppProperty.QUEUE_EMAIL_MAX_COUNT ) ) )
-                .retryDiscardAge( new TimeDuration( pwmApplication.getConfig().readSettingAsLong( PwmSetting.EMAIL_MAX_QUEUE_AGE ), TimeUnit.SECONDS ) )
-                .retryInterval( new TimeDuration( Long.parseLong( pwmApplication.getConfig().readAppProperty( AppProperty.QUEUE_EMAIL_RETRY_TIMEOUT_MS ) ) ) )
+                .retryDiscardAge( TimeDuration.of( pwmApplication.getConfig().readSettingAsLong( PwmSetting.EMAIL_MAX_QUEUE_AGE ), TimeDuration.Unit.SECONDS ) )
+                .retryInterval( TimeDuration.of(
+                        Long.parseLong( pwmApplication.getConfig().readAppProperty( AppProperty.QUEUE_EMAIL_RETRY_TIMEOUT_MS ) ),
+                        TimeDuration.Unit.MILLISECONDS )
+                )
                 .preThreads( Integer.parseInt( pwmApplication.getConfig().readAppProperty( AppProperty.QUEUE_EMAIL_MAX_THREADS ) ) )
                 .preThreads( Integer.parseInt( pwmApplication.getConfig().readAppProperty( AppProperty.QUEUE_EMAIL_MAX_THREADS ) ) )
                 .build();
                 .build();
         final LocalDBStoredQueue localDBStoredQueue = LocalDBStoredQueue.createLocalDBStoredQueue( pwmApplication, pwmApplication.getLocalDB(), LocalDB.DB.EMAIL_QUEUE );
         final LocalDBStoredQueue localDBStoredQueue = LocalDBStoredQueue.createLocalDBStoredQueue( pwmApplication, pwmApplication.getLocalDB(), LocalDB.DB.EMAIL_QUEUE );

+ 1 - 1
server/src/main/java/password/pwm/svc/event/AuditService.java

@@ -169,7 +169,7 @@ public class AuditService implements PwmService
             serviceInfo = new ServiceInfoBean( Collections.singletonList( storageMethodUsed ) );
             serviceInfo = new ServiceInfoBean( Collections.singletonList( storageMethodUsed ) );
         }
         }
         {
         {
-            final TimeDuration maxRecordAge = new TimeDuration( pwmApplication.getConfig().readSettingAsLong( PwmSetting.EVENTS_AUDIT_MAX_AGE ) * 1000 );
+            final TimeDuration maxRecordAge = TimeDuration.of( pwmApplication.getConfig().readSettingAsLong( PwmSetting.EVENTS_AUDIT_MAX_AGE ), TimeDuration.Unit.SECONDS );
             final long maxRecords = pwmApplication.getConfig().readSettingAsLong( PwmSetting.EVENTS_AUDIT_MAX_EVENTS );
             final long maxRecords = pwmApplication.getConfig().readSettingAsLong( PwmSetting.EVENTS_AUDIT_MAX_EVENTS );
             final AuditVault.Settings settings = new AuditVault.Settings(
             final AuditVault.Settings settings = new AuditVault.Settings(
                     maxRecords,
                     maxRecords,

+ 1 - 1
server/src/main/java/password/pwm/svc/event/LocalDbAuditVault.java

@@ -227,7 +227,7 @@ public class LocalDbAuditVault implements AuditVault
         // keep transaction duration around 100ms if possible.
         // keep transaction duration around 100ms if possible.
         final TransactionSizeCalculator transactionSizeCalculator = new TransactionSizeCalculator(
         final TransactionSizeCalculator transactionSizeCalculator = new TransactionSizeCalculator(
                 new TransactionSizeCalculator.SettingsBuilder()
                 new TransactionSizeCalculator.SettingsBuilder()
-                        .setDurationGoal( new TimeDuration( 101, TimeUnit.MILLISECONDS ) )
+                        .setDurationGoal( TimeDuration.of( 101, TimeDuration.Unit.MILLISECONDS ) )
                         .setMaxTransactions( 5003 )
                         .setMaxTransactions( 5003 )
                         .setMinTransactions( 3 )
                         .setMinTransactions( 3 )
                         .createSettings()
                         .createSettings()

+ 2 - 2
server/src/main/java/password/pwm/svc/event/SyslogAuditService.java

@@ -140,8 +140,8 @@ public class SyslogAuditService
 
 
         final WorkQueueProcessor.Settings settings = WorkQueueProcessor.Settings.builder()
         final WorkQueueProcessor.Settings settings = WorkQueueProcessor.Settings.builder()
                 .maxEvents( Integer.parseInt( configuration.readAppProperty( AppProperty.QUEUE_SYSLOG_MAX_COUNT ) ) )
                 .maxEvents( Integer.parseInt( configuration.readAppProperty( AppProperty.QUEUE_SYSLOG_MAX_COUNT ) ) )
-                .retryDiscardAge( new TimeDuration( Long.parseLong( configuration.readAppProperty( AppProperty.QUEUE_SYSLOG_MAX_AGE_MS ) ) ) )
-                .retryInterval( new TimeDuration( Long.parseLong( configuration.readAppProperty( AppProperty.QUEUE_SYSLOG_RETRY_TIMEOUT_MS ) ) ) )
+                .retryDiscardAge( TimeDuration.of( Long.parseLong( configuration.readAppProperty( AppProperty.QUEUE_SYSLOG_MAX_AGE_MS ) ), TimeDuration.Unit.MILLISECONDS ) )
+                .retryInterval( TimeDuration.of( Long.parseLong( configuration.readAppProperty( AppProperty.QUEUE_SYSLOG_RETRY_TIMEOUT_MS ) ), TimeDuration.Unit.MILLISECONDS ) )
                 .build();
                 .build();
 
 
         final LocalDBStoredQueue localDBStoredQueue = LocalDBStoredQueue.createLocalDBStoredQueue( pwmApplication, pwmApplication.getLocalDB(), LocalDB.DB.SYSLOG_QUEUE );
         final LocalDBStoredQueue localDBStoredQueue = LocalDBStoredQueue.createLocalDBStoredQueue( pwmApplication, pwmApplication.getLocalDB(), LocalDB.DB.SYSLOG_QUEUE );

+ 13 - 13
server/src/main/java/password/pwm/svc/intruder/IntruderManager.java

@@ -182,7 +182,7 @@ public class IntruderManager implements PwmService
                 {
                 {
                     try
                     try
                     {
                     {
-                        recordStore.cleanup( new TimeDuration( maxRecordAge ) );
+                        recordStore.cleanup( TimeDuration.of( maxRecordAge, TimeDuration.Unit.MILLISECONDS ) );
                     }
                     }
                     catch ( Exception e )
                     catch ( Exception e )
                     {
                     {
@@ -197,9 +197,9 @@ public class IntruderManager implements PwmService
             {
             {
                 final IntruderSettings settings = new IntruderSettings();
                 final IntruderSettings settings = new IntruderSettings();
                 settings.setCheckCount( ( int ) config.readSettingAsLong( PwmSetting.INTRUDER_USER_MAX_ATTEMPTS ) );
                 settings.setCheckCount( ( int ) config.readSettingAsLong( PwmSetting.INTRUDER_USER_MAX_ATTEMPTS ) );
-                settings.setResetDuration( new TimeDuration( 1000 * config.readSettingAsLong( PwmSetting.INTRUDER_USER_RESET_TIME ) ) );
-                settings.setCheckDuration( new TimeDuration( 1000 * config.readSettingAsLong( PwmSetting.INTRUDER_USER_CHECK_TIME ) ) );
-                if ( settings.getCheckCount() == 0 || settings.getCheckDuration().getTotalMilliseconds() == 0 || settings.getResetDuration().getTotalMilliseconds() == 0 )
+                settings.setResetDuration( TimeDuration.of( config.readSettingAsLong( PwmSetting.INTRUDER_USER_RESET_TIME ), TimeDuration.Unit.SECONDS ) );
+                settings.setCheckDuration( TimeDuration.of( config.readSettingAsLong( PwmSetting.INTRUDER_USER_CHECK_TIME ), TimeDuration.Unit.SECONDS ) );
+                if ( settings.getCheckCount() == 0 || settings.getCheckDuration().asMillis() == 0 || settings.getResetDuration().asMillis() == 0 )
                 {
                 {
                     LOGGER.info( "intruder user checking will remain disabled due to configuration settings" );
                     LOGGER.info( "intruder user checking will remain disabled due to configuration settings" );
                 }
                 }
@@ -212,9 +212,9 @@ public class IntruderManager implements PwmService
             {
             {
                 final IntruderSettings settings = new IntruderSettings();
                 final IntruderSettings settings = new IntruderSettings();
                 settings.setCheckCount( ( int ) config.readSettingAsLong( PwmSetting.INTRUDER_ATTRIBUTE_MAX_ATTEMPTS ) );
                 settings.setCheckCount( ( int ) config.readSettingAsLong( PwmSetting.INTRUDER_ATTRIBUTE_MAX_ATTEMPTS ) );
-                settings.setResetDuration( new TimeDuration( 1000 * config.readSettingAsLong( PwmSetting.INTRUDER_ATTRIBUTE_RESET_TIME ) ) );
-                settings.setCheckDuration( new TimeDuration( 1000 * config.readSettingAsLong( PwmSetting.INTRUDER_ATTRIBUTE_CHECK_TIME ) ) );
-                if ( settings.getCheckCount() == 0 || settings.getCheckDuration().getTotalMilliseconds() == 0 || settings.getResetDuration().getTotalMilliseconds() == 0 )
+                settings.setResetDuration( TimeDuration.of( config.readSettingAsLong( PwmSetting.INTRUDER_ATTRIBUTE_RESET_TIME ), TimeDuration.Unit.MILLISECONDS ) );
+                settings.setCheckDuration( TimeDuration.of( config.readSettingAsLong( PwmSetting.INTRUDER_ATTRIBUTE_CHECK_TIME ), TimeDuration.Unit.MILLISECONDS ) );
+                if ( settings.getCheckCount() == 0 || settings.getCheckDuration().asMillis() == 0 || settings.getResetDuration().asMillis() == 0 )
                 {
                 {
                     LOGGER.info( "intruder user checking will remain disabled due to configuration settings" );
                     LOGGER.info( "intruder user checking will remain disabled due to configuration settings" );
                 }
                 }
@@ -226,9 +226,9 @@ public class IntruderManager implements PwmService
             {
             {
                 final IntruderSettings settings = new IntruderSettings();
                 final IntruderSettings settings = new IntruderSettings();
                 settings.setCheckCount( ( int ) config.readSettingAsLong( PwmSetting.INTRUDER_TOKEN_DEST_MAX_ATTEMPTS ) );
                 settings.setCheckCount( ( int ) config.readSettingAsLong( PwmSetting.INTRUDER_TOKEN_DEST_MAX_ATTEMPTS ) );
-                settings.setResetDuration( new TimeDuration( 1000 * config.readSettingAsLong( PwmSetting.INTRUDER_TOKEN_DEST_RESET_TIME ) ) );
-                settings.setCheckDuration( new TimeDuration( 1000 * config.readSettingAsLong( PwmSetting.INTRUDER_TOKEN_DEST_CHECK_TIME ) ) );
-                if ( settings.getCheckCount() == 0 || settings.getCheckDuration().getTotalMilliseconds() == 0 || settings.getResetDuration().getTotalMilliseconds() == 0 )
+                settings.setResetDuration( TimeDuration.of( config.readSettingAsLong( PwmSetting.INTRUDER_TOKEN_DEST_RESET_TIME ), TimeDuration.Unit.SECONDS ) );
+                settings.setCheckDuration( TimeDuration.of( config.readSettingAsLong( PwmSetting.INTRUDER_TOKEN_DEST_CHECK_TIME ), TimeDuration.Unit.SECONDS ) );
+                if ( settings.getCheckCount() == 0 || settings.getCheckDuration().asMillis() == 0 || settings.getResetDuration().asMillis() == 0 )
                 {
                 {
                     LOGGER.info( "intruder user checking will remain disabled due to configuration settings" );
                     LOGGER.info( "intruder user checking will remain disabled due to configuration settings" );
                 }
                 }
@@ -240,9 +240,9 @@ public class IntruderManager implements PwmService
             {
             {
                 final IntruderSettings settings = new IntruderSettings();
                 final IntruderSettings settings = new IntruderSettings();
                 settings.setCheckCount( ( int ) config.readSettingAsLong( PwmSetting.INTRUDER_ADDRESS_MAX_ATTEMPTS ) );
                 settings.setCheckCount( ( int ) config.readSettingAsLong( PwmSetting.INTRUDER_ADDRESS_MAX_ATTEMPTS ) );
-                settings.setResetDuration( new TimeDuration( 1000 * config.readSettingAsLong( PwmSetting.INTRUDER_ADDRESS_RESET_TIME ) ) );
-                settings.setCheckDuration( new TimeDuration( 1000 * config.readSettingAsLong( PwmSetting.INTRUDER_ADDRESS_CHECK_TIME ) ) );
-                if ( settings.getCheckCount() == 0 || settings.getCheckDuration().getTotalMilliseconds() == 0 || settings.getResetDuration().getTotalMilliseconds() == 0 )
+                settings.setResetDuration( TimeDuration.of( config.readSettingAsLong( PwmSetting.INTRUDER_ADDRESS_RESET_TIME ), TimeDuration.Unit.SECONDS ) );
+                settings.setCheckDuration( TimeDuration.of( config.readSettingAsLong( PwmSetting.INTRUDER_ADDRESS_CHECK_TIME ), TimeDuration.Unit.SECONDS ) );
+                if ( settings.getCheckCount() == 0 || settings.getCheckDuration().asMillis() == 0 || settings.getResetDuration().asMillis() == 0 )
                 {
                 {
                     LOGGER.info( "intruder address checking will remain disabled due to configuration settings" );
                     LOGGER.info( "intruder address checking will remain disabled due to configuration settings" );
                 }
                 }

+ 6 - 7
server/src/main/java/password/pwm/svc/pwnotify/PwNotifyEngine.java

@@ -59,7 +59,6 @@ import java.util.Collection;
 import java.util.Iterator;
 import java.util.Iterator;
 import java.util.List;
 import java.util.List;
 import java.util.Locale;
 import java.util.Locale;
-import java.util.concurrent.TimeUnit;
 
 
 public class PwNotifyEngine
 public class PwNotifyEngine
 {
 {
@@ -75,10 +74,10 @@ public class PwNotifyEngine
 
 
     private final ConditionalTaskExecutor debugOutputTask = new ConditionalTaskExecutor(
     private final ConditionalTaskExecutor debugOutputTask = new ConditionalTaskExecutor(
             this::periodicDebugOutput,
             this::periodicDebugOutput,
-            new ConditionalTaskExecutor.TimeDurationPredicate( 1, TimeUnit.MINUTES )
+            new ConditionalTaskExecutor.TimeDurationPredicate( 1, TimeDuration.Unit.MINUTES )
     );
     );
 
 
-    private EventRateMeter eventRateMeter = new EventRateMeter( new TimeDuration( 5, TimeUnit.MINUTES ) );
+    private EventRateMeter eventRateMeter = new EventRateMeter( TimeDuration.of( 5, TimeDuration.Unit.MINUTES ) );
 
 
     private int examinedCount = 0;
     private int examinedCount = 0;
     private int noticeCount = 0;
     private int noticeCount = 0;
@@ -184,9 +183,9 @@ public class PwNotifyEngine
                 noticeCount += processBatch( batch );
                 noticeCount += processBatch( batch );
                 eventRateMeter.markEvents( batchSize );
                 eventRateMeter.markEvents( batchSize );
                 final TimeDuration batchTime = TimeDuration.fromCurrent( startBatch );
                 final TimeDuration batchTime = TimeDuration.fromCurrent( startBatch );
-                final TimeDuration pauseTime = new TimeDuration(
-                        settings.getBatchTimeMultiplier().multiply( new BigDecimal( batchTime.getTotalMilliseconds() ) ).longValue(),
-                        TimeUnit.MILLISECONDS );
+                final TimeDuration pauseTime = TimeDuration.of(
+                        settings.getBatchTimeMultiplier().multiply( new BigDecimal( batchTime.asMillis() ) ).longValue(),
+                        TimeDuration.Unit.MILLISECONDS );
                 pauseTime.pause();
                 pauseTime.pause();
 
 
                 debugOutputTask.conditionallyExecuteTask();
                 debugOutputTask.conditionallyExecuteTask();
@@ -266,7 +265,7 @@ public class PwNotifyEngine
             final Instant passwordExpirationTime
             final Instant passwordExpirationTime
     )
     )
     {
     {
-        final long maxSecondsAfterExpiration = TimeDuration.DAY.getTotalSeconds();
+        final long maxSecondsAfterExpiration = TimeDuration.DAY.as( TimeDuration.Unit.SECONDS );
         int nextDayInterval = -1;
         int nextDayInterval = -1;
         for ( final int configuredDayInterval : settings.getNotificationIntervals() )
         for ( final int configuredDayInterval : settings.getNotificationIntervals() )
         {
         {

+ 3 - 3
server/src/main/java/password/pwm/svc/pwnotify/PwNotifyService.java

@@ -163,14 +163,14 @@ public class PwNotifyService implements PwmService
             }
             }
 
 
             // more than 24hr ago.
             // more than 24hr ago.
-            if ( Duration.between( Instant.now(), storedJobState.getLastCompletion() ).abs().getSeconds() > settings.getMaximumSkipWindow().getTotalSeconds() )
+            if ( Duration.between( Instant.now(), storedJobState.getLastCompletion() ).abs().getSeconds() > settings.getMaximumSkipWindow().as( TimeDuration.Unit.SECONDS ) )
             {
             {
                 return Instant.now();
                 return Instant.now();
             }
             }
         }
         }
 
 
         final Instant nextZuluZeroTime = JavaHelper.nextZuluZeroTime();
         final Instant nextZuluZeroTime = JavaHelper.nextZuluZeroTime();
-        final Instant adjustedNextZuluZeroTime = nextZuluZeroTime.plus( settings.getZuluOffset().getTotalSeconds(), ChronoUnit.SECONDS );
+        final Instant adjustedNextZuluZeroTime = nextZuluZeroTime.plus( settings.getZuluOffset().as( TimeDuration.Unit.SECONDS ), ChronoUnit.SECONDS );
         final Instant previousAdjustedZuluZeroTime = adjustedNextZuluZeroTime.minus( 1, ChronoUnit.DAYS );
         final Instant previousAdjustedZuluZeroTime = adjustedNextZuluZeroTime.minus( 1, ChronoUnit.DAYS );
 
 
         if ( previousAdjustedZuluZeroTime.isAfter( Instant.now() ) )
         if ( previousAdjustedZuluZeroTime.isAfter( Instant.now() ) )
@@ -184,7 +184,7 @@ public class PwNotifyService implements PwmService
     public void close( )
     public void close( )
     {
     {
         status = STATUS.CLOSED;
         status = STATUS.CLOSED;
-        JavaHelper.closeAndWaitExecutor( executorService, new TimeDuration( 5, TimeUnit.SECONDS ) );
+        JavaHelper.closeAndWaitExecutor( executorService, TimeDuration.of( 5, TimeDuration.Unit.SECONDS ) );
     }
     }
 
 
     @Override
     @Override

+ 3 - 4
server/src/main/java/password/pwm/svc/pwnotify/PwNotifySettings.java

@@ -34,7 +34,6 @@ import java.math.BigDecimal;
 import java.util.ArrayList;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Collections;
 import java.util.List;
 import java.util.List;
-import java.util.concurrent.TimeUnit;
 
 
 @Value
 @Value
 @Builder
 @Builder
@@ -61,12 +60,12 @@ public class PwNotifySettings implements Serializable
             builder.notificationIntervals( Collections.unmodifiableList( timeDurations ) );
             builder.notificationIntervals( Collections.unmodifiableList( timeDurations ) );
         }
         }
 
 
-        builder.zuluOffset( new TimeDuration( configuration.readSettingAsLong( PwmSetting.PW_EXPY_NOTIFY_JOB_OFFSET ), TimeUnit.SECONDS ) );
+        builder.zuluOffset( TimeDuration.of( configuration.readSettingAsLong( PwmSetting.PW_EXPY_NOTIFY_JOB_OFFSET ), TimeDuration.Unit.SECONDS ) );
         builder.batchCount( Integer.parseInt( configuration.readAppProperty( AppProperty.PWNOTIFY_BATCH_COUNT ) ) );
         builder.batchCount( Integer.parseInt( configuration.readAppProperty( AppProperty.PWNOTIFY_BATCH_COUNT ) ) );
         builder.maxLdapSearchSize( Integer.parseInt( configuration.readAppProperty( AppProperty.PWNOTIFY_MAX_LDAP_SEARCH_SIZE ) ) );
         builder.maxLdapSearchSize( Integer.parseInt( configuration.readAppProperty( AppProperty.PWNOTIFY_MAX_LDAP_SEARCH_SIZE ) ) );
         builder.batchTimeMultiplier( new BigDecimal( configuration.readAppProperty( AppProperty.PWNOTIFY_BATCH_DELAY_TIME_MULTIPLIER ) ) );
         builder.batchTimeMultiplier( new BigDecimal( configuration.readAppProperty( AppProperty.PWNOTIFY_BATCH_DELAY_TIME_MULTIPLIER ) ) );
-        builder.maximumSkipWindow( new TimeDuration(
-                Long.parseLong( configuration.readAppProperty( AppProperty.PWNOTIFY_MAX_SKIP_RERUN_WINDOW_SECONDS ) ), TimeUnit.SECONDS ) );
+        builder.maximumSkipWindow( TimeDuration.of(
+                Long.parseLong( configuration.readAppProperty( AppProperty.PWNOTIFY_MAX_SKIP_RERUN_WINDOW_SECONDS ) ), TimeDuration.Unit.SECONDS ) );
         return builder.build();
         return builder.build();
     }
     }
 }
 }

+ 5 - 5
server/src/main/java/password/pwm/svc/report/ReportService.java

@@ -562,12 +562,12 @@ public class ReportService implements PwmService
                             reportStatus.setCount( reportStatus.getCount() + 1 );
                             reportStatus.setCount( reportStatus.getCount() + 1 );
                             eventRateMeter.markEvents( 1 );
                             eventRateMeter.markEvents( 1 );
                             final TimeDuration totalUpdateTime = TimeDuration.fromCurrent( startUpdateTime );
                             final TimeDuration totalUpdateTime = TimeDuration.fromCurrent( startUpdateTime );
-                            avgTracker.addSample( totalUpdateTime.getTotalMilliseconds() );
+                            avgTracker.addSample( totalUpdateTime.asMillis() );
 
 
                             try
                             try
                             {
                             {
                                 updateTimeLock.lock();
                                 updateTimeLock.lock();
-                                final TimeDuration scaledTime = new TimeDuration( totalUpdateTime.getTotalMilliseconds() / threadCount );
+                                final TimeDuration scaledTime = TimeDuration.of( totalUpdateTime.asMillis() / threadCount, TimeDuration.Unit.MILLISECONDS );
                                 reportStatus.setJobDuration( reportStatus.getJobDuration().add( scaledTime ) );
                                 reportStatus.setJobDuration( reportStatus.getJobDuration().add( scaledTime ) );
                             }
                             }
                             finally
                             finally
@@ -691,7 +691,7 @@ public class ReportService implements PwmService
 
 
                     examinedRecords++;
                     examinedRecords++;
 
 
-                    if ( TimeDuration.fromCurrent( lastLogOutputTime ).isLongerThan( 30, TimeUnit.SECONDS ) )
+                    if ( TimeDuration.fromCurrent( lastLogOutputTime ).isLongerThan( 30, TimeDuration.Unit.SECONDS ) )
                     {
                     {
                         final TimeDuration progressDuration = TimeDuration.fromCurrent( startTime );
                         final TimeDuration progressDuration = TimeDuration.fromCurrent( startTime );
                         LOGGER.trace( SessionLabel.REPORTING_SESSION_LABEL,
                         LOGGER.trace( SessionLabel.REPORTING_SESSION_LABEL,
@@ -738,8 +738,8 @@ public class ReportService implements PwmService
             if ( reportingEnabled )
             if ( reportingEnabled )
             {
             {
                 final Instant nextZuluZeroTime = JavaHelper.nextZuluZeroTime();
                 final Instant nextZuluZeroTime = JavaHelper.nextZuluZeroTime();
-                final long secondsUntilNextDredge = settings.getJobOffsetSeconds() + TimeDuration.fromCurrent( nextZuluZeroTime ).getTotalSeconds();
-                executorService.scheduleAtFixedRate( new DailyJobExecuteTask(), secondsUntilNextDredge, TimeDuration.DAY.getTotalSeconds(), TimeUnit.SECONDS );
+                final long secondsUntilNextDredge = settings.getJobOffsetSeconds() + TimeDuration.fromCurrent( nextZuluZeroTime ).as( TimeDuration.Unit.SECONDS );
+                executorService.scheduleAtFixedRate( new DailyJobExecuteTask(), secondsUntilNextDredge, TimeDuration.DAY.as( TimeDuration.Unit.SECONDS ), TimeUnit.SECONDS );
                 LOGGER.debug( "scheduled daily execution, next task will be at " + nextZuluZeroTime.toString() );
                 LOGGER.debug( "scheduled daily execution, next task will be at " + nextZuluZeroTime.toString() );
             }
             }
             executorService.submit( new RolloverTask() );
             executorService.submit( new RolloverTask() );

+ 2 - 2
server/src/main/java/password/pwm/svc/report/ReportSettings.java

@@ -41,7 +41,7 @@ class ReportSettings implements Serializable
 {
 {
     private static final PwmLogger LOGGER = PwmLogger.forClass( ReportSettings.class );
     private static final PwmLogger LOGGER = PwmLogger.forClass( ReportSettings.class );
 
 
-    private TimeDuration maxCacheAge = new TimeDuration( TimeDuration.DAY.getTotalMilliseconds() * 90 );
+    private TimeDuration maxCacheAge = TimeDuration.of( TimeDuration.DAY.asMillis() * 90, TimeDuration.Unit.MILLISECONDS );
     private String searchFilter = null;
     private String searchFilter = null;
     private int jobOffsetSeconds;
     private int jobOffsetSeconds;
     private int maxSearchSize = 100 * 1000;
     private int maxSearchSize = 100 * 1000;
@@ -59,7 +59,7 @@ class ReportSettings implements Serializable
     public static ReportSettings readSettingsFromConfig( final Configuration config )
     public static ReportSettings readSettingsFromConfig( final Configuration config )
     {
     {
         final ReportSettings settings = new ReportSettings();
         final ReportSettings settings = new ReportSettings();
-        settings.maxCacheAge = new TimeDuration( config.readSettingAsLong( PwmSetting.REPORTING_MAX_CACHE_AGE ) * 1000 );
+        settings.maxCacheAge = TimeDuration.of( config.readSettingAsLong( PwmSetting.REPORTING_MAX_CACHE_AGE ), TimeDuration.Unit.SECONDS );
         settings.searchFilter = config.readSettingAsString( PwmSetting.REPORTING_SEARCH_FILTER );
         settings.searchFilter = config.readSettingAsString( PwmSetting.REPORTING_SEARCH_FILTER );
         settings.maxSearchSize = ( int ) config.readSettingAsLong( PwmSetting.REPORTING_MAX_QUERY_SIZE );
         settings.maxSearchSize = ( int ) config.readSettingAsLong( PwmSetting.REPORTING_MAX_QUERY_SIZE );
 
 

+ 2 - 2
server/src/main/java/password/pwm/svc/report/ReportSummaryData.java

@@ -46,7 +46,7 @@ import java.util.stream.Collectors;
 
 
 public class ReportSummaryData
 public class ReportSummaryData
 {
 {
-    private static final long MS_DAY = TimeDuration.DAY.getTotalMilliseconds();
+    private static final long MS_DAY = TimeDuration.DAY.asMillis();
     private static final BigInteger TWO = new BigInteger( "2" );
     private static final BigInteger TWO = new BigInteger( "2" );
 
 
     private Instant meanCacheTime;
     private Instant meanCacheTime;
@@ -339,7 +339,7 @@ public class ReportSummaryData
             return 0;
             return 0;
         }
         }
 
 
-        final TimeDuration timeBoundary = new TimeDuration( 0, timeWindow );
+        final TimeDuration timeBoundary = TimeDuration.of( timeWindow, TimeDuration.Unit.MILLISECONDS );
         final TimeDuration eventDifference = TimeDuration.fromCurrent( eventDate );
         final TimeDuration eventDifference = TimeDuration.fromCurrent( eventDate );
 
 
         if ( timeWindow >= 0 && eventDate.isAfter( Instant.now() ) && eventDifference.isShorterThan( timeBoundary ) )
         if ( timeWindow >= 0 && eventDate.isAfter( Instant.now() ) && eventDifference.isShorterThan( timeBoundary ) )

+ 2 - 2
server/src/main/java/password/pwm/svc/stats/EventRateMeter.java

@@ -47,7 +47,7 @@ public class EventRateMeter implements Serializable
 
 
     public synchronized void reset( )
     public synchronized void reset( )
     {
     {
-        movingAverage = new MovingAverage( maxDuration.getTotalMilliseconds() );
+        movingAverage = new MovingAverage( maxDuration.asMillis() );
         remainder = 0;
         remainder = 0;
     }
     }
 
 
@@ -114,7 +114,7 @@ public class EventRateMeter implements Serializable
 
 
         public MovingAverage( final TimeDuration timeDuration )
         public MovingAverage( final TimeDuration timeDuration )
         {
         {
-            this.windowMillis = timeDuration.getTotalMilliseconds();
+            this.windowMillis = timeDuration.asMillis();
         }
         }
 
 
         /**
         /**

+ 4 - 4
server/src/main/java/password/pwm/svc/stats/StatisticsManager.java

@@ -64,7 +64,7 @@ public class StatisticsManager implements PwmService
     private static final PwmLogger LOGGER = PwmLogger.forClass( StatisticsManager.class );
     private static final PwmLogger LOGGER = PwmLogger.forClass( StatisticsManager.class );
 
 
     // 1 minutes
     // 1 minutes
-    private static final TimeDuration DB_WRITE_FREQUENCY = new TimeDuration( 1, TimeUnit.MINUTES );
+    private static final TimeDuration DB_WRITE_FREQUENCY = TimeDuration.MINUTE;
 
 
     private static final String DB_KEY_VERSION = "STATS_VERSION";
     private static final String DB_KEY_VERSION = "STATS_VERSION";
     private static final String DB_KEY_CUMULATIVE = "CUMULATIVE";
     private static final String DB_KEY_CUMULATIVE = "CUMULATIVE";
@@ -332,9 +332,9 @@ public class StatisticsManager implements PwmService
         {
         {
             // setup a timer to roll over at 0 Zula and one to write current stats every 10 seconds
             // setup a timer to roll over at 0 Zula and one to write current stats every 10 seconds
             executorService = JavaHelper.makeSingleThreadExecutorService( pwmApplication, this.getClass() );
             executorService = JavaHelper.makeSingleThreadExecutorService( pwmApplication, this.getClass() );
-            executorService.scheduleAtFixedRate( new FlushTask(), 10 * 1000, DB_WRITE_FREQUENCY.getTotalMilliseconds(), TimeUnit.MILLISECONDS );
+            executorService.scheduleAtFixedRate( new FlushTask(), 10 * 1000, DB_WRITE_FREQUENCY.asMillis(), TimeUnit.MICROSECONDS );
             final TimeDuration delayTillNextZulu = TimeDuration.fromCurrent( JavaHelper.nextZuluZeroTime() );
             final TimeDuration delayTillNextZulu = TimeDuration.fromCurrent( JavaHelper.nextZuluZeroTime() );
-            executorService.scheduleAtFixedRate( new NightlyTask(), delayTillNextZulu.getTotalMilliseconds(), TimeUnit.DAYS.toMillis( 1 ), TimeUnit.MILLISECONDS );
+            executorService.scheduleAtFixedRate( new NightlyTask(), delayTillNextZulu.asMillis(), TimeUnit.DAYS.toMillis( 1 ), TimeUnit.MILLISECONDS );
         }
         }
 
 
         status = STATUS.OPEN;
         status = STATUS.OPEN;
@@ -409,7 +409,7 @@ public class StatisticsManager implements PwmService
             LOGGER.error( "unexpected error closing: " + e.getMessage() );
             LOGGER.error( "unexpected error closing: " + e.getMessage() );
         }
         }
 
 
-        JavaHelper.closeAndWaitExecutor( executorService, new TimeDuration( 3, TimeUnit.SECONDS ) );
+        JavaHelper.closeAndWaitExecutor( executorService, TimeDuration.of( 3, TimeDuration.Unit.SECONDS ) );
 
 
         status = STATUS.CLOSED;
         status = STATUS.CLOSED;
     }
     }

+ 2 - 2
server/src/main/java/password/pwm/svc/telemetry/TelemetryService.java

@@ -217,7 +217,7 @@ public class TelemetryService implements PwmService
         final TimeDuration durationUntilNextPublish = durationUntilNextPublish();
         final TimeDuration durationUntilNextPublish = durationUntilNextPublish();
         executorService.schedule(
         executorService.schedule(
                 new PublishJob(),
                 new PublishJob(),
-                durationUntilNextPublish.getTotalMilliseconds(),
+                durationUntilNextPublish.asMillis(),
                 TimeUnit.MILLISECONDS );
                 TimeUnit.MILLISECONDS );
         LOGGER.trace( SessionLabel.TELEMETRY_SESSION_LABEL, "next publish time: " + durationUntilNextPublish().asCompactString() );
         LOGGER.trace( SessionLabel.TELEMETRY_SESSION_LABEL, "next publish time: " + durationUntilNextPublish().asCompactString() );
     }
     }
@@ -370,7 +370,7 @@ public class TelemetryService implements PwmService
         {
         {
             return Settings.builder()
             return Settings.builder()
                     .minimumAuthentications( Integer.parseInt( config.readAppProperty( AppProperty.TELEMETRY_MIN_AUTHENTICATIONS ) ) )
                     .minimumAuthentications( Integer.parseInt( config.readAppProperty( AppProperty.TELEMETRY_MIN_AUTHENTICATIONS ) ) )
-                    .publishFrequency( new TimeDuration( Integer.parseInt( config.readAppProperty( AppProperty.TELEMETRY_SEND_FREQUENCY_SECONDS ) ), TimeUnit.SECONDS ) )
+                    .publishFrequency( TimeDuration.of( Integer.parseInt( config.readAppProperty( AppProperty.TELEMETRY_SEND_FREQUENCY_SECONDS ) ), TimeDuration.Unit.SECONDS ) )
                     .senderImplementation( config.readAppProperty( AppProperty.TELEMETRY_SENDER_IMPLEMENTATION ) )
                     .senderImplementation( config.readAppProperty( AppProperty.TELEMETRY_SENDER_IMPLEMENTATION ) )
                     .senderSettings( config.readAppProperty( AppProperty.TELEMETRY_SENDER_SETTINGS ) )
                     .senderSettings( config.readAppProperty( AppProperty.TELEMETRY_SENDER_SETTINGS ) )
                     .build();
                     .build();

+ 2 - 2
server/src/main/java/password/pwm/svc/token/TokenService.java

@@ -204,7 +204,7 @@ public class TokenService implements PwmService
 
 
         {
         {
             final int cleanerFrequencySeconds = Integer.parseInt( configuration.readAppProperty( AppProperty.TOKEN_CLEANER_INTERVAL_SECONDS ) );
             final int cleanerFrequencySeconds = Integer.parseInt( configuration.readAppProperty( AppProperty.TOKEN_CLEANER_INTERVAL_SECONDS ) );
-            final TimeDuration cleanerFrequency = new TimeDuration( cleanerFrequencySeconds, TimeUnit.SECONDS );
+            final TimeDuration cleanerFrequency = TimeDuration.of( cleanerFrequencySeconds, TimeDuration.Unit.SECONDS );
             executorService.scheduleAtFixedRate( cleanerTask, 10, cleanerFrequencySeconds, TimeUnit.SECONDS );
             executorService.scheduleAtFixedRate( cleanerTask, 10, cleanerFrequencySeconds, TimeUnit.SECONDS );
             LOGGER.trace( "token cleanup will occur every " + cleanerFrequency.asCompactString() );
             LOGGER.trace( "token cleanup will occur every " + cleanerFrequency.asCompactString() );
         }
         }
@@ -787,6 +787,6 @@ public class TokenService implements PwmService
             maxValue = Math.max( maxValue, newUserProfile.readSettingAsLong( PwmSetting.NEWUSER_TOKEN_LIFETIME_EMAIL ) );
             maxValue = Math.max( maxValue, newUserProfile.readSettingAsLong( PwmSetting.NEWUSER_TOKEN_LIFETIME_EMAIL ) );
             maxValue = Math.max( maxValue, newUserProfile.readSettingAsLong( PwmSetting.NEWUSER_TOKEN_LIFETIME_SMS ) );
             maxValue = Math.max( maxValue, newUserProfile.readSettingAsLong( PwmSetting.NEWUSER_TOKEN_LIFETIME_SMS ) );
         }
         }
-        return new TimeDuration( maxValue, TimeUnit.SECONDS );
+        return TimeDuration.of( maxValue, TimeDuration.Unit.SECONDS );
     }
     }
 }
 }

+ 1 - 2
server/src/main/java/password/pwm/svc/token/TokenUtil.java

@@ -53,7 +53,6 @@ import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.List;
 import java.util.Locale;
 import java.util.Locale;
 import java.util.Map;
 import java.util.Map;
-import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 import java.util.stream.Collectors;
 
 
 public class TokenUtil
 public class TokenUtil
@@ -252,7 +251,7 @@ public class TokenUtil
         {
         {
 
 
             final TimeDuration tokenLifetime = tokenInitAndSendRequest.getTokenLifetime() == null
             final TimeDuration tokenLifetime = tokenInitAndSendRequest.getTokenLifetime() == null
-                    ? new TimeDuration( config.readSettingAsLong( PwmSetting.TOKEN_LIFETIME ), TimeUnit.SECONDS )
+                    ? TimeDuration.of( config.readSettingAsLong( PwmSetting.TOKEN_LIFETIME ), TimeDuration.Unit.SECONDS )
                     : tokenInitAndSendRequest.getTokenLifetime();
                     : tokenInitAndSendRequest.getTokenLifetime();
 
 
             try
             try

+ 1 - 1
server/src/main/java/password/pwm/svc/wordlist/AbstractWordlist.java

@@ -471,7 +471,7 @@ abstract class AbstractWordlist implements Wordlist, PwmService
                 if ( autoImportError != null )
                 if ( autoImportError != null )
                 {
                 {
                     final int retrySeconds = Integer.parseInt( pwmApplication.getConfig().readAppProperty( AppProperty.APPLICATION_WORDLIST_RETRY_SECONDS ) );
                     final int retrySeconds = Integer.parseInt( pwmApplication.getConfig().readAppProperty( AppProperty.APPLICATION_WORDLIST_RETRY_SECONDS ) );
-                    logger.error( "auto-import of remote wordlist failed, will retry in " + ( new TimeDuration( retrySeconds, TimeUnit.SECONDS ).asCompactString() ) );
+                    logger.error( "auto-import of remote wordlist failed, will retry in " + ( TimeDuration.of( retrySeconds, TimeDuration.Unit.SECONDS ).asCompactString() ) );
                     executorService.schedule( ( ) ->
                     executorService.schedule( ( ) ->
                     {
                     {
                         try
                         try

+ 7 - 9
server/src/main/java/password/pwm/svc/wordlist/Populator.java

@@ -40,10 +40,8 @@ import java.io.InputStream;
 import java.text.DecimalFormat;
 import java.text.DecimalFormat;
 import java.text.NumberFormat;
 import java.text.NumberFormat;
 import java.time.Instant;
 import java.time.Instant;
-import java.util.Date;
 import java.util.Map;
 import java.util.Map;
 import java.util.TreeMap;
 import java.util.TreeMap;
-import java.util.concurrent.TimeUnit;
 
 
 /**
 /**
  * @author Jason D. Rivard
  * @author Jason D. Rivard
@@ -55,7 +53,7 @@ class Populator
     // words truncated to this length, prevents massive words if the input
     // words truncated to this length, prevents massive words if the input
     private static final int MAX_LINE_LENGTH = 64;
     private static final int MAX_LINE_LENGTH = 64;
 
 
-    private static final TimeDuration DEBUG_OUTPUT_FREQUENCY = new TimeDuration( 3, TimeUnit.MINUTES );
+    private static final TimeDuration DEBUG_OUTPUT_FREQUENCY = TimeDuration.of( 3, TimeDuration.Unit.MINUTES );
 
 
     // words tarting with this prefix are ignored.
     // words tarting with this prefix are ignored.
     private static final String COMMENT_PREFIX = "!#comment:";
     private static final String COMMENT_PREFIX = "!#comment:";
@@ -72,7 +70,7 @@ class Populator
     private PopulationStats perReportStats = new PopulationStats();
     private PopulationStats perReportStats = new PopulationStats();
     private TransactionSizeCalculator transactionCalculator = new TransactionSizeCalculator(
     private TransactionSizeCalculator transactionCalculator = new TransactionSizeCalculator(
             new TransactionSizeCalculator.SettingsBuilder()
             new TransactionSizeCalculator.SettingsBuilder()
-                    .setDurationGoal( new TimeDuration( 600, TimeUnit.MILLISECONDS ) )
+                    .setDurationGoal( TimeDuration.of( 600, TimeDuration.Unit.MILLISECONDS ) )
                     .setMinTransactions( 10 )
                     .setMinTransactions( 10 )
                     .setMaxTransactions( 350 * 1000 )
                     .setMaxTransactions( 350 * 1000 )
                     .createSettings()
                     .createSettings()
@@ -151,7 +149,7 @@ class Populator
             running = true;
             running = true;
             init();
             init();
 
 
-            long lastReportTime = System.currentTimeMillis() - ( long ) ( DEBUG_OUTPUT_FREQUENCY.getTotalMilliseconds() * 0.33 );
+            long lastReportTime = System.currentTimeMillis() - ( long ) ( DEBUG_OUTPUT_FREQUENCY.asMillis() * 0.33 );
 
 
             String line;
             String line;
 
 
@@ -164,7 +162,7 @@ class Populator
                 addLine( line );
                 addLine( line );
                 loopLines++;
                 loopLines++;
 
 
-                if ( TimeDuration.fromCurrent( lastReportTime ).isLongerThan( DEBUG_OUTPUT_FREQUENCY.getTotalMilliseconds() ) )
+                if ( TimeDuration.fromCurrent( lastReportTime ).isLongerThan( DEBUG_OUTPUT_FREQUENCY.asMillis() ) )
                 {
                 {
                     LOGGER.info( makeStatString() );
                     LOGGER.info( makeStatString() );
                     lastReportTime = System.currentTimeMillis();
                     lastReportTime = System.currentTimeMillis();
@@ -236,7 +234,7 @@ class Populator
             sb.append( "read " ).append( loopLines ).append( ", " );
             sb.append( "read " ).append( loopLines ).append( ", " );
             sb.append( "saved " );
             sb.append( "saved " );
             sb.append( bufferedWords.size() ).append( " words" );
             sb.append( bufferedWords.size() ).append( " words" );
-            sb.append( " (" ).append( new TimeDuration( commitTime ).asCompactString() ).append( ")" );
+            sb.append( " (" ).append( TimeDuration.of( commitTime, TimeDuration.Unit.MILLISECONDS ).asCompactString() ).append( ")" );
 
 
             LOGGER.trace( sb.toString() );
             LOGGER.trace( sb.toString() );
         }
         }
@@ -261,7 +259,7 @@ class Populator
         final StringBuilder sb = new StringBuilder();
         final StringBuilder sb = new StringBuilder();
         sb.append( rootWordlist.debugLabel );
         sb.append( rootWordlist.debugLabel );
         sb.append( " population complete, added " ).append( wordlistSize );
         sb.append( " population complete, added " ).append( wordlistSize );
-        sb.append( " total words in " ).append( new TimeDuration( overallStats.getElapsedSeconds() * 1000 ).asCompactString() );
+        sb.append( " total words in " ).append( TimeDuration.of( overallStats.getElapsedSeconds() * 1000, TimeDuration.Unit.MILLISECONDS ).asCompactString() );
         {
         {
             final StoredWordlistDataBean storedWordlistDataBean = StoredWordlistDataBean.builder()
             final StoredWordlistDataBean storedWordlistDataBean = StoredWordlistDataBean.builder()
                     .sha1hash( JavaHelper.binaryArrayToHex( checksumInputStream.closeAndFinalChecksum() ) )
                     .sha1hash( JavaHelper.binaryArrayToHex( checksumInputStream.closeAndFinalChecksum() ) )
@@ -281,7 +279,7 @@ class Populator
         abortFlag = true;
         abortFlag = true;
 
 
         final int maxWaitMs = 1000 * 30;
         final int maxWaitMs = 1000 * 30;
-        final Date startWaitTime = new Date();
+        final Instant startWaitTime = Instant.now();
         while ( isRunning() && TimeDuration.fromCurrent( startWaitTime ).isShorterThan( maxWaitMs ) )
         while ( isRunning() && TimeDuration.fromCurrent( startWaitTime ).isShorterThan( maxWaitMs ) )
         {
         {
             JavaHelper.pause( 1000 );
             JavaHelper.pause( 1000 );

+ 7 - 7
server/src/main/java/password/pwm/svc/wordlist/SharedHistoryManager.java

@@ -192,7 +192,7 @@ public class SharedHistoryManager implements PwmService
     private void init( final PwmApplication pwmApplication, final long maxAgeMs )
     private void init( final PwmApplication pwmApplication, final long maxAgeMs )
     {
     {
         status = STATUS.OPENING;
         status = STATUS.OPENING;
-        final long startTime = System.currentTimeMillis();
+        final Instant startTime = Instant.now();
 
 
         try
         try
         {
         {
@@ -232,9 +232,9 @@ public class SharedHistoryManager implements PwmService
             final int size = localDB.size( WORDS_DB );
             final int size = localDB.size( WORDS_DB );
             final StringBuilder sb = new StringBuilder();
             final StringBuilder sb = new StringBuilder();
             sb.append( "open with " ).append( size ).append( " words (" );
             sb.append( "open with " ).append( size ).append( " words (" );
-            sb.append( new TimeDuration( System.currentTimeMillis(), startTime ).asCompactString() ).append( ")" );
-            sb.append( ", maxAgeMs=" ).append( new TimeDuration( maxAgeMs ).asCompactString() );
-            sb.append( ", oldestEntry=" ).append( new TimeDuration( System.currentTimeMillis(), oldestEntry ).asCompactString() );
+            sb.append( TimeDuration.compactFromCurrent( startTime ) ).append( ")" );
+            sb.append( ", maxAgeMs=" ).append( TimeDuration.of( maxAgeMs, TimeDuration.Unit.MILLISECONDS ).asCompactString() );
+            sb.append( ", oldestEntry=" ).append( TimeDuration.fromCurrent( oldestEntry ).asCompactString() );
             LOGGER.info( sb.toString() );
             LOGGER.info( sb.toString() );
         }
         }
         catch ( LocalDBException e )
         catch ( LocalDBException e )
@@ -252,7 +252,7 @@ public class SharedHistoryManager implements PwmService
             long frequencyMs = maxAgeMs > MAX_CLEANER_FREQUENCY ? MAX_CLEANER_FREQUENCY : maxAgeMs;
             long frequencyMs = maxAgeMs > MAX_CLEANER_FREQUENCY ? MAX_CLEANER_FREQUENCY : maxAgeMs;
             frequencyMs = frequencyMs < MIN_CLEANER_FREQUENCY ? MIN_CLEANER_FREQUENCY : frequencyMs;
             frequencyMs = frequencyMs < MIN_CLEANER_FREQUENCY ? MIN_CLEANER_FREQUENCY : frequencyMs;
 
 
-            LOGGER.debug( "scheduling cleaner task to run once every " + new TimeDuration( frequencyMs ).asCompactString() );
+            LOGGER.debug( "scheduling cleaner task to run once every " + TimeDuration.of( frequencyMs, TimeDuration.Unit.MILLISECONDS ).asCompactString() );
             final String threadName = JavaHelper.makeThreadName( pwmApplication, this.getClass() ) + " timer";
             final String threadName = JavaHelper.makeThreadName( pwmApplication, this.getClass() ) + " timer";
             cleanerTimer = new Timer( threadName, true );
             cleanerTimer = new Timer( threadName, true );
             cleanerTimer.schedule( new CleanerTask(), 1000, frequencyMs );
             cleanerTimer.schedule( new CleanerTask(), 1000, frequencyMs );
@@ -293,7 +293,7 @@ public class SharedHistoryManager implements PwmService
             return;
             return;
         }
         }
 
 
-        final long startTime = System.currentTimeMillis();
+        final Instant startTime = Instant.now();
 
 
         try
         try
         {
         {
@@ -305,7 +305,7 @@ public class SharedHistoryManager implements PwmService
             {
             {
                 final StringBuilder logOutput = new StringBuilder();
                 final StringBuilder logOutput = new StringBuilder();
                 logOutput.append( preExisting ? "updated" : "added" ).append( " word" );
                 logOutput.append( preExisting ? "updated" : "added" ).append( " word" );
-                logOutput.append( " (" ).append( new TimeDuration( System.currentTimeMillis(), startTime ).asCompactString() ).append( ")" );
+                logOutput.append( " (" ).append( TimeDuration.compactFromCurrent( startTime ) ).append( ")" );
                 logOutput.append( " (" ).append( this.size() ).append( " total words)" );
                 logOutput.append( " (" ).append( this.size() ).append( " total words)" );
                 LOGGER.trace( logOutput.toString() );
                 LOGGER.trace( logOutput.toString() );
             }
             }

+ 4 - 4
server/src/main/java/password/pwm/util/ProgressInfo.java

@@ -57,7 +57,7 @@ public class ProgressInfo implements Serializable
 
 
     public TimeDuration elapsed( )
     public TimeDuration elapsed( )
     {
     {
-        return new TimeDuration( startTime, nowTime );
+        return TimeDuration.between( startTime, nowTime );
     }
     }
 
 
     public long itemsRemaining( )
     public long itemsRemaining( )
@@ -67,7 +67,7 @@ public class ProgressInfo implements Serializable
 
 
     public float itemsPerMs( )
     public float itemsPerMs( )
     {
     {
-        final long elapsedMs = elapsed().getTotalMilliseconds();
+        final long elapsedMs = elapsed().asMillis();
         if ( elapsedMs <= 0 )
         if ( elapsedMs <= 0 )
         {
         {
             return 0;
             return 0;
@@ -84,13 +84,13 @@ public class ProgressInfo implements Serializable
             return TimeDuration.ZERO;
             return TimeDuration.ZERO;
         }
         }
         final BigDecimal remainingMs = new BigDecimal( itemsRemaining() ).divide( new BigDecimal( itemsPerMs ), MathContext.DECIMAL32 );
         final BigDecimal remainingMs = new BigDecimal( itemsRemaining() ).divide( new BigDecimal( itemsPerMs ), MathContext.DECIMAL32 );
-        return new TimeDuration( remainingMs.longValue() );
+        return TimeDuration.of( remainingMs.longValue(), TimeDuration.Unit.MILLISECONDS );
     }
     }
 
 
     public Instant estimatedCompletion( )
     public Instant estimatedCompletion( )
     {
     {
         final TimeDuration remainingDuration = remainingDuration();
         final TimeDuration remainingDuration = remainingDuration();
-        return Instant.ofEpochMilli( System.currentTimeMillis() + remainingDuration.getTotalMilliseconds() );
+        return Instant.ofEpochMilli( System.currentTimeMillis() + remainingDuration.asMillis() );
     }
     }
 
 
     public String debugOutput( )
     public String debugOutput( )

+ 8 - 10
server/src/main/java/password/pwm/util/TransactionSizeCalculator.java

@@ -25,8 +25,6 @@ package password.pwm.util;
 import password.pwm.util.java.JavaHelper;
 import password.pwm.util.java.JavaHelper;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.java.TimeDuration;
 
 
-import java.util.concurrent.TimeUnit;
-
 public class TransactionSizeCalculator
 public class TransactionSizeCalculator
 {
 {
 
 
@@ -44,24 +42,24 @@ public class TransactionSizeCalculator
     public void reset( )
     public void reset( )
     {
     {
         transactionSize = settings.getMinTransactions();
         transactionSize = settings.getMinTransactions();
-        lastDuration = settings.getDurationGoal().getTotalMilliseconds();
+        lastDuration = settings.getDurationGoal().asMillis();
     }
     }
 
 
     public void recordLastTransactionDuration( final long duration )
     public void recordLastTransactionDuration( final long duration )
     {
     {
-        recordLastTransactionDuration( new TimeDuration( duration ) );
+        recordLastTransactionDuration( TimeDuration.of( duration, TimeDuration.Unit.MILLISECONDS ) );
     }
     }
 
 
     public void pause( )
     public void pause( )
     {
     {
-        JavaHelper.pause( Math.min( lastDuration, settings.getDurationGoal().getTotalMilliseconds() * 2 ) );
+        JavaHelper.pause( Math.min( lastDuration, settings.getDurationGoal().asMillis() * 2 ) );
     }
     }
 
 
     public void recordLastTransactionDuration( final TimeDuration duration )
     public void recordLastTransactionDuration( final TimeDuration duration )
     {
     {
-        lastDuration = duration.getTotalMilliseconds();
-        final long durationGoalMs = settings.getDurationGoal().getTotalMilliseconds();
-        final long difference = Math.abs( duration.getTotalMilliseconds() - durationGoalMs );
+        lastDuration = duration.asMillis();
+        final long durationGoalMs = settings.getDurationGoal().asMillis();
+        final long difference = Math.abs( duration.asMillis() - durationGoalMs );
         final int closeThreshold = ( int ) ( durationGoalMs * .15f );
         final int closeThreshold = ( int ) ( durationGoalMs * .15f );
 
 
         int newTransactionSize;
         int newTransactionSize;
@@ -142,7 +140,7 @@ public class TransactionSizeCalculator
                 throw new IllegalArgumentException( "durationGoal must not be null" );
                 throw new IllegalArgumentException( "durationGoal must not be null" );
             }
             }
 
 
-            if ( durationGoal.getTotalMilliseconds() < 1 )
+            if ( durationGoal.asMillis() < 1 )
             {
             {
                 throw new IllegalArgumentException( "durationGoal must be greater than 0ms" );
                 throw new IllegalArgumentException( "durationGoal must be greater than 0ms" );
             }
             }
@@ -167,7 +165,7 @@ public class TransactionSizeCalculator
 
 
     public static class SettingsBuilder
     public static class SettingsBuilder
     {
     {
-        private TimeDuration durationGoal = new TimeDuration( 100, TimeUnit.MILLISECONDS );
+        private TimeDuration durationGoal = TimeDuration.of( 100, TimeDuration.Unit.MILLISECONDS );
         private int maxTransactions = 5003;
         private int maxTransactions = 5003;
         private int minTransactions = 3;
         private int minTransactions = 3;
 
 

+ 6 - 7
server/src/main/java/password/pwm/util/java/ConditionalTaskExecutor.java

@@ -24,7 +24,6 @@ package password.pwm.util.java;
 
 
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.logging.PwmLogger;
 
 
-import java.util.concurrent.TimeUnit;
 import java.util.function.Predicate;
 import java.util.function.Predicate;
 
 
 /**
 /**
@@ -76,17 +75,17 @@ public class ConditionalTaskExecutor
         public TimeDurationPredicate( final TimeDuration timeDuration )
         public TimeDurationPredicate( final TimeDuration timeDuration )
         {
         {
             this.timeDuration = timeDuration;
             this.timeDuration = timeDuration;
-            nextExecuteTimestamp = System.currentTimeMillis() + timeDuration.getTotalMilliseconds();
+            nextExecuteTimestamp = System.currentTimeMillis() + timeDuration.asMillis();
         }
         }
 
 
-        public TimeDurationPredicate( final long value, final TimeUnit unit )
+        public TimeDurationPredicate( final long value, final TimeDuration.Unit unit )
         {
         {
-            this( new TimeDuration( value, unit ) );
+            this( TimeDuration.of( value, unit ) );
         }
         }
 
 
-        public TimeDurationPredicate setNextTimeFromNow( final long value, final TimeUnit unit )
+        public TimeDurationPredicate setNextTimeFromNow( final long value, final TimeDuration.Unit unit )
         {
         {
-            nextExecuteTimestamp = System.currentTimeMillis() + unit.toMillis( value );
+            nextExecuteTimestamp = System.currentTimeMillis() + TimeDuration.of( value, unit ).asMillis();
             return this;
             return this;
         }
         }
 
 
@@ -95,7 +94,7 @@ public class ConditionalTaskExecutor
         {
         {
             if ( nextExecuteTimestamp <= System.currentTimeMillis() )
             if ( nextExecuteTimestamp <= System.currentTimeMillis() )
             {
             {
-                nextExecuteTimestamp = System.currentTimeMillis() + timeDuration.getTotalMilliseconds();
+                nextExecuteTimestamp = System.currentTimeMillis() + timeDuration.asMillis();
                 return true;
                 return true;
             }
             }
             return false;
             return false;

+ 1 - 1
server/src/main/java/password/pwm/util/java/JavaHelper.java

@@ -383,7 +383,7 @@ public class JavaHelper
         executor.shutdown();
         executor.shutdown();
         try
         try
         {
         {
-            return executor.awaitTermination( timeDuration.getTotalMilliseconds(), TimeUnit.MILLISECONDS );
+            return executor.awaitTermination( timeDuration.asMillis(), TimeUnit.MILLISECONDS );
         }
         }
         catch ( InterruptedException e )
         catch ( InterruptedException e )
         {
         {

+ 119 - 208
server/src/main/java/password/pwm/util/java/TimeDuration.java

@@ -23,6 +23,7 @@
 package password.pwm.util.java;
 package password.pwm.util.java;
 
 
 import com.novell.ldapchai.util.StringHelper;
 import com.novell.ldapchai.util.StringHelper;
+import lombok.Value;
 import password.pwm.PwmConstants;
 import password.pwm.PwmConstants;
 import password.pwm.i18n.Display;
 import password.pwm.i18n.Display;
 import password.pwm.util.LocaleHelper;
 import password.pwm.util.LocaleHelper;
@@ -35,8 +36,8 @@ import java.text.DecimalFormat;
 import java.time.Duration;
 import java.time.Duration;
 import java.time.Instant;
 import java.time.Instant;
 import java.time.temporal.ChronoUnit;
 import java.time.temporal.ChronoUnit;
+import java.time.temporal.TemporalUnit;
 import java.util.ArrayList;
 import java.util.ArrayList;
-import java.util.Date;
 import java.util.List;
 import java.util.List;
 import java.util.Locale;
 import java.util.Locale;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeUnit;
@@ -46,64 +47,89 @@ import java.util.concurrent.TimeUnit;
  * stored as milliseconds.</p>
  * stored as milliseconds.</p>
  *
  *
  * <p>Negative time durations are not permitted.  Operations that would result in a negative value
  * <p>Negative time durations are not permitted.  Operations that would result in a negative value
- * are negated and will instead result in positive values.</p>
+ * are ignored and will instead result in a zero value.</p>
  *
  *
  * @author Jason D. Rivard
  * @author Jason D. Rivard
  */
  */
 public class TimeDuration implements Comparable, Serializable
 public class TimeDuration implements Comparable, Serializable
 {
 {
+    public enum Unit
+    {
+        MILLISECONDS( ChronoUnit.MILLIS, TimeUnit.MILLISECONDS ),
+        SECONDS( ChronoUnit.SECONDS, TimeUnit.SECONDS ),
+        MINUTES( ChronoUnit.MINUTES, TimeUnit.MINUTES ),
+        HOURS( ChronoUnit.HOURS, TimeUnit.HOURS ),
+        DAYS( ChronoUnit.DAYS, TimeUnit.DAYS ),;
+
+        private final TemporalUnit temporalUnit;
+        private final TimeUnit timeUnit;
+
+        Unit( final TemporalUnit temporalUnit, final TimeUnit timeUnit )
+        {
+            this.temporalUnit = temporalUnit;
+            this.timeUnit = timeUnit;
+        }
+
+        public TemporalUnit getTemporalUnit( )
+        {
+            return temporalUnit;
+        }
+
+        public TimeUnit getTimeUnit( )
+        {
+            return timeUnit;
+        }
+    }
+
     public static final TimeDuration ZERO = new TimeDuration( 0 );
     public static final TimeDuration ZERO = new TimeDuration( 0 );
-    public static final TimeDuration MILLISECOND = new TimeDuration( 1, TimeUnit.MILLISECONDS );
-    public static final TimeDuration SECOND = new TimeDuration( 1, TimeUnit.SECONDS );
-    public static final TimeDuration SECONDS_10 = new TimeDuration( 10, TimeUnit.SECONDS );
-    public static final TimeDuration SECONDS_30 = new TimeDuration( 30, TimeUnit.SECONDS );
-    public static final TimeDuration MINUTE = new TimeDuration( 1, TimeUnit.MINUTES );
-    public static final TimeDuration HOUR = new TimeDuration( 1, TimeUnit.HOURS );
-    public static final TimeDuration DAY = new TimeDuration( 1, TimeUnit.DAYS );
+    public static final TimeDuration MILLISECOND = new TimeDuration( 1 );
+    public static final TimeDuration MILLISECONDS_2 = new TimeDuration( 2 );
+    public static final TimeDuration MILLISECONDS_3 = new TimeDuration( 3 );
+    public static final TimeDuration SECOND = new TimeDuration( 1000 );
+    public static final TimeDuration SECONDS_10 = new TimeDuration( 10 * 1000 );
+    public static final TimeDuration SECONDS_30 = new TimeDuration( 30 * 1000 );
+    public static final TimeDuration MINUTE = new TimeDuration( 60 * 1000 );
+    public static final TimeDuration HOUR = new TimeDuration( 60 * 60 * 1000 );
+    public static final TimeDuration DAY = new TimeDuration( 24 * 60 * 60 * 1000 );
 
 
     private final long ms;
     private final long ms;
-    private transient TimeDetail cachedTimeDetail;
 
 
     /**
     /**
      * Create a new TimeDuration using the specified duration, in milliseconds.
      * Create a new TimeDuration using the specified duration, in milliseconds.
      *
      *
      * @param durationMilliseconds a time period in milliseconds
      * @param durationMilliseconds a time period in milliseconds
      */
      */
-    public TimeDuration( final long durationMilliseconds )
+    private TimeDuration( final long durationMilliseconds )
     {
     {
-        if ( durationMilliseconds < 0 )
-        {
-            this.ms = 0;
-        }
-        else
-        {
-            this.ms = durationMilliseconds;
-        }
+        this.ms = durationMilliseconds < 0 ? 0 : durationMilliseconds;
     }
     }
 
 
-    public TimeDuration( final long duration, final TimeUnit timeUnit )
+    private static TimeDuration newTimeDuration( final long durationMilliseconds )
     {
     {
-        this( timeUnit.toMillis( duration ) );
+        switch ( (int) durationMilliseconds )
+        {
+            case 0: return ZERO;
+            case 1: return MILLISECOND;
+            case 2: return MILLISECONDS_2;
+            case 3: return MILLISECONDS_3;
+            case 1000: return SECOND;
+            case 10 * 1000: return SECONDS_10;
+            case 30 * 1000: return SECONDS_30;
+            case 60 * 1000: return MINUTE;
+            case 60 * 60 * 1000: return HOUR;
+            case 24 * 60 * 60 * 1000: return DAY;
+            default: return new TimeDuration( durationMilliseconds );
+        }
     }
     }
 
 
     public static TimeDuration fromCurrent( final long ms )
     public static TimeDuration fromCurrent( final long ms )
     {
     {
-        return new TimeDuration( System.currentTimeMillis(), ms );
-    }
-
-    public static TimeDuration fromCurrent( final Date date )
-    {
-        return new TimeDuration( System.currentTimeMillis(), date.getTime() );
+        return between( Instant.now(), Instant.ofEpochMilli( ms ) );
     }
     }
 
 
     public static TimeDuration fromCurrent( final Instant instant )
     public static TimeDuration fromCurrent( final Instant instant )
     {
     {
-        return new TimeDuration( System.currentTimeMillis(), instant.toEpochMilli() );
-    }
-
-    public static TimeDuration between( final Instant start, final Instant finish )
-    {
-        return new TimeDuration( start, finish );
+        return between( Instant.now(), instant );
     }
     }
 
 
     public static String compactFromCurrent( final Instant instant )
     public static String compactFromCurrent( final Instant instant )
@@ -113,32 +139,12 @@ public class TimeDuration implements Comparable, Serializable
 
 
     public static String asCompactString( final long ms )
     public static String asCompactString( final long ms )
     {
     {
-        return new TimeDuration( ms ).asCompactString();
-    }
-
-
-    /**
-     * Create a new TimeDuration using the absolute difference as the time
-     * period between the two supplied timestamps.
-     *
-     * @param date         timestamp in Date format
-     * @param milliseconds timestamp in ms
-     */
-    public TimeDuration( final Date date, final long milliseconds )
-    {
-        this( date.getTime(), milliseconds );
+        return newTimeDuration( ms ).asCompactString();
     }
     }
 
 
-    /**
-     * Create a new TimeDuration using the absolute difference as the time
-     * period between the two supplied timestamps.
-     *
-     * @param date         timestamp in Date format
-     * @param milliseconds timestamp in ms
-     */
-    public TimeDuration( final long milliseconds, final Date date )
+    public long asMillis()
     {
     {
-        this( milliseconds, date.getTime() );
+        return ms;
     }
     }
 
 
     /**
     /**
@@ -148,33 +154,9 @@ public class TimeDuration implements Comparable, Serializable
      * @param instant1 timestamp in Instant format
      * @param instant1 timestamp in Instant format
      * @param instant2 timestamp in Instant format
      * @param instant2 timestamp in Instant format
      */
      */
-    public TimeDuration( final Instant instant1, final Instant instant2 )
-    {
-        this( instant1.toEpochMilli(), instant2.toEpochMilli() );
-    }
-
-    /**
-     * Create a new TimeDuration using the absolute difference as the time
-     * period between the two supplied timestamps.
-     *
-     * @param date1 timestamp in Date format
-     * @param date2 timestamp in Date format
-     */
-    public TimeDuration( final Date date1, final Date date2 )
-    {
-        this( date1.getTime(), date2.getTime() );
-    }
-
-    /**
-     * Create a new TimeDuration using the absolute difference as the time
-     * period between the two supplied timestamps.
-     *
-     * @param milliseconds1 timestamp in ms
-     * @param milliseconds2 timestamp in ms
-     */
-    public TimeDuration( final long milliseconds1, final long milliseconds2 )
+    public static TimeDuration between( final Instant instant1, final Instant instant2 )
     {
     {
-        this( Math.abs( milliseconds1 - milliseconds2 ) );
+        return newTimeDuration( Math.abs( instant1.toEpochMilli() - instant2.toEpochMilli() ) );
     }
     }
 
 
     public boolean equals( final Object o )
     public boolean equals( final Object o )
@@ -198,41 +180,26 @@ public class TimeDuration implements Comparable, Serializable
         return ( int ) ( ms ^ ( ms >>> 32 ) );
         return ( int ) ( ms ^ ( ms >>> 32 ) );
     }
     }
 
 
-
     public TimeDuration add( final TimeDuration duration )
     public TimeDuration add( final TimeDuration duration )
     {
     {
-        return new TimeDuration( this.getTotalMilliseconds() + duration.getTotalMilliseconds() );
+        return newTimeDuration( this.ms + duration.ms );
     }
     }
 
 
     public Instant incrementFromInstant( final Instant input )
     public Instant incrementFromInstant( final Instant input )
     {
     {
         final long inputMillis = input.toEpochMilli();
         final long inputMillis = input.toEpochMilli();
-        final long nextMills = inputMillis + this.getTotalMilliseconds();
+        final long nextMills = inputMillis + this.ms;
         return Instant.ofEpochMilli( nextMills );
         return Instant.ofEpochMilli( nextMills );
     }
     }
 
 
-    public long getTotalMilliseconds( )
-    {
-        return ms;
-    }
-
-    public long getTotalSeconds( )
-    {
-        return ms / 1000;
-    }
-
-    public long getTotalMinutes( )
-    {
-        return ms / ( 60 * 1000 );
-    }
-
-    public long getTotalDays( )
+    public long as( final Unit unit )
     {
     {
-        return ms / ( 60 * 1000 * 60 * 24 );
+        return unit.getTimeUnit().convert( ms, TimeUnit.MILLISECONDS );
     }
     }
 
 
     public String asCompactString( )
     public String asCompactString( )
     {
     {
+        final FractionalTimeDetail fractionalTimeDetail = new FractionalTimeDetail( ms );
         final StringBuilder sb = new StringBuilder();
         final StringBuilder sb = new StringBuilder();
 
 
         if ( this.equals( ZERO ) )
         if ( this.equals( ZERO ) )
@@ -242,32 +209,32 @@ public class TimeDuration implements Comparable, Serializable
 
 
         if ( this.equals( DAY ) || this.isLongerThan( DAY ) )
         if ( this.equals( DAY ) || this.isLongerThan( DAY ) )
         {
         {
-            sb.append( this.getDays() );
+            sb.append( fractionalTimeDetail.getDays() );
             sb.append( "d" );
             sb.append( "d" );
         }
         }
 
 
         if ( this.equals( HOUR ) || this.isLongerThan( HOUR ) )
         if ( this.equals( HOUR ) || this.isLongerThan( HOUR ) )
         {
         {
-            if ( getHours() != 0 && getHours() != 24 )
+            if ( fractionalTimeDetail.getHours() != 0 && fractionalTimeDetail.getHours() != 24 )
             {
             {
                 if ( sb.length() > 0 )
                 if ( sb.length() > 0 )
                 {
                 {
                     sb.append( ":" );
                     sb.append( ":" );
                 }
                 }
-                sb.append( getHours() );
+                sb.append( fractionalTimeDetail.getHours() );
                 sb.append( "h" );
                 sb.append( "h" );
             }
             }
         }
         }
 
 
         if ( this.equals( MINUTE ) || this.isLongerThan( MINUTE ) )
         if ( this.equals( MINUTE ) || this.isLongerThan( MINUTE ) )
         {
         {
-            if ( getMinutes() != 0 )
+            if ( fractionalTimeDetail.getMinutes() != 0 )
             {
             {
                 if ( sb.length() > 0 )
                 if ( sb.length() > 0 )
                 {
                 {
                     sb.append( ":" );
                     sb.append( ":" );
                 }
                 }
-                sb.append( getMinutes() );
+                sb.append( fractionalTimeDetail.getMinutes() );
                 sb.append( "m" );
                 sb.append( "m" );
             }
             }
         }
         }
@@ -275,13 +242,13 @@ public class TimeDuration implements Comparable, Serializable
         if ( this.isShorterThan( 1000 * 60 * 10 ) && this.isLongerThan( 1000 * 3 ) )
         if ( this.isShorterThan( 1000 * 60 * 10 ) && this.isLongerThan( 1000 * 3 ) )
         {
         {
             // 10 minutes to 3 seconds
             // 10 minutes to 3 seconds
-            if ( getSeconds() != 0 )
+            if ( fractionalTimeDetail.getSeconds() != 0 )
             {
             {
                 if ( sb.length() > 0 )
                 if ( sb.length() > 0 )
                 {
                 {
                     sb.append( ":" );
                     sb.append( ":" );
                 }
                 }
-                sb.append( getSeconds() );
+                sb.append( fractionalTimeDetail.getSeconds() );
                 sb.append( "s" );
                 sb.append( "s" );
             }
             }
         }
         }
@@ -289,13 +256,13 @@ public class TimeDuration implements Comparable, Serializable
         if ( this.isShorterThan( 1000 * 3 ) )
         if ( this.isShorterThan( 1000 * 3 ) )
         {
         {
             // 3 seconds
             // 3 seconds
-            if ( getMilliseconds() != 0 )
+            if ( ms != 0 )
             {
             {
                 if ( sb.length() > 0 )
                 if ( sb.length() > 0 )
                 {
                 {
                     sb.append( ":" );
                     sb.append( ":" );
                 }
                 }
-                sb.append( getMilliseconds() );
+                sb.append( ms );
                 sb.append( "ms" );
                 sb.append( "ms" );
             }
             }
         }
         }
@@ -309,26 +276,6 @@ public class TimeDuration implements Comparable, Serializable
         return sb.toString();
         return sb.toString();
     }
     }
 
 
-    public long getDays( )
-    {
-        return getTimeDetail().days;
-    }
-
-    private TimeDetail getTimeDetail( )
-    {
-        // lazy init, but not sync'd, no big deal if dupes created
-        if ( cachedTimeDetail == null )
-        {
-            cachedTimeDetail = new TimeDetail( ms );
-        }
-        return cachedTimeDetail;
-    }
-
-    public long getHours( )
-    {
-        return getTimeDetail().hours;
-    }
-
     public boolean isLongerThan( final TimeDuration duration )
     public boolean isLongerThan( final TimeDuration duration )
     {
     {
         return this.compareTo( duration ) > 0;
         return this.compareTo( duration ) > 0;
@@ -337,43 +284,28 @@ public class TimeDuration implements Comparable, Serializable
     public int compareTo( final Object o )
     public int compareTo( final Object o )
     {
     {
         final TimeDuration td = ( TimeDuration ) o;
         final TimeDuration td = ( TimeDuration ) o;
-        final long otherMS = td.getTotalMilliseconds();
-        return ( ms == otherMS ? 0 : ( ms < otherMS ? -1 : 1 ) );
-    }
-
-    public long getMinutes( )
-    {
-        return getTimeDetail().minutes;
+        final long otherMS = td.as( Unit.MILLISECONDS );
+        return Long.compare( ms, otherMS );
     }
     }
 
 
     public boolean isLongerThan( final long durationMS )
     public boolean isLongerThan( final long durationMS )
     {
     {
-        return this.isLongerThan( new TimeDuration( durationMS ) );
-    }
-
-    public boolean isLongerThan( final long duration, final TimeUnit timeUnit )
-    {
-        return this.isLongerThan( timeUnit.toMillis( duration ) );
+        return this.isLongerThan( newTimeDuration( durationMS ) );
     }
     }
 
 
-    public boolean isShorterThan( final long duration, final TimeUnit timeUnit )
+    public boolean isLongerThan( final long duration, final Unit timeUnit )
     {
     {
-        return this.isShorterThan( timeUnit.toMillis( duration ) );
+        return this.isLongerThan( TimeDuration.of( duration, timeUnit ) );
     }
     }
 
 
-    public long getSeconds( )
+    public boolean isShorterThan( final long duration, final Unit timeUnit )
     {
     {
-        return getTimeDetail().seconds;
+        return this.isShorterThan( TimeDuration.of( duration, timeUnit ) );
     }
     }
 
 
     public boolean isShorterThan( final long durationMS )
     public boolean isShorterThan( final long durationMS )
     {
     {
-        return this.isShorterThan( new TimeDuration( durationMS ) );
-    }
-
-    public long getMilliseconds( )
-    {
-        return ms;
+        return this.isShorterThan( newTimeDuration( durationMS ) );
     }
     }
 
 
     public String asLongString( )
     public String asLongString( )
@@ -383,47 +315,44 @@ public class TimeDuration implements Comparable, Serializable
 
 
     public String asLongString( final Locale locale )
     public String asLongString( final Locale locale )
     {
     {
-        final TimeDetail timeDetail = getTimeDetail();
+        final FractionalTimeDetail fractionalTimeDetail = new FractionalTimeDetail( ms );
         final List<String> segments = new ArrayList<>();
         final List<String> segments = new ArrayList<>();
 
 
         //output number of days
         //output number of days
-        if ( timeDetail.days > 0 )
+        if ( fractionalTimeDetail.days > 0 )
         {
         {
-            final StringBuilder sb = new StringBuilder();
-            sb.append( timeDetail.days );
-            sb.append( " " );
-            sb.append( timeDetail.days == 1
-                    ? LocaleHelper.getLocalizedMessage( locale, Display.Display_Day, null )
-                    : LocaleHelper.getLocalizedMessage( locale, Display.Display_Days, null ) );
-            segments.add( sb.toString() );
+            segments.add( fractionalTimeDetail.days
+                    + " "
+                    + ( fractionalTimeDetail.days == 1
+                            ? LocaleHelper.getLocalizedMessage( locale, Display.Display_Day, null )
+                            : LocaleHelper.getLocalizedMessage( locale, Display.Display_Days, null ) )
+            );
         }
         }
 
 
         //output number of hours
         //output number of hours
-        if ( timeDetail.hours > 0 )
+        if ( fractionalTimeDetail.hours > 0 )
         {
         {
-            final StringBuilder sb = new StringBuilder();
-            sb.append( timeDetail.hours );
-            sb.append( " " );
-            sb.append( timeDetail.hours == 1
-                    ? LocaleHelper.getLocalizedMessage( locale, Display.Display_Hour, null )
-                    : LocaleHelper.getLocalizedMessage( locale, Display.Display_Hours, null ) );
-            segments.add( sb.toString() );
+            segments.add( fractionalTimeDetail.hours
+                    + " "
+                    + ( fractionalTimeDetail.hours == 1
+                            ? LocaleHelper.getLocalizedMessage( locale, Display.Display_Hour, null )
+                            : LocaleHelper.getLocalizedMessage( locale, Display.Display_Hours, null ) )
+            );
         }
         }
 
 
         //output number of minutes
         //output number of minutes
-        if ( timeDetail.minutes > 0 )
+        if ( fractionalTimeDetail.minutes > 0 )
         {
         {
-            final StringBuilder sb = new StringBuilder();
-            sb.append( timeDetail.minutes );
-            sb.append( " " );
-            sb.append( timeDetail.minutes == 1
-                    ? LocaleHelper.getLocalizedMessage( locale, Display.Display_Minute, null )
-                    : LocaleHelper.getLocalizedMessage( locale, Display.Display_Minutes, null ) );
-            segments.add( sb.toString() );
+            segments.add( fractionalTimeDetail.minutes
+                    + " "
+                    + ( fractionalTimeDetail.minutes == 1
+                            ? LocaleHelper.getLocalizedMessage( locale, Display.Display_Minute, null )
+                            : LocaleHelper.getLocalizedMessage( locale, Display.Display_Minutes, null ) )
+            );
         }
         }
 
 
         //seconds & ms
         //seconds & ms
-        if ( timeDetail.seconds > 0 || segments.isEmpty() )
+        if ( fractionalTimeDetail.seconds > 0 || segments.isEmpty() )
         {
         {
             final StringBuilder sb = new StringBuilder();
             final StringBuilder sb = new StringBuilder();
             if ( sb.length() == 0 )
             if ( sb.length() == 0 )
@@ -451,12 +380,12 @@ public class TimeDuration implements Comparable, Serializable
                 }
                 }
                 else
                 else
                 {
                 {
-                    sb.append( timeDetail.seconds );
+                    sb.append( fractionalTimeDetail.seconds );
                 }
                 }
             }
             }
             else
             else
             {
             {
-                sb.append( timeDetail.seconds );
+                sb.append( fractionalTimeDetail.seconds );
             }
             }
             sb.append( " " );
             sb.append( " " );
             sb.append( ms == 1000
             sb.append( ms == 1000
@@ -469,16 +398,6 @@ public class TimeDuration implements Comparable, Serializable
         return StringHelper.stringCollectionToString( segments, ", " );
         return StringHelper.stringCollectionToString( segments, ", " );
     }
     }
 
 
-    public Date getDateAfterNow( )
-    {
-        return this.getDateAfter( new Date( System.currentTimeMillis() ) );
-    }
-
-    public Date getDateAfter( final Date specifiedDate )
-    {
-        return new Date( specifiedDate.getTime() + ms );
-    }
-
     public Instant getInstantAfter( final Instant specifiedDate )
     public Instant getInstantAfter( final Instant specifiedDate )
     {
     {
         return specifiedDate.minusMillis( ms );
         return specifiedDate.minusMillis( ms );
@@ -489,15 +408,6 @@ public class TimeDuration implements Comparable, Serializable
         return Instant.now().minusMillis( ms );
         return Instant.now().minusMillis( ms );
     }
     }
 
 
-    public Date getDateBeforeNow( )
-    {
-        return this.getDateBefore( new Date( System.currentTimeMillis() ) );
-    }
-
-    public Date getDateBefore( final Date specifiedDate )
-    {
-        return new Date( specifiedDate.getTime() - ms );
-    }
 
 
     public boolean isShorterThan( final TimeDuration duration )
     public boolean isShorterThan( final TimeDuration duration )
     {
     {
@@ -506,7 +416,7 @@ public class TimeDuration implements Comparable, Serializable
 
 
     public TimeDuration subtract( final TimeDuration duration )
     public TimeDuration subtract( final TimeDuration duration )
     {
     {
-        return new TimeDuration( Math.abs( this.getTotalMilliseconds() - duration.getTotalMilliseconds() ) );
+        return newTimeDuration( Math.abs( ms - duration.ms ) );
     }
     }
 
 
     @Override
     @Override
@@ -554,7 +464,7 @@ public class TimeDuration implements Comparable, Serializable
     @CheckReturnValue( when = When.NEVER )
     @CheckReturnValue( when = When.NEVER )
     public TimeDuration pause( )
     public TimeDuration pause( )
     {
     {
-        return pause( this.getTotalMilliseconds() );
+        return pause( this.as( Unit.MILLISECONDS ) );
     }
     }
 
 
     public Duration asDuration()
     public Duration asDuration()
@@ -564,15 +474,16 @@ public class TimeDuration implements Comparable, Serializable
 
 
     public static TimeDuration fromDuration( final Duration duration )
     public static TimeDuration fromDuration( final Duration duration )
     {
     {
-        return new TimeDuration( duration.get( ChronoUnit.MILLIS ) );
+        return newTimeDuration( duration.toMillis() );
     }
     }
 
 
-    public static TimeDuration of ( final long value, final TimeUnit timeUnit )
+    public static TimeDuration of ( final long value, final Unit timeUnit )
     {
     {
-        return new TimeDuration( value, timeUnit );
+        return fromDuration( Duration.of( value, timeUnit.getTemporalUnit() ) );
     }
     }
 
 
-    private static class TimeDetail implements Serializable
+    @Value
+    private static class FractionalTimeDetail implements Serializable
     {
     {
         private final long milliseconds;
         private final long milliseconds;
         private final long seconds;
         private final long seconds;
@@ -580,7 +491,7 @@ public class TimeDuration implements Comparable, Serializable
         private final long hours;
         private final long hours;
         private final long days;
         private final long days;
 
 
-        TimeDetail( final long duration )
+        FractionalTimeDetail( final long duration )
         {
         {
             final long totalSeconds = new BigDecimal( duration ).movePointLeft( 3 ).longValue();
             final long totalSeconds = new BigDecimal( duration ).movePointLeft( 3 ).longValue();
             milliseconds = duration % 1000;
             milliseconds = duration % 1000;

+ 1 - 1
server/src/main/java/password/pwm/util/localdb/LocalDBFactory.java

@@ -83,7 +83,7 @@ public class LocalDBFactory
         final LocalDB localDB = new LocalDBAdaptor( dbProvider, pwmApplication );
         final LocalDB localDB = new LocalDBAdaptor( dbProvider, pwmApplication );
 
 
         initInstance( dbProvider, dbDirectory, initParameters, className, parameters );
         initInstance( dbProvider, dbDirectory, initParameters, className, parameters );
-        final TimeDuration openTime = new TimeDuration( System.currentTimeMillis() - startTime );
+        final TimeDuration openTime = TimeDuration.of( System.currentTimeMillis() - startTime, TimeDuration.Unit.MILLISECONDS );
 
 
         if ( !readonly )
         if ( !readonly )
         {
         {

+ 2 - 2
server/src/main/java/password/pwm/util/localdb/LocalDBStoredQueue.java

@@ -24,6 +24,7 @@ package password.pwm.util.localdb;
 
 
 import password.pwm.PwmApplication;
 import password.pwm.PwmApplication;
 import password.pwm.util.java.ConditionalTaskExecutor;
 import password.pwm.util.java.ConditionalTaskExecutor;
+import password.pwm.util.java.TimeDuration;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.logging.PwmLogger;
 
 
 import java.math.BigInteger;
 import java.math.BigInteger;
@@ -40,7 +41,6 @@ import java.util.Map;
 import java.util.NoSuchElementException;
 import java.util.NoSuchElementException;
 import java.util.Queue;
 import java.util.Queue;
 import java.util.Set;
 import java.util.Set;
-import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.locks.ReadWriteLock;
 import java.util.concurrent.locks.ReadWriteLock;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
@@ -1097,7 +1097,7 @@ LocalDBStoredQueue implements Queue<String>, Deque<String>
                             }
                             }
                         }
                         }
                     },
                     },
-                    new ConditionalTaskExecutor.TimeDurationPredicate( 30, TimeUnit.SECONDS )
+                    new ConditionalTaskExecutor.TimeDurationPredicate( 30, TimeDuration.Unit.SECONDS )
             );
             );
 
 
             // trim the top.
             // trim the top.

+ 1 - 2
server/src/main/java/password/pwm/util/localdb/LocalDBUtility.java

@@ -55,7 +55,6 @@ import java.util.Map;
 import java.util.Timer;
 import java.util.Timer;
 import java.util.TimerTask;
 import java.util.TimerTask;
 import java.util.TreeMap;
 import java.util.TreeMap;
-import java.util.concurrent.TimeUnit;
 import java.util.zip.GZIPInputStream;
 import java.util.zip.GZIPInputStream;
 import java.util.zip.GZIPOutputStream;
 import java.util.zip.GZIPOutputStream;
 
 
@@ -235,7 +234,7 @@ public class LocalDBUtility
         final Instant startTime = Instant.now();
         final Instant startTime = Instant.now();
         final TransactionSizeCalculator transactionCalculator = new TransactionSizeCalculator(
         final TransactionSizeCalculator transactionCalculator = new TransactionSizeCalculator(
                 new TransactionSizeCalculator.SettingsBuilder()
                 new TransactionSizeCalculator.SettingsBuilder()
-                        .setDurationGoal( new TimeDuration( 100, TimeUnit.MILLISECONDS ) )
+                        .setDurationGoal( TimeDuration.of( 100, TimeDuration.Unit.MILLISECONDS ) )
                         .setMinTransactions( 50 )
                         .setMinTransactions( 50 )
                         .setMaxTransactions( 5 * 1000 )
                         .setMaxTransactions( 5 * 1000 )
                         .createSettings()
                         .createSettings()

+ 13 - 14
server/src/main/java/password/pwm/util/localdb/WorkQueueProcessor.java

@@ -60,8 +60,8 @@ import java.util.concurrent.locks.LockSupport;
 public final class WorkQueueProcessor<W extends Serializable>
 public final class WorkQueueProcessor<W extends Serializable>
 {
 {
 
 
-    private static final TimeDuration SUBMIT_QUEUE_FULL_RETRY_CYCLE_INTERVAL = new TimeDuration( 100, TimeUnit.MILLISECONDS );
-    private static final TimeDuration CLOSE_RETRY_CYCLE_INTERVAL = new TimeDuration( 100, TimeUnit.MILLISECONDS );
+    private static final TimeDuration SUBMIT_QUEUE_FULL_RETRY_CYCLE_INTERVAL = TimeDuration.of( 100, TimeDuration.Unit.MILLISECONDS );
+    private static final TimeDuration CLOSE_RETRY_CYCLE_INTERVAL = TimeDuration.of( 100, TimeDuration.Unit.MILLISECONDS );
 
 
     private final Deque<String> queue;
     private final Deque<String> queue;
     private final Settings settings;
     private final Settings settings;
@@ -77,7 +77,7 @@ public final class WorkQueueProcessor<W extends Serializable>
     private ThreadPoolExecutor executorService;
     private ThreadPoolExecutor executorService;
 
 
     private final EventRateMeter.MovingAverage avgLagTime = new EventRateMeter.MovingAverage( 60 * 60 * 1000 );
     private final EventRateMeter.MovingAverage avgLagTime = new EventRateMeter.MovingAverage( 60 * 60 * 1000 );
-    private final EventRateMeter sendRate = new EventRateMeter( new TimeDuration( 1, TimeUnit.HOURS ) );
+    private final EventRateMeter sendRate = new EventRateMeter( TimeDuration.HOUR );
 
 
     private final AtomicInteger preQueueSubmit = new AtomicInteger( 0 );
     private final AtomicInteger preQueueSubmit = new AtomicInteger( 0 );
     private final AtomicInteger preQueueBypass = new AtomicInteger( 0 );
     private final AtomicInteger preQueueBypass = new AtomicInteger( 0 );
@@ -153,8 +153,8 @@ public final class WorkQueueProcessor<W extends Serializable>
         if ( localWorkerThread.isRunning() )
         if ( localWorkerThread.isRunning() )
         {
         {
             JavaHelper.pause(
             JavaHelper.pause(
-                    settings.getMaxShutdownWaitTime().getMilliseconds(),
-                    CLOSE_RETRY_CYCLE_INTERVAL.getTotalMilliseconds(),
+                    settings.getMaxShutdownWaitTime().asMillis(),
+                    CLOSE_RETRY_CYCLE_INTERVAL.asMillis(),
                     o -> !localWorkerThread.isRunning() );
                     o -> !localWorkerThread.isRunning() );
         }
         }
 
 
@@ -255,7 +255,7 @@ public final class WorkQueueProcessor<W extends Serializable>
                             + ", item=" + itemProcessor.convertToDebugString( itemWrapper.getWorkItem() );
                             + ", item=" + itemProcessor.convertToDebugString( itemWrapper.getWorkItem() );
                     throw new PwmOperationalException( new ErrorInformation( PwmError.ERROR_UNKNOWN, errorMsg ) );
                     throw new PwmOperationalException( new ErrorInformation( PwmError.ERROR_UNKNOWN, errorMsg ) );
                 }
                 }
-                JavaHelper.pause( SUBMIT_QUEUE_FULL_RETRY_CYCLE_INTERVAL.getTotalMilliseconds() );
+                JavaHelper.pause( SUBMIT_QUEUE_FULL_RETRY_CYCLE_INTERVAL.asMillis() );
             }
             }
 
 
             eldestItem = itemWrapper.getDate();
             eldestItem = itemWrapper.getDate();
@@ -434,7 +434,7 @@ public final class WorkQueueProcessor<W extends Serializable>
 
 
                         case RETRY:
                         case RETRY:
                         {
                         {
-                            retryWakeupTime = Instant.ofEpochMilli( System.currentTimeMillis() + settings.getRetryInterval().getTotalMilliseconds() );
+                            retryWakeupTime = Instant.ofEpochMilli( System.currentTimeMillis() + settings.getRetryInterval().asMillis() );
                             logger.debug( "will retry item after failure, item=" + makeDebugText( itemWrapper ) );
                             logger.debug( "will retry item after failure, item=" + makeDebugText( itemWrapper ) );
                         }
                         }
                         break;
                         break;
@@ -550,24 +550,23 @@ public final class WorkQueueProcessor<W extends Serializable>
         private int preThreads = 0;
         private int preThreads = 0;
 
 
         @Builder.Default
         @Builder.Default
-        private TimeDuration maxSubmitWaitTime = new TimeDuration( 5, TimeUnit.SECONDS );
+        private TimeDuration maxSubmitWaitTime = TimeDuration.of( 5, TimeDuration.Unit.SECONDS );
 
 
         @Builder.Default
         @Builder.Default
+        private TimeDuration retryInterval = TimeDuration.of( 30, TimeDuration.Unit.SECONDS );
 
 
-        private TimeDuration retryInterval = new TimeDuration( 30, TimeUnit.SECONDS );
         @Builder.Default
         @Builder.Default
-
-        private TimeDuration retryDiscardAge = new TimeDuration( 1, TimeUnit.HOURS );
+        private TimeDuration retryDiscardAge = TimeDuration.of( 1, TimeDuration.Unit.HOURS );
 
 
         @Builder.Default
         @Builder.Default
-        private TimeDuration maxShutdownWaitTime = new TimeDuration( 30, TimeUnit.SECONDS );
+        private TimeDuration maxShutdownWaitTime = TimeDuration.of( 30, TimeDuration.Unit.SECONDS );
     }
     }
 
 
     private void logAndStatUpdateForSuccess( final ItemWrapper<W> itemWrapper )
     private void logAndStatUpdateForSuccess( final ItemWrapper<W> itemWrapper )
             throws PwmOperationalException
             throws PwmOperationalException
     {
     {
         final TimeDuration lagTime = TimeDuration.fromCurrent( itemWrapper.getDate() );
         final TimeDuration lagTime = TimeDuration.fromCurrent( itemWrapper.getDate() );
-        avgLagTime.update( lagTime.getTotalMilliseconds() );
+        avgLagTime.update( lagTime.asMillis() );
         sendRate.markEvents( 1 );
         sendRate.markEvents( 1 );
         logger.trace( "successfully processed item=" + makeDebugText( itemWrapper ) + "; lagTime=" + lagTime.asCompactString()
         logger.trace( "successfully processed item=" + makeDebugText( itemWrapper ) + "; lagTime=" + lagTime.asCompactString()
                 + "; " + StringUtil.mapToString( debugInfo() ) );
                 + "; " + StringUtil.mapToString( debugInfo() ) );
@@ -576,7 +575,7 @@ public final class WorkQueueProcessor<W extends Serializable>
     public Map<String, String> debugInfo( )
     public Map<String, String> debugInfo( )
     {
     {
         final Map<String, String> output = new HashMap<>();
         final Map<String, String> output = new HashMap<>();
-        output.put( "avgLagTime", new TimeDuration( ( long ) avgLagTime.getAverage() ).asCompactString() );
+        output.put( "avgLagTime", TimeDuration.of( ( long ) avgLagTime.getAverage(), TimeDuration.Unit.MILLISECONDS ).asCompactString() );
         output.put( "sendRate", sendRate.readEventRate().setScale( 2, BigDecimal.ROUND_DOWN ) + "/s" );
         output.put( "sendRate", sendRate.readEventRate().setScale( 2, BigDecimal.ROUND_DOWN ) + "/s" );
         output.put( "preQueueSubmit", String.valueOf( preQueueSubmit.get() ) );
         output.put( "preQueueSubmit", String.valueOf( preQueueSubmit.get() ) );
         output.put( "preQueueBypass", String.valueOf( preQueueBypass.get() ) );
         output.put( "preQueueBypass", String.valueOf( preQueueBypass.get() ) );

+ 3 - 5
server/src/main/java/password/pwm/util/localdb/XodusLocalDB.java

@@ -54,13 +54,11 @@ import java.nio.file.StandardOpenOption;
 import java.time.Instant;
 import java.time.Instant;
 import java.util.Collection;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Collections;
-import java.util.Date;
 import java.util.HashMap;
 import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.Map;
 import java.util.ResourceBundle;
 import java.util.ResourceBundle;
 import java.util.Set;
 import java.util.Set;
-import java.util.concurrent.TimeUnit;
 import java.util.zip.Deflater;
 import java.util.zip.Deflater;
 import java.util.zip.DeflaterOutputStream;
 import java.util.zip.DeflaterOutputStream;
 import java.util.zip.Inflater;
 import java.util.zip.Inflater;
@@ -70,7 +68,7 @@ import java.util.zip.InflaterOutputStream;
 public class XodusLocalDB implements LocalDBProvider
 public class XodusLocalDB implements LocalDBProvider
 {
 {
     private static final PwmLogger LOGGER = PwmLogger.forClass( XodusLocalDB.class );
     private static final PwmLogger LOGGER = PwmLogger.forClass( XodusLocalDB.class );
-    private static final TimeDuration STATS_OUTPUT_INTERVAL = new TimeDuration( 24, TimeUnit.HOURS );
+    private static final TimeDuration STATS_OUTPUT_INTERVAL = TimeDuration.DAY;
 
 
     private static final String FILE_SUB_PATH = "xodus";
     private static final String FILE_SUB_PATH = "xodus";
     private static final String README_FILENAME = "README.TXT";
     private static final String README_FILENAME = "README.TXT";
@@ -102,7 +100,7 @@ public class XodusLocalDB implements LocalDBProvider
     private final Map<LocalDB.DB, Store> cachedStoreObjects = new HashMap<>();
     private final Map<LocalDB.DB, Store> cachedStoreObjects = new HashMap<>();
 
 
     private final ConditionalTaskExecutor outputLogExecutor = new ConditionalTaskExecutor(
     private final ConditionalTaskExecutor outputLogExecutor = new ConditionalTaskExecutor(
-            ( ) -> outputStats(), new ConditionalTaskExecutor.TimeDurationPredicate( STATS_OUTPUT_INTERVAL ).setNextTimeFromNow( 1, TimeUnit.MINUTES )
+            ( ) -> outputStats(), new ConditionalTaskExecutor.TimeDurationPredicate( STATS_OUTPUT_INTERVAL ).setNextTimeFromNow( 1, TimeDuration.Unit.MINUTES )
     );
     );
 
 
     private BindMachine bindMachine = new BindMachine( BindMachine.DEFAULT_ENABLE_COMPRESSION, BindMachine.DEFAULT_MIN_COMPRESSION_LENGTH );
     private BindMachine bindMachine = new BindMachine( BindMachine.DEFAULT_ENABLE_COMPRESSION, BindMachine.DEFAULT_MIN_COMPRESSION_LENGTH );
@@ -414,7 +412,7 @@ public class XodusLocalDB implements LocalDBProvider
         checkStatus( true );
         checkStatus( true );
 
 
         LOGGER.trace( "begin truncate of " + db.toString() + ", size=" + this.size( db ) );
         LOGGER.trace( "begin truncate of " + db.toString() + ", size=" + this.size( db ) );
-        final Date startDate = new Date();
+        final Instant startDate = Instant.now();
 
 
         environment.executeInTransaction( transaction ->
         environment.executeInTransaction( transaction ->
         {
         {

+ 1 - 1
server/src/main/java/password/pwm/util/logging/LocalDBLogger.java

@@ -458,7 +458,7 @@ public class LocalDBLogger implements PwmService
                         final Instant startTime = Instant.now();
                         final Instant startTime = Instant.now();
                         localDBListQueue.removeLast( cleanupCount );
                         localDBListQueue.removeLast( cleanupCount );
                         final TimeDuration purgeTime = TimeDuration.fromCurrent( startTime );
                         final TimeDuration purgeTime = TimeDuration.fromCurrent( startTime );
-                        final TimeDuration pauseTime = new TimeDuration( JavaHelper.rangeCheck( 20, 2000, ( int ) purgeTime.getTotalMilliseconds() ) );
+                        final TimeDuration pauseTime = TimeDuration.of( JavaHelper.rangeCheck( 20, 2000, ( int ) purgeTime.asMillis() ), TimeDuration.Unit.MILLISECONDS );
                         pauseTime.pause();
                         pauseTime.pause();
                     }
                     }
                 }
                 }

+ 7 - 5
server/src/main/java/password/pwm/util/logging/LocalDBLoggerSettings.java

@@ -31,7 +31,6 @@ import java.io.Serializable;
 import java.util.Collections;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.HashSet;
 import java.util.Set;
 import java.util.Set;
-import java.util.concurrent.TimeUnit;
 
 
 public class LocalDBLoggerSettings implements Serializable
 public class LocalDBLoggerSettings implements Serializable
 {
 {
@@ -106,9 +105,12 @@ public class LocalDBLoggerSettings implements Serializable
         }
         }
         final int maxEvents = ( int ) configuration.readSettingAsLong( PwmSetting.EVENTS_PWMDB_MAX_EVENTS );
         final int maxEvents = ( int ) configuration.readSettingAsLong( PwmSetting.EVENTS_PWMDB_MAX_EVENTS );
         final long maxAgeMS = 1000 * configuration.readSettingAsLong( PwmSetting.EVENTS_PWMDB_MAX_AGE );
         final long maxAgeMS = 1000 * configuration.readSettingAsLong( PwmSetting.EVENTS_PWMDB_MAX_AGE );
-        final TimeDuration maxAge = new TimeDuration( maxAgeMS );
+        final TimeDuration maxAge = TimeDuration.of( maxAgeMS, TimeDuration.Unit.MILLISECONDS );
         final int maxBufferSize = Integer.parseInt( configuration.readAppProperty( AppProperty.LOCALDB_LOGWRITER_BUFFER_SIZE ) );
         final int maxBufferSize = Integer.parseInt( configuration.readAppProperty( AppProperty.LOCALDB_LOGWRITER_BUFFER_SIZE ) );
-        final TimeDuration maxBufferWaitTime = new TimeDuration( Long.parseLong( configuration.readAppProperty( AppProperty.LOCALDB_LOGWRITER_MAX_BUFFER_WAIT_MS ) ) );
+        final TimeDuration maxBufferWaitTime = TimeDuration.of(
+                Long.parseLong( configuration.readAppProperty( AppProperty.LOCALDB_LOGWRITER_MAX_BUFFER_WAIT_MS ) ),
+                TimeDuration.Unit.MILLISECONDS
+        );
         final int maxTrimSize = Integer.parseInt( configuration.readAppProperty( AppProperty.LOCALDB_LOGWRITER_MAX_TRIM_SIZE ) );
         final int maxTrimSize = Integer.parseInt( configuration.readAppProperty( AppProperty.LOCALDB_LOGWRITER_MAX_TRIM_SIZE ) );
 
 
         return new Builder()
         return new Builder()
@@ -124,10 +126,10 @@ public class LocalDBLoggerSettings implements Serializable
     public static class Builder
     public static class Builder
     {
     {
         private int maxEvents = 1 * 1000 * 1000;
         private int maxEvents = 1 * 1000 * 1000;
-        private TimeDuration maxAge = new TimeDuration( 7, TimeUnit.DAYS );
+        private TimeDuration maxAge = TimeDuration.of( 7, TimeDuration.Unit.DAYS );
         private Set<Flag> flags = Collections.emptySet();
         private Set<Flag> flags = Collections.emptySet();
         private int maxBufferSize = 1000;
         private int maxBufferSize = 1000;
-        private TimeDuration maxBufferWaitTime = new TimeDuration( 1, TimeUnit.MINUTES );
+        private TimeDuration maxBufferWaitTime = TimeDuration.of( 1, TimeDuration.Unit.MINUTES );
         private int maxTrimSize = 501;
         private int maxTrimSize = 501;
 
 
         public Builder setMaxEvents( final int maxEvents )
         public Builder setMaxEvents( final int maxEvents )

+ 1 - 1
server/src/main/java/password/pwm/util/logging/LocalDBSearchResults.java

@@ -125,6 +125,6 @@ public class LocalDBSearchResults implements Iterator<PwmLogEvent>
 
 
     public TimeDuration getSearchTime( )
     public TimeDuration getSearchTime( )
     {
     {
-        return finishTime == null ? TimeDuration.fromCurrent( startTime ) : new TimeDuration( startTime, finishTime );
+        return finishTime == null ? TimeDuration.fromCurrent( startTime ) : TimeDuration.between( startTime, finishTime );
     }
     }
 }
 }

+ 1 - 1
server/src/main/java/password/pwm/util/macro/StandardMacros.java

@@ -415,7 +415,7 @@ public abstract class StandardMacros
             {
             {
                 final Instant pwdExpirationTime = userInfo.getPasswordExpirationTime();
                 final Instant pwdExpirationTime = userInfo.getPasswordExpirationTime();
                 final TimeDuration timeUntilExpiration = TimeDuration.fromCurrent( pwdExpirationTime );
                 final TimeDuration timeUntilExpiration = TimeDuration.fromCurrent( pwdExpirationTime );
-                final long daysUntilExpiration = timeUntilExpiration.getDays();
+                final long daysUntilExpiration = timeUntilExpiration.as( TimeDuration.Unit.DAYS );
                 return String.valueOf( daysUntilExpiration );
                 return String.valueOf( daysUntilExpiration );
             }
             }
             catch ( PwmUnrecoverableException e )
             catch ( PwmUnrecoverableException e )

+ 2 - 2
server/src/main/java/password/pwm/util/operations/OtpService.java

@@ -63,10 +63,10 @@ import java.io.IOException;
 import java.io.Serializable;
 import java.io.Serializable;
 import java.security.MessageDigest;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import java.security.NoSuchAlgorithmException;
+import java.time.Instant;
 import java.util.ArrayList;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Collections;
-import java.util.Date;
 import java.util.EnumMap;
 import java.util.EnumMap;
 import java.util.Iterator;
 import java.util.Iterator;
 import java.util.List;
 import java.util.List;
@@ -323,7 +323,7 @@ public class OtpService implements PwmService
     {
     {
         OTPUserRecord otpConfig = null;
         OTPUserRecord otpConfig = null;
         final Configuration config = pwmApplication.getConfig();
         final Configuration config = pwmApplication.getConfig();
-        final Date methodStartTime = new Date();
+        final Instant methodStartTime = Instant.now();
 
 
         final List<DataStorageMethod> otpSecretStorageLocations = config.getOtpSecretStorageLocations(
         final List<DataStorageMethod> otpSecretStorageLocations = config.getOtpSecretStorageLocations(
                 PwmSetting.OTP_SECRET_READ_PREFERENCE );
                 PwmSetting.OTP_SECRET_READ_PREFERENCE );

+ 3 - 4
server/src/main/java/password/pwm/util/operations/PasswordUtility.java

@@ -98,7 +98,6 @@ import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.List;
 import java.util.Locale;
 import java.util.Locale;
 import java.util.Map;
 import java.util.Map;
-import java.util.concurrent.TimeUnit;
 
 
 /**
 /**
  * @author Jason D. Rivard
  * @author Jason D. Rivard
@@ -1286,10 +1285,10 @@ public class PasswordUtility
                 return;
                 return;
             }
             }
 
 
-            minimumLifetime = new TimeDuration( minimumLifetimeSeconds, TimeUnit.SECONDS );
+            minimumLifetime = TimeDuration.of( minimumLifetimeSeconds, TimeDuration.Unit.SECONDS );
 
 
         }
         }
-        final Instant allowedChangeDate = Instant.ofEpochMilli( lastModified.toEpochMilli() + minimumLifetime.getTotalMilliseconds() );
+        final Instant allowedChangeDate = Instant.ofEpochMilli( lastModified.toEpochMilli() + minimumLifetime.asMillis() );
         final TimeDuration passwordAge = TimeDuration.fromCurrent( lastModified );
         final TimeDuration passwordAge = TimeDuration.fromCurrent( lastModified );
         final String msg = "last password change was at "
         final String msg = "last password change was at "
                 + JavaHelper.toIsoDate( lastModified )
                 + JavaHelper.toIsoDate( lastModified )
@@ -1350,7 +1349,7 @@ public class PasswordUtility
                 return false;
                 return false;
             }
             }
 
 
-            minimumLifetime = new TimeDuration( minimumLifetimeSeconds, TimeUnit.SECONDS );
+            minimumLifetime = TimeDuration.of( minimumLifetimeSeconds, TimeDuration.Unit.SECONDS );
         }
         }
 
 
         final TimeDuration passwordAge = TimeDuration.fromCurrent( lastModified );
         final TimeDuration passwordAge = TimeDuration.fromCurrent( lastModified );

+ 14 - 14
server/src/main/java/password/pwm/util/operations/cr/NMASCrOperator.java

@@ -154,7 +154,7 @@ public class NMASCrOperator implements CrOperator
         {
         {
             maxNmasIdleSeconds = minSeconds;
             maxNmasIdleSeconds = minSeconds;
         }
         }
-        maxThreadIdleTime = new TimeDuration( maxNmasIdleSeconds * 1000 );
+        maxThreadIdleTime = TimeDuration.of( maxNmasIdleSeconds, TimeDuration.Unit.SECONDS );
 
 
         registerSaslProvider();
         registerSaslProvider();
     }
     }
@@ -771,7 +771,7 @@ public class NMASCrOperator implements CrOperator
             {
             {
                 final Instant startTime = Instant.now();
                 final Instant startTime = Instant.now();
                 boolean done = this.isNmasDone();
                 boolean done = this.isNmasDone();
-                Date lastLogTime = new Date();
+                Instant lastLogTime = Instant.now();
                 while ( !done && TimeDuration.fromCurrent( startTime ).isShorterThan( maxThreadIdleTime ) )
                 while ( !done && TimeDuration.fromCurrent( startTime ).isShorterThan( maxThreadIdleTime ) )
                 {
                 {
                     LOGGER.trace( "attempt to read return code, but isNmasDone=false, will await completion" );
                     LOGGER.trace( "attempt to read return code, but isNmasDone=false, will await completion" );
@@ -788,7 +788,7 @@ public class NMASCrOperator implements CrOperator
                     {
                     {
                         LOGGER.trace( "waiting for return code: " + TimeDuration.fromCurrent( startTime ).asCompactString()
                         LOGGER.trace( "waiting for return code: " + TimeDuration.fromCurrent( startTime ).asCompactString()
                                 + " unsupportedCallbackHasOccurred=" + unsupportedCallbackHasOccurred );
                                 + " unsupportedCallbackHasOccurred=" + unsupportedCallbackHasOccurred );
-                        lastLogTime = new Date();
+                        lastLogTime = Instant.now();
                     }
                     }
                 }
                 }
                 LOGGER.debug( "read return code in " + TimeDuration.fromCurrent( startTime ).asCompactString() );
                 LOGGER.debug( "read return code in " + TimeDuration.fromCurrent( startTime ).asCompactString() );
@@ -804,7 +804,7 @@ public class NMASCrOperator implements CrOperator
 
 
     private class NMASSessionThread extends Thread
     private class NMASSessionThread extends Thread
     {
     {
-        private volatile Date lastActivityTimestamp = new Date();
+        private volatile Instant lastActivityTimestamp = Instant.now();
         private volatile NMASThreadState loginState = NMASThreadState.NEW;
         private volatile NMASThreadState loginState = NMASThreadState.NEW;
         private volatile boolean loginResultReady = false;
         private volatile boolean loginResultReady = false;
         private volatile com.novell.security.nmas.client.NMASLoginResult loginResult = null;
         private volatile com.novell.security.nmas.client.NMASLoginResult loginResult = null;
@@ -832,7 +832,7 @@ public class NMASCrOperator implements CrOperator
             return this.loginState;
             return this.loginState;
         }
         }
 
 
-        public Date getLastActivityTimestamp( )
+        public Instant getLastActivityTimestamp( )
         {
         {
             return lastActivityTimestamp;
             return lastActivityTimestamp;
         }
         }
@@ -841,7 +841,7 @@ public class NMASCrOperator implements CrOperator
         {
         {
             this.loginResult = paramNMASLoginResult;
             this.loginResult = paramNMASLoginResult;
             this.loginResultReady = true;
             this.loginResultReady = true;
-            this.lastActivityTimestamp = new Date();
+            this.lastActivityTimestamp = Instant.now();
         }
         }
 
 
         public final synchronized com.novell.security.nmas.client.NMASLoginResult getLoginResult( )
         public final synchronized com.novell.security.nmas.client.NMASLoginResult getLoginResult( )
@@ -858,7 +858,7 @@ public class NMASCrOperator implements CrOperator
                 }
                 }
             }
             }
 
 
-            lastActivityTimestamp = new Date();
+            lastActivityTimestamp = Instant.now();
             return this.loginResult;
             return this.loginResult;
         }
         }
 
 
@@ -882,7 +882,7 @@ public class NMASCrOperator implements CrOperator
             setLoginState( NMASThreadState.NEW );
             setLoginState( NMASThreadState.NEW );
             setDaemon( true );
             setDaemon( true );
             setName( PwmConstants.PWM_APP_NAME + "-NMASSessionThread thread id=" + threadID );
             setName( PwmConstants.PWM_APP_NAME + "-NMASSessionThread thread id=" + threadID );
-            lastActivityTimestamp = new Date();
+            lastActivityTimestamp = Instant.now();
             start();
             start();
         }
         }
 
 
@@ -909,19 +909,19 @@ public class NMASCrOperator implements CrOperator
             {
             {
                 return;
                 return;
             }
             }
-            lastActivityTimestamp = new Date();
+            lastActivityTimestamp = Instant.now();
             if ( this.ldapConn == null )
             if ( this.ldapConn == null )
             {
             {
                 setLoginState( NMASThreadState.COMPLETED );
                 setLoginState( NMASThreadState.COMPLETED );
                 setLoginResult( new com.novell.security.nmas.client.NMASLoginResult( -1681 ) );
                 setLoginResult( new com.novell.security.nmas.client.NMASLoginResult( -1681 ) );
-                lastActivityTimestamp = new Date();
+                lastActivityTimestamp = Instant.now();
                 return;
                 return;
             }
             }
 
 
             try
             try
             {
             {
                 setLoginState( NMASThreadState.BIND );
                 setLoginState( NMASThreadState.BIND );
-                lastActivityTimestamp = new Date();
+                lastActivityTimestamp = Instant.now();
                 try
                 try
                 {
                 {
                     this.ldapConn.bind(
                     this.ldapConn.bind(
@@ -950,9 +950,9 @@ public class NMASCrOperator implements CrOperator
                 }
                 }
 
 
                 setLoginState( NMASThreadState.COMPLETED );
                 setLoginState( NMASThreadState.COMPLETED );
-                lastActivityTimestamp = new Date();
+                lastActivityTimestamp = Instant.now();
                 setLoginResult( new com.novell.security.nmas.client.NMASLoginResult( this.callbackHandler.awaitRetCode(), this.ldapConn ) );
                 setLoginResult( new com.novell.security.nmas.client.NMASLoginResult( this.callbackHandler.awaitRetCode(), this.ldapConn ) );
-                lastActivityTimestamp = new Date();
+                lastActivityTimestamp = Instant.now();
             }
             }
             catch ( LDAPException e )
             catch ( LDAPException e )
             {
             {
@@ -974,7 +974,7 @@ public class NMASCrOperator implements CrOperator
                         = new com.novell.security.nmas.client.NMASLoginResult( this.callbackHandler.awaitRetCode(), e );
                         = new com.novell.security.nmas.client.NMASLoginResult( this.callbackHandler.awaitRetCode(), e );
                 setLoginResult( localNMASLoginResult );
                 setLoginResult( localNMASLoginResult );
             }
             }
-            lastActivityTimestamp = new Date();
+            lastActivityTimestamp = Instant.now();
         }
         }
 
 
         public void abort( )
         public void abort( )

+ 5 - 3
server/src/main/java/password/pwm/util/queue/SmsQueueManager.java

@@ -62,7 +62,6 @@ import java.util.Collections;
 import java.util.LinkedHashMap;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.List;
 import java.util.Map;
 import java.util.Map;
-import java.util.concurrent.TimeUnit;
 import java.util.regex.Matcher;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import java.util.regex.Pattern;
 
 
@@ -127,8 +126,11 @@ public class SmsQueueManager implements PwmService
 
 
         final WorkQueueProcessor.Settings settings = WorkQueueProcessor.Settings.builder()
         final WorkQueueProcessor.Settings settings = WorkQueueProcessor.Settings.builder()
                 .maxEvents( Integer.parseInt( pwmApplication.getConfig().readAppProperty( AppProperty.QUEUE_SMS_MAX_COUNT ) ) )
                 .maxEvents( Integer.parseInt( pwmApplication.getConfig().readAppProperty( AppProperty.QUEUE_SMS_MAX_COUNT ) ) )
-                .retryDiscardAge( new TimeDuration( pwmApplication.getConfig().readSettingAsLong( PwmSetting.SMS_MAX_QUEUE_AGE ), TimeUnit.SECONDS ) )
-                .retryInterval( new TimeDuration( Long.parseLong( pwmApplication.getConfig().readAppProperty( AppProperty.QUEUE_SMS_RETRY_TIMEOUT_MS ) ) ) )
+                .retryDiscardAge( TimeDuration.of( pwmApplication.getConfig().readSettingAsLong( PwmSetting.SMS_MAX_QUEUE_AGE ), TimeDuration.Unit.SECONDS ) )
+                .retryInterval( TimeDuration.of(
+                        Long.parseLong( pwmApplication.getConfig().readAppProperty( AppProperty.QUEUE_SMS_RETRY_TIMEOUT_MS ) ),
+                        TimeDuration.Unit.MILLISECONDS )
+                )
                 .build();
                 .build();
 
 
         final LocalDBStoredQueue localDBStoredQueue = LocalDBStoredQueue.createLocalDBStoredQueue( pwmApplication, pwmApplication.getLocalDB(), LocalDB.DB.SMS_QUEUE );
         final LocalDBStoredQueue localDBStoredQueue = LocalDBStoredQueue.createLocalDBStoredQueue( pwmApplication, pwmApplication.getLocalDB(), LocalDB.DB.SMS_QUEUE );

+ 1 - 1
server/src/main/java/password/pwm/util/secure/SecureEngine.java

@@ -512,7 +512,7 @@ public class SecureEngine
                 final TimeDuration executionDuration = TimeDuration.fromCurrent( startTime );
                 final TimeDuration executionDuration = TimeDuration.fromCurrent( startTime );
                 outputData.write( "processed " + testIterations + " iterations using "
                 outputData.write( "processed " + testIterations + " iterations using "
                         + alg.toString() + " (" + alg.getLabel() + ") in "
                         + alg.toString() + " (" + alg.getLabel() + ") in "
-                        + executionDuration.getTotalMilliseconds() + "ms" );
+                        + executionDuration.asMillis() + "ms" );
                 outputData.write( "\n" );
                 outputData.write( "\n" );
             }
             }
         }
         }

+ 1 - 2
server/src/main/java/password/pwm/ws/server/rest/RestFormSigningServer.java

@@ -51,7 +51,6 @@ import java.io.IOException;
 import java.io.Serializable;
 import java.io.Serializable;
 import java.time.Instant;
 import java.time.Instant;
 import java.util.Map;
 import java.util.Map;
-import java.util.concurrent.TimeUnit;
 
 
 @WebServlet(
 @WebServlet(
         urlPatterns = {
         urlPatterns = {
@@ -129,7 +128,7 @@ public class RestFormSigningServer extends RestServlet
     public static Map<String, String> readSignedFormValue( final PwmApplication pwmApplication, final String input ) throws PwmUnrecoverableException
     public static Map<String, String> readSignedFormValue( final PwmApplication pwmApplication, final String input ) throws PwmUnrecoverableException
     {
     {
         final Integer maxAgeSeconds = Integer.parseInt( pwmApplication.getConfig().readAppProperty( AppProperty.WS_REST_SERVER_SIGNING_FORM_TIMEOUT_SECONDS ) );
         final Integer maxAgeSeconds = Integer.parseInt( pwmApplication.getConfig().readAppProperty( AppProperty.WS_REST_SERVER_SIGNING_FORM_TIMEOUT_SECONDS ) );
-        final TimeDuration maxAge = new TimeDuration( maxAgeSeconds, TimeUnit.SECONDS );
+        final TimeDuration maxAge = TimeDuration.of( maxAgeSeconds, TimeDuration.Unit.SECONDS );
         final SignedFormData signedFormData = pwmApplication.getSecureService().decryptObject( input, SignedFormData.class );
         final SignedFormData signedFormData = pwmApplication.getSecureService().decryptObject( input, SignedFormData.class );
         if ( signedFormData != null )
         if ( signedFormData != null )
         {
         {

+ 67 - 0
server/src/test/java/password/pwm/util/java/TimeDurationTest.java

@@ -0,0 +1,67 @@
+/*
+ * Password Management Servlets (PWM)
+ * http://www.pwm-project.org
+ *
+ * Copyright (c) 2006-2009 Novell, Inc.
+ * Copyright (c) 2009-2018 The PWM Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+package password.pwm.util.java;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class TimeDurationTest
+{
+    @Test
+    public void testConversions() {
+        Assert.assertEquals( TimeDuration.SECOND.asMillis(), 1000 );
+        Assert.assertEquals( TimeDuration.SECONDS_10.asMillis(), 10 * 1000 );
+        Assert.assertEquals( TimeDuration.SECONDS_30.asMillis(), 30 * 1000 );
+        Assert.assertEquals( TimeDuration.MINUTE.asMillis(), 60 * 1000 );
+        Assert.assertEquals( TimeDuration.HOUR.asMillis(), 60 * 60 * 1000 );
+        Assert.assertEquals( TimeDuration.DAY.asMillis(), 24 * 60 * 60 * 1000 );
+
+        final TimeDuration timeDuration_15m = TimeDuration.of( 15, TimeDuration.Unit.MINUTES );
+        final TimeDuration timeDuration_37h = TimeDuration.of( 37, TimeDuration.Unit.HOURS );
+
+        Assert.assertEquals( timeDuration_15m.asMillis(), 15 * 60 * 1000 );
+        Assert.assertEquals( timeDuration_15m.as( TimeDuration.Unit.MILLISECONDS ), 15 * 60 * 1000 );
+        Assert.assertEquals( timeDuration_15m.as( TimeDuration.Unit.SECONDS ), 15 * 60 );
+        Assert.assertEquals( timeDuration_15m.as( TimeDuration.Unit.MINUTES ), 15 );
+        Assert.assertEquals( timeDuration_15m.as( TimeDuration.Unit.HOURS ), 0 );
+        Assert.assertEquals( timeDuration_15m.as( TimeDuration.Unit.DAYS ), 0 );
+
+        Assert.assertTrue( timeDuration_37h.isLongerThan( timeDuration_15m ) );
+        Assert.assertFalse( timeDuration_37h.isShorterThan( timeDuration_15m ) );
+        Assert.assertFalse( timeDuration_15m.isLongerThan( timeDuration_37h ) );
+        Assert.assertEquals( timeDuration_15m, timeDuration_15m );
+        Assert.assertNotEquals( timeDuration_15m, timeDuration_37h );
+
+        Assert.assertEquals( TimeDuration.MILLISECOND.add( TimeDuration.MILLISECOND ), TimeDuration.MILLISECONDS_2 );
+        Assert.assertEquals( TimeDuration.MILLISECONDS_2.subtract( TimeDuration.MILLISECOND ), TimeDuration.MILLISECOND );
+
+        Assert.assertEquals( TimeDuration.MILLISECOND, TimeDuration.MILLISECOND );
+        Assert.assertEquals( TimeDuration.SECOND, TimeDuration.SECOND );
+        Assert.assertEquals( TimeDuration.SECONDS_10, TimeDuration.SECONDS_10 );
+        Assert.assertEquals( TimeDuration.SECONDS_30, TimeDuration.SECONDS_30 );
+        Assert.assertEquals( TimeDuration.MINUTE, TimeDuration.MINUTE );
+        Assert.assertEquals( TimeDuration.HOUR, TimeDuration.HOUR);
+        Assert.assertEquals( TimeDuration.DAY, TimeDuration.DAY);
+    }
+}

+ 2 - 2
webapp/src/main/webapp/public/reference/timezones.jsp

@@ -35,11 +35,11 @@
     <tbody>
     <tbody>
     <% for (final String tzID : TimeZone.getAvailableIDs()) { %>
     <% for (final String tzID : TimeZone.getAvailableIDs()) { %>
     <% final TimeZone tz = TimeZone.getTimeZone(tzID); %>
     <% final TimeZone tz = TimeZone.getTimeZone(tzID); %>
-    <% final TimeDuration offset = new TimeDuration(0,tz.getOffset(System.currentTimeMillis())); %>
+    <% final TimeDuration offset = TimeDuration.of(tz.getOffset(System.currentTimeMillis()), TimeDuration.Unit.MILLISECONDS); %>
     <tr>
     <tr>
         <td><%=tzID%></td>
         <td><%=tzID%></td>
         <td><%=tz.getDisplayName()%></td>
         <td><%=tz.getDisplayName()%></td>
-        <td><%=offset.getHours()%>h <%=offset.getMinutes()%>m <%=offset.getSeconds()%>s</td>
+        <td><%=offset.as( TimeDuration.Unit.HOURS)%>h <%=offset.as( TimeDuration.Unit.MINUTES)%>m <%=offset.as( TimeDuration.Unit.SECONDS)%>s</td>
     </tr>
     </tr>
     <% } %>
     <% } %>
     </tbody>
     </tbody>