Forráskód Böngészése

TimeDuration.pause refactoring

jrivard@gmail.com 6 éve
szülő
commit
589e2b3ed2
22 módosított fájl, 59 hozzáadás és 225 törlés
  1. 5 4
      server/src/main/java/password/pwm/config/Configuration.java
  2. 1 2
      server/src/main/java/password/pwm/health/HealthMonitor.java
  3. 1 4
      server/src/main/java/password/pwm/http/ContextManager.java
  4. 3 5
      server/src/main/java/password/pwm/http/servlet/forgottenpw/ForgottenPasswordServlet.java
  5. 14 36
      server/src/main/java/password/pwm/http/servlet/helpdesk/HelpdeskServlet.java
  6. 1 1
      server/src/main/java/password/pwm/http/servlet/peoplesearch/PeopleSearchDataReader.java
  7. 1 2
      server/src/main/java/password/pwm/svc/intruder/IntruderManager.java
  8. 1 1
      server/src/main/java/password/pwm/svc/report/ReportService.java
  9. 3 6
      server/src/main/java/password/pwm/svc/wordlist/AbstractWordlist.java
  10. 0 4
      server/src/main/java/password/pwm/svc/wordlist/SharedHistoryManager.java
  11. 2 2
      server/src/main/java/password/pwm/util/TransactionSizeCalculator.java
  12. 0 3
      server/src/main/java/password/pwm/util/cli/commands/ExportAuditCommand.java
  13. 0 2
      server/src/main/java/password/pwm/util/cli/commands/ExportResponsesCommand.java
  14. 0 2
      server/src/main/java/password/pwm/util/cli/commands/ExportStatsCommand.java
  15. 0 3
      server/src/main/java/password/pwm/util/cli/commands/TokenInfoCommand.java
  16. 0 48
      server/src/main/java/password/pwm/util/java/JavaHelper.java
  17. 0 85
      server/src/main/java/password/pwm/util/java/Sleeper.java
  18. 20 3
      server/src/main/java/password/pwm/util/java/TimeDuration.java
  19. 3 6
      server/src/main/java/password/pwm/util/localdb/WorkQueueProcessor.java
  20. 1 1
      server/src/main/java/password/pwm/util/logging/LocalDBLogger.java
  21. 1 2
      server/src/main/java/password/pwm/util/operations/cr/NMASCrOperator.java
  22. 2 3
      server/src/test/java/password/pwm/util/localdb/LocalDBStoredQueueExtendedTest.java

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

@@ -955,12 +955,12 @@ public class Configuration implements SettingReader
 
     public String readAppProperty( final AppProperty property )
     {
-        final Map<String, String> configurationValues = StringUtil.convertStringListToNameValuePair( this.readSettingAsStringArray( PwmSetting.APP_PROPERTY_OVERRIDES ), "=" );
-        if ( configurationValues.containsKey( property.getKey() ) )
+        if ( dataCache.appPropertyOverrides == null )
         {
-            return configurationValues.get( property.getKey() );
+            dataCache.appPropertyOverrides = StringUtil.convertStringListToNameValuePair( this.readSettingAsStringArray( PwmSetting.APP_PROPERTY_OVERRIDES ), "=" );
         }
-        return property.getDefaultValue();
+
+        return dataCache.appPropertyOverrides.getOrDefault( property.getKey(), property.getDefaultValue() );
     }
 
     private Convenience helper = new Convenience();
@@ -1040,6 +1040,7 @@ public class Configuration implements SettingReader
         private final Map<PwmSetting, StoredValue> settings = new EnumMap<>( PwmSetting.class );
         private final Map<String, Map<Locale, String>> customText = new LinkedHashMap<>();
         private final Map<ProfileType, Map<String, Profile>> profileCache = new LinkedHashMap<>();
+        private Map<String, String> appPropertyOverrides = null;
     }
 
     public Map<AppProperty, String> readAllNonDefaultAppProperties( )

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

@@ -28,7 +28,6 @@ import password.pwm.PwmApplication;
 import password.pwm.error.PwmException;
 import password.pwm.svc.PwmService;
 import password.pwm.util.PwmScheduler;
-import password.pwm.util.java.JavaHelper;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.logging.PwmLogger;
 
@@ -153,7 +152,7 @@ public class HealthMonitor implements PwmService
             final Instant startTime = Instant.now();
             LOGGER.trace( () ->  "begin force immediate check" );
             final Future future = pwmApplication.getPwmScheduler().scheduleFutureJob( new ImmediateJob(), executorService, TimeDuration.ZERO );
-            JavaHelper.pause( settings.getMaximumForceCheckWait().asMillis(), 500, o -> future.isDone() );
+            settings.getMaximumForceCheckWait().pause( future::isDone );
             LOGGER.trace( () ->  "exit force immediate check, done=" + future.isDone() + ", " + TimeDuration.compactFromCurrent( startTime ) );
         }
 

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

@@ -561,10 +561,7 @@ public class ContextManager implements Serializable
 
             LOGGER.trace( () -> "waiting up to " + maxRequestWaitTime.asCompactString()
                     + " for " + startingRequetsInProgress  + " requests to complete." );
-            JavaHelper.pause(
-                    maxRequestWaitTime.asMillis(),
-                    10,
-                    o -> pwmApplication.getInprogressRequests().get() == 0
+            maxRequestWaitTime.pause( TimeDuration.of( 10, TimeDuration.Unit.MILLISECONDS ), () -> pwmApplication.getInprogressRequests().get() == 0
             );
 
             final int requestsInPrgoress = pwmApplication.getInprogressRequests().get();

+ 3 - 5
server/src/main/java/password/pwm/http/servlet/forgottenpw/ForgottenPasswordServlet.java

@@ -84,6 +84,7 @@ import password.pwm.util.PostChangePasswordAction;
 import password.pwm.util.form.FormUtility;
 import password.pwm.util.java.JavaHelper;
 import password.pwm.util.java.JsonUtil;
+import password.pwm.util.java.TimeDuration;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.operations.ActionExecutor;
 import password.pwm.util.operations.PasswordUtility;
@@ -831,8 +832,8 @@ public class ForgottenPasswordServlet extends ControlledPwmServlet
 
         {
             LOGGER.trace( pwmRequest, () -> "preparing to send a new token to user" );
-            final long delayTime = Long.parseLong( pwmRequest.getConfig().readAppProperty( AppProperty.TOKEN_RESEND_DELAY_MS ) );
-            JavaHelper.pause( delayTime );
+            final long delayTimeMs = Long.parseLong( pwmRequest.getConfig().readAppProperty( AppProperty.TOKEN_RESEND_DELAY_MS ) );
+            TimeDuration.of( delayTimeMs, TimeDuration.Unit.MILLISECONDS ).pause();
         }
 
         {
@@ -858,9 +859,6 @@ public class ForgottenPasswordServlet extends ControlledPwmServlet
         {
             final FormConfiguration formConfiguration = forgottenPasswordBean.getAttributeForm().iterator().next();
 
-            // add a bit of jitter to pretend like we're checking a data source
-            JavaHelper.pause( 300 + pwmRequest.getPwmApplication().getSecureService().pwmRandom().nextInt( 700 ) );
-
             if ( forgottenPasswordBean.getUserSearchValues() != null )
             {
                 final List<FormConfiguration> formConfigurations = pwmRequest.getConfig().readSettingAsForm( PwmSetting.FORGOTTEN_PASSWORD_SEARCH_FORM );

+ 14 - 36
server/src/main/java/password/pwm/http/servlet/helpdesk/HelpdeskServlet.java

@@ -644,8 +644,6 @@ public class HelpdeskServlet extends ControlledPwmServlet
     {
         final HelpdeskProfile helpdeskProfile = getHelpdeskProfile( pwmRequest );
 
-        final Instant startTime = Instant.now();
-
         final HelpdeskVerificationRequestBean helpdeskVerificationRequestBean = JsonUtil.deserialize(
                 pwmRequest.readRequestBodyAsString(),
                 HelpdeskVerificationRequestBean.class
@@ -714,19 +712,7 @@ public class HelpdeskServlet extends ControlledPwmServlet
                 pwmRequest.getPwmApplication().getAuditManager().submit( auditRecord );
             }
 
-            // add a delay to prevent continuous checks
-            final long delayMs = Long.parseLong( pwmRequest.getConfig().readAppProperty( AppProperty.HELPDESK_VERIFICATION_INVALID_DELAY_MS ) );
-            while ( TimeDuration.fromCurrent( startTime ).isShorterThan( delayMs ) )
-            {
-                JavaHelper.pause( 100 );
-            }
-
-            final HelpdeskVerificationResponseBean responseBean = new HelpdeskVerificationResponseBean(
-                    passed,
-                    verificationStateBean.toClientString( pwmRequest.getPwmApplication() )
-            );
-            final RestResultBean restResultBean = RestResultBean.withData( responseBean );
-            pwmRequest.outputJsonResult( restResultBean );
+            return outputVerificationResponseBean( pwmRequest, passed, verificationStateBean );
         }
         catch ( PwmOperationalException e )
         {
@@ -848,7 +834,6 @@ public class HelpdeskServlet extends ControlledPwmServlet
     )
             throws IOException, PwmUnrecoverableException, ServletException
     {
-        final Instant startTime = Instant.now();
         final HelpdeskVerificationRequestBean helpdeskVerificationRequestBean = JsonUtil.deserialize(
                 pwmRequest.readRequestBodyAsString(),
                 HelpdeskVerificationRequestBean.class
@@ -915,20 +900,7 @@ public class HelpdeskServlet extends ControlledPwmServlet
             pwmRequest.getPwmApplication().getAuditManager().submit( auditRecord );
         }
 
-        // add a delay to prevent continuous checks
-        final long delayMs = Long.parseLong( pwmRequest.getConfig().readAppProperty( AppProperty.HELPDESK_VERIFICATION_INVALID_DELAY_MS ) );
-        while ( TimeDuration.fromCurrent( startTime ).isShorterThan( delayMs ) )
-        {
-            JavaHelper.pause( 100 );
-        }
-
-        final HelpdeskVerificationResponseBean responseBean = new HelpdeskVerificationResponseBean(
-                passed,
-                verificationStateBean.toClientString( pwmRequest.getPwmApplication() )
-        );
-        final RestResultBean restResultBean = RestResultBean.withData( responseBean );
-        pwmRequest.outputJsonResult( restResultBean );
-        return ProcessStatus.Halt;
+        return outputVerificationResponseBean( pwmRequest, passed, verificationStateBean );
     }
 
     @ActionHandler( action = "clearOtpSecret" )
@@ -1052,7 +1024,6 @@ public class HelpdeskServlet extends ControlledPwmServlet
             throws IOException, PwmUnrecoverableException, ServletException
     {
         final HelpdeskProfile helpdeskProfile = getHelpdeskProfile( pwmRequest );
-        final Instant startTime = Instant.now();
         final String bodyString = pwmRequest.readRequestBodyAsString();
         final HelpdeskVerificationRequestBean helpdeskVerificationRequestBean = JsonUtil.deserialize(
                 bodyString,
@@ -1132,12 +1103,19 @@ public class HelpdeskServlet extends ControlledPwmServlet
             pwmRequest.getPwmApplication().getAuditManager().submit( auditRecord );
         }
 
+        return outputVerificationResponseBean( pwmRequest, passed, verificationStateBean );
+    }
+
+    private ProcessStatus outputVerificationResponseBean(
+            final PwmRequest pwmRequest,
+            final boolean passed,
+            final HelpdeskVerificationStateBean verificationStateBean
+    )
+            throws IOException, PwmUnrecoverableException
+    {
         // add a delay to prevent continuous checks
-        final long delayMs = Long.parseLong( pwmRequest.getConfig().readAppProperty( AppProperty.HELPDESK_VERIFICATION_INVALID_DELAY_MS ) );
-        while ( TimeDuration.fromCurrent( startTime ).isShorterThan( delayMs ) )
-        {
-            JavaHelper.pause( 100 );
-        }
+        final long delayMs = JavaHelper.silentParseLong( pwmRequest.getConfig().readAppProperty( AppProperty.HELPDESK_VERIFICATION_INVALID_DELAY_MS ), 500 );
+        TimeDuration.of( delayMs, TimeDuration.Unit.MILLISECONDS ).jitterPause( pwmRequest.getPwmApplication().getSecureService(), 0.3f );
 
         final HelpdeskVerificationResponseBean responseBean = new HelpdeskVerificationResponseBean(
                 passed,

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

@@ -998,7 +998,7 @@ class PeopleSearchDataReader
         executor.execute( job );
 
         final TimeDuration maxDuration = peopleSearchConfiguration.getExportCsvMaxDuration();
-        JavaHelper.pause( maxDuration.asMillis(), 1000, o -> ( executor.getQueue().size() + executor.getActiveCount() <= 0 ) );
+        maxDuration.pause( () -> executor.getQueue().size() + executor.getActiveCount() <= 0 );
 
         final TimeDuration timeDuration = TimeDuration.fromCurrent( startTime );
         LOGGER.trace( pwmRequest, () -> "completed csv export of " + rowCounter.get() + " records in " + timeDuration.asCompactString() );

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

@@ -445,7 +445,6 @@ public class IntruderManager implements PwmService
         delayPenalty( manager.readIntruderRecord( subject ), sessionLabel == null ? null : sessionLabel );
     }
 
-
     private void delayPenalty( final IntruderRecord intruderRecord, final SessionLabel sessionLabel )
     {
         int points = 0;
@@ -468,7 +467,7 @@ public class IntruderManager implements PwmService
                 LOGGER.trace( sessionLabel, () -> "delaying response " + finalDelay + "ms due to intruder record: " + JsonUtil.serialize( intruderRecord ) );
             }
 
-            JavaHelper.pause( delayPenalty );
+            TimeDuration.of( delayPenalty, TimeDuration.Unit.MILLISECONDS ).pause();
         }
     }
 

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

@@ -557,7 +557,7 @@ public class ReportService implements PwmService
 
                             if ( pauseBetweenIterations )
                             {
-                                JavaHelper.pause( avgTracker.avgAsLong() );
+                                TimeDuration.of( avgTracker.avgAsLong(), TimeDuration.Unit.MILLISECONDS ).pause();
                             }
                         }
                         catch ( Exception e )

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

@@ -169,13 +169,10 @@ abstract class AbstractWordlist implements Wordlist, PwmService
         {
             executorService.shutdown();
 
+            JavaHelper.closeAndWaitExecutor( executorService, closeWaitTime );
             if ( backgroundImportRunning.get() )
             {
-                JavaHelper.pause( closeWaitTime.asMillis(), 50, o -> !backgroundImportRunning.get() );
-                if ( backgroundImportRunning.get() )
-                {
-                    getLogger().warn( "background thread still running after waiting " + closeWaitTime.asCompactString() );
-                }
+                getLogger().warn( "background thread still running after waiting " + closeWaitTime.asCompactString() );
             }
         }
     }
@@ -327,7 +324,7 @@ abstract class AbstractWordlist implements Wordlist, PwmService
         inhibitBackgroundImportFlag.set( true );
         try
         {
-            JavaHelper.pause( 10_000, 100, o -> !backgroundImportRunning.get() );
+            TimeDuration.of( 10, TimeDuration.Unit.SECONDS ).pause( () -> !backgroundImportRunning.get() );
             if ( backgroundImportRunning.get() )
             {
                 throw PwmUnrecoverableException.newException( PwmError.ERROR_WORDLIST_IMPORT_ERROR, "unable to cancel background operation in progress" );

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

@@ -34,7 +34,6 @@ import password.pwm.health.HealthRecord;
 import password.pwm.svc.PwmService;
 import password.pwm.util.PwmScheduler;
 import password.pwm.util.java.JavaHelper;
-import password.pwm.util.java.Sleeper;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.localdb.LocalDB;
 import password.pwm.util.localdb.LocalDBException;
@@ -328,8 +327,6 @@ public class SharedHistoryManager implements PwmService
 
     private class CleanerTask extends TimerTask
     {
-        final Sleeper sleeper = new Sleeper( 10 );
-
         private CleanerTask( )
         {
         }
@@ -400,7 +397,6 @@ public class SharedHistoryManager implements PwmService
                     {
                         localOldestEntry = timeStamp < localOldestEntry ? timeStamp : localOldestEntry;
                     }
-                    sleeper.sleep();
                 }
             }
             finally

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

@@ -24,7 +24,6 @@ package password.pwm.util;
 
 import lombok.Builder;
 import lombok.Value;
-import password.pwm.util.java.JavaHelper;
 import password.pwm.util.java.TimeDuration;
 
 import java.util.Objects;
@@ -56,7 +55,8 @@ public class TransactionSizeCalculator
     @SuppressWarnings( "ResultOfMethodCallIgnored" )
     public void pause( )
     {
-        JavaHelper.pause( Math.min( lastDuration, settings.getDurationGoal().asMillis() * 2 ) );
+        final long pauseTimeMs = Math.min( lastDuration, settings.getDurationGoal().asMillis() * 2 );
+        TimeDuration.of( pauseTimeMs, TimeDuration.Unit.MILLISECONDS ).pause();
     }
 
     public void recordLastTransactionDuration( final TimeDuration duration )

+ 0 - 3
server/src/main/java/password/pwm/util/cli/commands/ExportAuditCommand.java

@@ -26,7 +26,6 @@ import password.pwm.PwmApplication;
 import password.pwm.PwmConstants;
 import password.pwm.svc.event.AuditService;
 import password.pwm.util.cli.CliParameters;
-import password.pwm.util.java.JavaHelper;
 import password.pwm.util.java.TimeDuration;
 
 import java.io.File;
@@ -43,7 +42,6 @@ public class ExportAuditCommand extends AbstractCliCommand
         final PwmApplication pwmApplication = cliEnvironment.getPwmApplication();
         final AuditService auditManager = new AuditService();
         auditManager.init( pwmApplication );
-        JavaHelper.pause( 1000 );
 
         final File outputFile = ( File ) cliEnvironment.getOptions().get( CliParameters.REQUIRED_NEW_OUTPUT_FILE.getName() );
 
@@ -53,7 +51,6 @@ public class ExportAuditCommand extends AbstractCliCommand
         try ( FileOutputStream fileOutputStream = new FileOutputStream( outputFile, true ) )
         {
             counter = auditManager.outputVaultToCsv( fileOutputStream, PwmConstants.DEFAULT_LOCALE, false );
-            fileOutputStream.close();
         }
         out( "completed writing " + counter + " rows of audit output in " + TimeDuration.fromCurrent( startTime ).asLongString() );
     }

+ 0 - 2
server/src/main/java/password/pwm/util/cli/commands/ExportResponsesCommand.java

@@ -31,7 +31,6 @@ import password.pwm.bean.UserIdentity;
 import password.pwm.ldap.search.SearchConfiguration;
 import password.pwm.ldap.search.UserSearchEngine;
 import password.pwm.util.cli.CliParameters;
-import password.pwm.util.java.JavaHelper;
 import password.pwm.util.java.JsonUtil;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.ws.server.rest.RestChallengesServer;
@@ -53,7 +52,6 @@ public class ExportResponsesCommand extends AbstractCliCommand
         final PwmApplication pwmApplication = cliEnvironment.getPwmApplication();
 
         final File outputFile = ( File ) cliEnvironment.getOptions().get( CliParameters.REQUIRED_NEW_OUTPUT_FILE.getName() );
-        JavaHelper.pause( 2000 );
 
         final long startTime = System.currentTimeMillis();
         final UserSearchEngine userSearchEngine = pwmApplication.getUserSearchEngine();

+ 0 - 2
server/src/main/java/password/pwm/util/cli/commands/ExportStatsCommand.java

@@ -25,7 +25,6 @@ package password.pwm.util.cli.commands;
 import password.pwm.PwmApplication;
 import password.pwm.svc.stats.StatisticsManager;
 import password.pwm.util.cli.CliParameters;
-import password.pwm.util.java.JavaHelper;
 import password.pwm.util.java.TimeDuration;
 
 import java.io.File;
@@ -42,7 +41,6 @@ public class ExportStatsCommand extends AbstractCliCommand
     {
         final PwmApplication pwmApplication = cliEnvironment.getPwmApplication();
         final StatisticsManager statsManger = pwmApplication.getStatisticsManager();
-        JavaHelper.pause( 1000 );
 
         final File outputFile = ( File ) cliEnvironment.getOptions().get( CliParameters.REQUIRED_NEW_OUTPUT_FILE.getName() );
         final long startTime = System.currentTimeMillis();

+ 0 - 3
server/src/main/java/password/pwm/util/cli/commands/TokenInfoCommand.java

@@ -75,9 +75,6 @@ public class TokenInfoCommand extends AbstractCliCommand
                 out( "        value: " + value );
             }
         }
-
-        pwmApplication.shutdown();
-        JavaHelper.pause( 1000 );
     }
 
     @Override

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

@@ -139,54 +139,6 @@ public class JavaHelper
         return out.toString();
     }
 
-    /**
-     * Pause the calling thread the specified amount of time.
-     *
-     * @param sleepTimeMS - a time duration in milliseconds
-     * @return time actually spent sleeping
-     */
-    @CheckReturnValue( when = javax.annotation.meta.When.NEVER )
-    public static long pause( final long sleepTimeMS )
-    {
-        final long startTime = System.currentTimeMillis();
-        final long sliceTime = Math.max( 5, sleepTimeMS / 10 );
-        do
-        {
-            try
-            {
-                final long sleepTime = sleepTimeMS - ( System.currentTimeMillis() - startTime );
-                Thread.sleep( Math.min( sleepTime, sliceTime ) );
-            }
-            catch ( InterruptedException e )
-            {
-                // ignore
-            }
-        }
-        while ( ( System.currentTimeMillis() - startTime ) < sleepTimeMS );
-
-        return System.currentTimeMillis() - startTime;
-    }
-
-    public static long pause(
-            final long sleepTimeMS,
-            final long predicateCheckIntervalMS,
-            final Predicate predicate
-    )
-    {
-        final long startTime = System.currentTimeMillis();
-        final long pauseTime = Math.min( sleepTimeMS, predicateCheckIntervalMS );
-        while ( ( System.currentTimeMillis() - startTime ) < sleepTimeMS )
-        {
-            JavaHelper.pause( pauseTime );
-            if ( predicate.test( null ) )
-            {
-                break;
-            }
-        }
-
-        return System.currentTimeMillis() - startTime;
-    }
-
     public static String binaryArrayToHex( final byte[] buf )
     {
         final char[] hexChars = "0123456789ABCDEF".toCharArray();

+ 0 - 85
server/src/main/java/password/pwm/util/java/Sleeper.java

@@ -1,85 +0,0 @@
-/*
- * 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;
-
-/**
- * Sleep for a percentage of time.  The percentage is determined by the
- * loadFactor, which should be a value from 0-100.  The loadFactor is applied as
- * a percentage of total time that should be spent sleeping.
- *
- * @author Jason D. Rivard
- */
-public class Sleeper
-{
-
-    private static final long MAX_SLEEP_TIME = 500;
-    private static final long STANDARD_SLEEP_TIME = 20;
-
-    private final boolean doSleep;
-    private final int loadFactor;
-
-    private long startTime = System.currentTimeMillis();
-    private long sleepTime = 0;
-
-    public Sleeper( final int loadFactor )
-    {
-        this.loadFactor = loadFactor >= 0 ? loadFactor : 0;
-
-        doSleep = loadFactor > 0;
-    }
-
-    public int getLoadFactor( )
-    {
-        return loadFactor;
-    }
-
-    public void reset( )
-    {
-        startTime = System.currentTimeMillis();
-        sleepTime = 0;
-    }
-
-    public void sleep( )
-    {
-        if ( !doSleep )
-        {
-            return;
-        }
-
-        final long totalRunTime = System.currentTimeMillis() - startTime;
-        final float factor = loadFactor / 100f;
-        final long desiredTotalSleepTime = ( long ) ( totalRunTime * factor );
-
-        final long beginSleepTime = System.currentTimeMillis();
-        while ( sleepTime < desiredTotalSleepTime )
-        {
-            sleepTime += JavaHelper.pause( STANDARD_SLEEP_TIME );
-
-            final long currentSleepTime = System.currentTimeMillis() - beginSleepTime;
-            if ( currentSleepTime > MAX_SLEEP_TIME )
-            {
-                return;
-            }
-        }
-    }
-}

+ 20 - 3
server/src/main/java/password/pwm/util/java/TimeDuration.java

@@ -27,6 +27,8 @@ import lombok.Value;
 import password.pwm.PwmConstants;
 import password.pwm.i18n.Display;
 import password.pwm.util.i18n.LocaleHelper;
+import password.pwm.util.secure.PwmRandom;
+import password.pwm.util.secure.SecureService;
 
 import javax.annotation.CheckReturnValue;
 import javax.annotation.meta.When;
@@ -443,22 +445,37 @@ public class TimeDuration implements Comparable, Serializable
         return pause( this, () -> false );
     }
 
+    /**
+     * Pause the calling thread the specified amount of time.
+     *
+     * @return time actually spent sleeping
+     */
+    @CheckReturnValue( when = When.NEVER )
+    public TimeDuration jitterPause( final SecureService secureService, final float factor )
+    {
+        final PwmRandom pwmRandom = secureService.pwmRandom();
+        final long jitterMs = (long) ( this.ms * factor );
+        final long deviation = pwmRandom.nextBoolean() ? jitterMs + this.ms : jitterMs - this.ms;
+        return pause( TimeDuration.of( deviation, Unit.MILLISECONDS ), () -> false );
+    }
+
     @CheckReturnValue( when = When.NEVER )
     public TimeDuration pause(
             final BooleanSupplier interruptBoolean
     )
     {
-        return pause( this, interruptBoolean );
+        final long interruptMs = JavaHelper.rangeCheck( 5, 1000, this.asMillis() / 100 );
+        return pause( TimeDuration.of( interruptMs, Unit.MILLISECONDS ), interruptBoolean );
     }
 
     @CheckReturnValue( when = When.NEVER )
     public TimeDuration pause(
-            final TimeDuration predicateCheckInterval,
+            final TimeDuration interruptCheckInterval,
             final BooleanSupplier interruptBoolean
     )
     {
         final long startTime = System.currentTimeMillis();
-        final long pauseTime = JavaHelper.rangeCheck( this.asMillis(), this.asMillis(), predicateCheckInterval.asMillis()  );
+        final long pauseTime = JavaHelper.rangeCheck( this.asMillis(), this.asMillis(), interruptCheckInterval.asMillis()  );
 
         while ( ( System.currentTimeMillis() - startTime ) < this.asMillis() && !interruptBoolean.getAsBoolean() )
         {

+ 3 - 6
server/src/main/java/password/pwm/util/localdb/WorkQueueProcessor.java

@@ -154,10 +154,7 @@ public final class WorkQueueProcessor<W extends Serializable>
 
         if ( localWorkerThread.isRunning() )
         {
-            JavaHelper.pause(
-                    settings.getMaxShutdownWaitTime().asMillis(),
-                    CLOSE_RETRY_CYCLE_INTERVAL.asMillis(),
-                    o -> !localWorkerThread.isRunning() );
+            settings.getMaxShutdownWaitTime().pause( CLOSE_RETRY_CYCLE_INTERVAL, () -> !localWorkerThread.isRunning() );
         }
 
         final TimeDuration timeDuration = TimeDuration.fromCurrent( startTime );
@@ -257,7 +254,7 @@ public final class WorkQueueProcessor<W extends Serializable>
                             + ", item=" + itemProcessor.convertToDebugString( itemWrapper.getWorkItem() );
                     throw new PwmOperationalException( new ErrorInformation( PwmError.ERROR_INTERNAL, errorMsg ) );
                 }
-                JavaHelper.pause( SUBMIT_QUEUE_FULL_RETRY_CYCLE_INTERVAL.asMillis() );
+                SUBMIT_QUEUE_FULL_RETRY_CYCLE_INTERVAL.pause();
             }
 
             eldestItem = itemWrapper.getDate();
@@ -358,7 +355,7 @@ public final class WorkQueueProcessor<W extends Serializable>
             // rest until not running for up to 3 seconds....
             if ( running.get() )
             {
-                JavaHelper.pause( 3000, 10, o -> !running.get() );
+                TimeDuration.of( 3, TimeDuration.Unit.SECONDS ).pause( TimeDuration.of( 10, TimeDuration.Unit.MILLISECONDS ), () -> !running.get() );
             }
         }
 

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

@@ -389,7 +389,7 @@ public class LocalDBLogger implements PwmService
                         LOGGER.warn( "discarded event after waiting max buffer wait time of " + settings.getMaxBufferWaitTime().asCompactString() );
                         return;
                     }
-                    JavaHelper.pause( 100 );
+                    TimeDuration.of( 100, TimeDuration.Unit.MILLISECONDS ).pause();
                 }
             }
         }

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

@@ -77,7 +77,6 @@ import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.ldap.LdapOperationsHelper;
 import password.pwm.util.PasswordData;
 import password.pwm.util.java.AtomicLoopIntIncrementer;
-import password.pwm.util.java.JavaHelper;
 import password.pwm.util.java.JsonUtil;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.logging.PwmLogger;
@@ -777,7 +776,7 @@ public class NMASCrOperator implements CrOperator
                 while ( !done && TimeDuration.fromCurrent( startTime ).isShorterThan( maxThreadIdleTime ) )
                 {
                     LOGGER.trace( () -> "attempt to read return code, but isNmasDone=false, will await completion" );
-                    JavaHelper.pause( 10 );
+                    TimeDuration.of( 10, TimeDuration.Unit.SECONDS ).pause();
                     if ( completeOnUnsupportedFailure )
                     {
                         done = unsupportedCallbackHasOccurred || this.isNmasDone();

+ 2 - 3
server/src/test/java/password/pwm/util/localdb/LocalDBStoredQueueExtendedTest.java

@@ -28,8 +28,7 @@ import org.junit.BeforeClass;
 import org.junit.ClassRule;
 import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
-import password.pwm.util.java.JavaHelper;
-import password.pwm.util.secure.PwmRandom;
+import password.pwm.util.java.TimeDuration;
 
 import java.io.File;
 import java.util.Iterator;
@@ -176,7 +175,7 @@ public class LocalDBStoredQueueExtendedTest
         Assert.assertEquals( SIZE, storedQueue.size() );
         for ( int i = 0; i < SIZE; ++i )
         {
-            JavaHelper.pause( PwmRandom.getInstance().nextInt( 1000 ) );
+            TimeDuration.of( 100, TimeDuration.Unit.MILLISECONDS ).pause();
             Assert.assertEquals( SIZE - i, storedQueue.size() );
             storedQueue.remove();
         }