Parcourir la source

LocalDBStoredQueue improvements
static code analysis cleanups

Jason Rivard il y a 4 ans
Parent
commit
826bc1be82
67 fichiers modifiés avec 989 ajouts et 411 suppressions
  1. 2 2
      onejar/src/main/java/password/pwm/onejar/TomcatOnejarRunner.java
  2. 5 5
      pom.xml
  3. 2 1
      pwm-cr/src/main/java/password/pwm/cr/hash/PBKDF2HashMachine.java
  4. 2 9
      pwm-cr/src/main/java/password/pwm/cr/hash/TypicalHashMachine.java
  5. 2 2
      pwm-cr/src/test/java/password/pwm/cr/ChaiXmlResponseSet1Test.java
  6. 2 2
      rest-test-service/src/main/java/password/pwm/resttest/RestTestUtilities.java
  7. 1 1
      server/src/main/java/password/pwm/PwmApplication.java
  8. 2 1
      server/src/main/java/password/pwm/PwmConstants.java
  9. 1 1
      server/src/main/java/password/pwm/bean/UserIdentity.java
  10. 2 9
      server/src/main/java/password/pwm/config/Configuration.java
  11. 1 1
      server/src/main/java/password/pwm/config/function/AbstractUriCertImportFunction.java
  12. 1 1
      server/src/main/java/password/pwm/config/profile/ChallengeProfile.java
  13. 11 4
      server/src/main/java/password/pwm/config/value/BooleanValue.java
  14. 1 1
      server/src/main/java/password/pwm/http/JspUrl.java
  15. 2 9
      server/src/main/java/password/pwm/http/PwmHttpRequestWrapper.java
  16. 1 1
      server/src/main/java/password/pwm/http/filter/ObsoleteUrlFilter.java
  17. 1 4
      server/src/main/java/password/pwm/http/filter/SessionFilter.java
  18. 2 2
      server/src/main/java/password/pwm/http/servlet/AbstractPwmServlet.java
  19. 2 2
      server/src/main/java/password/pwm/http/servlet/ControlledPwmServlet.java
  20. 1 1
      server/src/main/java/password/pwm/http/servlet/LogoutServlet.java
  21. 1 1
      server/src/main/java/password/pwm/http/servlet/ShortcutServlet.java
  22. 2 2
      server/src/main/java/password/pwm/http/servlet/configguide/ConfigGuideForm.java
  23. 1 1
      server/src/main/java/password/pwm/http/servlet/configmanager/DebugItemGenerator.java
  24. 1 1
      server/src/main/java/password/pwm/http/servlet/forgottenpw/RemoteVerificationMethod.java
  25. 1 2
      server/src/main/java/password/pwm/http/servlet/newuser/NewUserFormUtils.java
  26. 3 3
      server/src/main/java/password/pwm/http/servlet/resource/ResourceFileRequest.java
  27. 1 1
      server/src/main/java/password/pwm/http/servlet/resource/ResourceFileServlet.java
  28. 1 3
      server/src/main/java/password/pwm/http/servlet/updateprofile/UpdateProfileUtil.java
  29. 2 3
      server/src/main/java/password/pwm/ldap/LdapBrowser.java
  30. 1 2
      server/src/main/java/password/pwm/ldap/PasswordChangeProgressChecker.java
  31. 4 4
      server/src/main/java/password/pwm/ldap/UserInfoReader.java
  32. 1 2
      server/src/main/java/password/pwm/ldap/search/UserSearchEngine.java
  33. 1 1
      server/src/main/java/password/pwm/svc/email/EmailServerUtil.java
  34. 3 1
      server/src/main/java/password/pwm/svc/report/ReportService.java
  35. 3 2
      server/src/main/java/password/pwm/svc/report/ReportSummaryData.java
  36. 2 2
      server/src/main/java/password/pwm/svc/shorturl/UrlShortenerService.java
  37. 3 4
      server/src/main/java/password/pwm/svc/wordlist/WordlistConfiguration.java
  38. 4 5
      server/src/main/java/password/pwm/svc/wordlist/WordlistImporter.java
  39. 1 1
      server/src/main/java/password/pwm/util/BasicAuthInfo.java
  40. 1 2
      server/src/main/java/password/pwm/util/DailySummaryJob.java
  41. 3 3
      server/src/main/java/password/pwm/util/PropertyConfigurationImporter.java
  42. 3 3
      server/src/main/java/password/pwm/util/cli/MainOptions.java
  43. 1 1
      server/src/main/java/password/pwm/util/db/DatabaseAccessorImpl.java
  44. 1 1
      server/src/main/java/password/pwm/util/java/StringUtil.java
  45. 3 2
      server/src/main/java/password/pwm/util/java/XmlFactory.java
  46. 1 2
      server/src/main/java/password/pwm/util/localdb/AbstractJDBCLocalDB.java
  47. 234 251
      server/src/main/java/password/pwm/util/localdb/LocalDBStoredQueue.java
  48. 2 2
      server/src/main/java/password/pwm/util/logging/LocalDBLoggerSettings.java
  49. 1 1
      server/src/main/java/password/pwm/util/logging/PwmLogger.java
  50. 1 1
      server/src/main/java/password/pwm/util/operations/cr/NMASCrOperator.java
  51. 3 3
      server/src/main/java/password/pwm/util/operations/otp/PasscodeGenerator.java
  52. 3 3
      server/src/main/java/password/pwm/util/password/PasswordCharCounter.java
  53. 3 3
      server/src/main/java/password/pwm/util/password/PwmPasswordRuleUtil.java
  54. 2 2
      server/src/main/java/password/pwm/util/queue/SmsQueueManager.java
  55. 2 11
      server/src/main/java/password/pwm/util/secure/PwmSecurityKey.java
  56. 3 3
      server/src/main/java/password/pwm/util/secure/X509Utils.java
  57. 5 5
      server/src/main/java/password/pwm/ws/server/RestAuthenticationProcessor.java
  58. 1 1
      server/src/main/java/password/pwm/ws/server/RestUtility.java
  59. 1 1
      server/src/test/java/password/pwm/config/stored/ConfigurationCleanerTest.java
  60. 1 2
      server/src/test/java/password/pwm/config/stored/StoredConfigurationTest.java
  61. 1 1
      server/src/test/java/password/pwm/health/HealthMessageTest.java
  62. 1 1
      server/src/test/java/password/pwm/http/filter/RequestInitializationFilterTest.java
  63. 1 1
      server/src/test/java/password/pwm/i18n/NonLocalizedKeyTest.java
  64. 4 4
      server/src/test/java/password/pwm/util/localdb/LocalDBStoredQueueExtendedTest.java
  65. 80 0
      server/src/test/java/password/pwm/util/localdb/LocalDBStoredQueuePositionTest.java
  66. 546 0
      server/src/test/java/password/pwm/util/localdb/LocalDBStoredQueueTest.java
  67. 1 1
      server/src/test/java/password/pwm/util/password/PasswordRuleChecksTest.java

+ 2 - 2
onejar/src/main/java/password/pwm/onejar/TomcatOnejarRunner.java

@@ -275,11 +275,11 @@ public class TomcatOnejarRunner
     {
         try ( InputStream inputStream = TomcatOnejarRunner.class.getClassLoader().getResourceAsStream( srcPath ) )
         {
-            try ( BufferedReader reader = new BufferedReader( new InputStreamReader( inputStream, "UTF8" ) ) )
+            try ( BufferedReader reader = new BufferedReader( new InputStreamReader( inputStream, StandardCharsets.UTF_8 ) ) )
             {
                 String contents = reader.lines().collect( Collectors.joining( "\n" ) );
                 contents = contents.replace( "[[[ROOT_CONTEXT]]]", rootcontext );
-                Files.write( Paths.get( destPath ), contents.getBytes( "UTF8" ) );
+                Files.write( Paths.get( destPath ), contents.getBytes( StandardCharsets.UTF_8 ) );
             }
         }
     }

+ 5 - 5
pom.xml

@@ -232,7 +232,7 @@
                     <dependency>
                         <groupId>com.puppycrawl.tools</groupId>
                         <artifactId>checkstyle</artifactId>
-                        <version>8.35</version>
+                        <version>8.36</version>
                     </dependency>
                 </dependencies>
                 <executions>
@@ -400,13 +400,13 @@
         <dependency>
             <groupId>org.mockito</groupId>
             <artifactId>mockito-core</artifactId>
-            <version>3.5.2</version>
+            <version>3.5.10</version>
             <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>org.assertj</groupId>
             <artifactId>assertj-core</artifactId>
-            <version>3.16.1</version>
+            <version>3.17.1</version>
             <scope>test</scope>
         </dependency>
         <dependency>
@@ -424,13 +424,13 @@
         <dependency>
             <groupId>org.openjdk.jmh</groupId>
             <artifactId>jmh-core</artifactId>
-            <version>1.25</version>
+            <version>1.25.2</version>
             <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>org.openjdk.jmh</groupId>
             <artifactId>jmh-generator-annprocess</artifactId>
-            <version>1.25</version>
+            <version>1.25.2</version>
             <scope>test</scope>
         </dependency>
 

+ 2 - 1
pwm-cr/src/main/java/password/pwm/cr/hash/PBKDF2HashMachine.java

@@ -25,6 +25,7 @@ import password.pwm.cr.api.StoredResponseItem;
 
 import javax.crypto.SecretKeyFactory;
 import javax.crypto.spec.PBEKeySpec;
+import java.nio.charset.StandardCharsets;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
@@ -107,7 +108,7 @@ class PBKDF2HashMachine extends AbstractHashMachine implements ResponseHashMachi
                 }
 
                 final char[] chars = input.toCharArray();
-                final byte[] saltBytes = salt.getBytes( "UTF-8" );
+                final byte[] saltBytes = salt.getBytes( StandardCharsets.UTF_8 );
 
                 spec = new PBEKeySpec( chars, saltBytes, iterations, keyLength );
                 skf = SecretKeyFactory.getInstance( methodName );

+ 2 - 9
pwm-cr/src/main/java/password/pwm/cr/hash/TypicalHashMachine.java

@@ -23,7 +23,7 @@ package password.pwm.cr.hash;
 import net.iharder.Base64;
 import password.pwm.cr.api.StoredResponseItem;
 
-import java.io.UnsupportedEncodingException;
+import java.nio.charset.StandardCharsets;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import java.util.Collections;
@@ -114,14 +114,7 @@ public class TypicalHashMachine extends AbstractHashMachine implements ResponseH
 
 
         byte[] hashedBytes;
-        try
-        {
-            hashedBytes = input.getBytes( "UTF-8" );
-        }
-        catch ( final UnsupportedEncodingException e )
-        {
-            throw new IllegalStateException( "unsupported UTF8 byte encoding: " + e.getMessage() );
-        }
+        hashedBytes = input.getBytes( StandardCharsets.UTF_8 );
 
         switch ( version )
         {

+ 2 - 2
pwm-cr/src/test/java/password/pwm/cr/ChaiXmlResponseSet1Test.java

@@ -31,7 +31,7 @@ import password.pwm.cr.hash.HashFactory;
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.io.Reader;
-import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
 
 @SuppressWarnings( "checkstyle:MultipleStringLiterals" )
 public class ChaiXmlResponseSet1Test
@@ -92,7 +92,7 @@ public class ChaiXmlResponseSet1Test
 
     private static Reader readInputXmlFile()
     {
-        return new InputStreamReader( ChaiXmlResponseSet1Test.class.getResourceAsStream( "ChaiXmlResponseSet1.xml" ), Charset.forName( "UTF8" ) );
+        return new InputStreamReader( ChaiXmlResponseSet1Test.class.getResourceAsStream( "ChaiXmlResponseSet1.xml" ), StandardCharsets.UTF_8 );
     }
 
 

+ 2 - 2
rest-test-service/src/main/java/password/pwm/resttest/RestTestUtilities.java

@@ -27,7 +27,7 @@ import java.io.IOException;
 import java.io.InputStreamReader;
 import java.io.Reader;
 import java.io.StringWriter;
-import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
 
 public class RestTestUtilities
 {
@@ -37,7 +37,7 @@ public class RestTestUtilities
         final StringWriter stringWriter = new StringWriter();
         final Reader readerStream = new InputStreamReader(
                 req.getInputStream(),
-                Charset.forName( "UTF8" )
+                StandardCharsets.UTF_8
         );
 
         try

+ 1 - 1
server/src/main/java/password/pwm/PwmApplication.java

@@ -133,7 +133,7 @@ public class PwmApplication
     private LocalDB localDB;
     private LocalDBLogger localDBLogger;
 
-    private PwmApplication( final PwmEnvironment pwmEnvironment )
+    public PwmApplication( final PwmEnvironment pwmEnvironment )
             throws PwmUnrecoverableException
     {
         this.pwmEnvironment = pwmEnvironment;

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

@@ -27,6 +27,7 @@ import password.pwm.util.java.StringUtil;
 import java.io.InputStream;
 import java.net.URL;
 import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
@@ -72,7 +73,7 @@ public abstract class PwmConstants
     public static final String CONFIGMANAGER_INTRUDER_USERNAME = "ConfigurationManagerLogin";
 
     public static final Locale DEFAULT_LOCALE = new Locale( readPwmConstantsBundle( "locale.defaultLocale" ) );
-    public static final Charset DEFAULT_CHARSET = Charset.forName( "UTF8" );
+    public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
     public static final List<String> HIGHLIGHT_LOCALES = StringUtil.splitAndTrim( readPwmConstantsBundle( "locale.highlightList" ), "," );
 
     public static final CSVFormat DEFAULT_CSV_FORMAT = CSVFormat.DEFAULT;

+ 1 - 1
server/src/main/java/password/pwm/bean/UserIdentity.java

@@ -145,7 +145,7 @@ public class UserIdentity implements Serializable, Comparable<UserIdentity>
 
         try
         {
-            final String input = key.substring( CRYPO_HEADER.length(), key.length() );
+            final String input = key.substring( CRYPO_HEADER.length() );
             final String jsonValue = pwmApplication.getSecureService().decryptStringValue( input );
             return JsonUtil.deserialize( jsonValue, UserIdentity.class );
         }

+ 2 - 9
server/src/main/java/password/pwm/config/Configuration.java

@@ -98,7 +98,7 @@ public class Configuration implements SettingReader
 
     private final ConfigurationSuppliers configurationSuppliers = new ConfigurationSuppliers();
 
-    private DataCache dataCache = new DataCache();
+    private final DataCache dataCache = new DataCache();
 
     public Configuration( final StoredConfiguration storedConfiguration )
     {
@@ -154,14 +154,7 @@ public class Configuration implements SettingReader
     public <E extends Enum<E>> E readSettingAsEnum( final PwmSetting setting, final Class<E> enumClass )
     {
         final StoredValue value = readStoredValue( setting );
-        final E returnValue = ValueTypeConverter.valueToEnum( setting, value, enumClass );
-
-        if ( MessageSendMethod.class.equals( enumClass ) )
-        {
-            deprecatedSettingException( setting, null, ( MessageSendMethod ) returnValue );
-        }
-
-        return returnValue;
+        return ValueTypeConverter.valueToEnum( setting, value, enumClass );
     }
 
     public <E extends Enum<E>> Set<E> readSettingAsOptionList( final PwmSetting setting, final Class<E> enumClass )

+ 1 - 1
server/src/main/java/password/pwm/config/function/AbstractUriCertImportFunction.java

@@ -82,7 +82,7 @@ abstract class AbstractUriCertImportFunction implements SettingUIFunction
         final UserIdentity userIdentity = pwmSession.isAuthenticated() ? pwmSession.getUserInfo().getUserIdentity() : null;
         store( certs, modifier, setting, profile, extraData, userIdentity );
 
-        final StringBuffer returnStr = new StringBuffer();
+        final StringBuilder returnStr = new StringBuilder();
         for ( final X509Certificate loopCert : certs )
         {
             returnStr.append( X509Utils.makeDebugText( loopCert ) );

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

@@ -75,7 +75,7 @@ public class ChallengeProfile implements Profile, Serializable
         this.helpdeskChallengeSet = helpdeskChallengeSet;
         this.minRandomSetup = minRandomSetup;
         this.minHelpdeskRandomsSetup = minHelpdeskRandomSetup;
-        this.userPermissions = userPermissions != null ? Collections.unmodifiableList( userPermissions ) : Collections.<UserPermission>emptyList();
+        this.userPermissions = userPermissions != null ? Collections.unmodifiableList( userPermissions ) : Collections.emptyList();
     }
 
     public static ChallengeProfile readChallengeProfileFromConfig(

+ 11 - 4
server/src/main/java/password/pwm/config/value/BooleanValue.java

@@ -38,13 +38,20 @@ import java.util.Optional;
 
 public class BooleanValue implements StoredValue
 {
+    private static final BooleanValue POSITIVE = new BooleanValue( true );
+    private static final BooleanValue NEGATIVE = new BooleanValue( false );
+
     private final boolean value;
 
-    public BooleanValue( final boolean value )
+    private BooleanValue( final boolean value )
     {
         this.value = value;
     }
 
+    public static BooleanValue of( final boolean input )
+    {
+        return input ? POSITIVE : NEGATIVE;
+    }
 
     public static StoredValueFactory factory( )
     {
@@ -52,7 +59,7 @@ public class BooleanValue implements StoredValue
         {
             public BooleanValue fromJson( final String value )
             {
-                return new BooleanValue( JsonUtil.deserialize( value, Boolean.class ) );
+                return BooleanValue.of( JsonUtil.deserialize( value, Boolean.class ) );
             }
 
             public BooleanValue fromXmlElement( final PwmSetting pwmSetting, final XmlElement settingElement, final PwmSecurityKey input )
@@ -61,9 +68,9 @@ public class BooleanValue implements StoredValue
                 if ( valueElement.isPresent() )
                 {
                     final String value = valueElement.get().getTextTrim();
-                    return new BooleanValue( Boolean.valueOf( value ) );
+                    return BooleanValue.of( Boolean.parseBoolean( value ) );
                 }
-                return new BooleanValue( false );
+                return BooleanValue.of( false );
             }
 
         };

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

@@ -102,7 +102,7 @@ public enum JspUrl
     HELPDESK_SEARCH( "helpdesk.jsp" ),
     FULL_PAGE_HEALTH( "fullpagehealth.jsp" ),;
 
-    private String path;
+    private final String path;
     private static final String JSP_ROOT_URL = "/WEB-INF/jsp/";
 
     JspUrl( final String path )

+ 2 - 9
server/src/main/java/password/pwm/http/PwmHttpRequestWrapper.java

@@ -37,7 +37,7 @@ import password.pwm.util.logging.PwmLogger;
 import javax.servlet.http.Cookie;
 import javax.servlet.http.HttpServletRequest;
 import java.io.IOException;
-import java.io.UnsupportedEncodingException;
+import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -412,14 +412,7 @@ public class PwmHttpRequestWrapper
     private static String decodeStringToDefaultCharSet( final String input )
     {
         String decodedValue = input;
-        try
-        {
-            decodedValue = new String( input.getBytes( "ISO-8859-1" ), PwmConstants.DEFAULT_CHARSET );
-        }
-        catch ( final UnsupportedEncodingException e )
-        {
-            LOGGER.error( () -> "error decoding request parameter: " + e.getMessage() );
-        }
+        decodedValue = new String( input.getBytes( StandardCharsets.ISO_8859_1 ), PwmConstants.DEFAULT_CHARSET );
         return decodedValue;
     }
 

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

@@ -90,7 +90,7 @@ public class ObsoleteUrlFilter extends AbstractPwmFilter
         }
 
         final String requestUrl = pwmRequest.getURLwithoutQueryString();
-        final String requestServletUrl = requestUrl.substring( pwmRequest.getContextPath().length(), requestUrl.length() );
+        final String requestServletUrl = requestUrl.substring( pwmRequest.getContextPath().length() );
 
         for ( final PwmServletDefinition pwmServletDefinition : PwmServletDefinition.values() )
         {

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

@@ -56,7 +56,6 @@ import java.net.InetAddress;
 import java.net.URI;
 import java.net.UnknownHostException;
 import java.time.Instant;
-import java.util.Arrays;
 import java.util.Enumeration;
 import java.util.List;
 
@@ -394,9 +393,7 @@ public class SessionFilter extends AbstractPwmFilter
             {
                 if ( !verificationParamName.equals( paramName ) )
                 {
-                    final List<String> paramValues = Arrays.asList( req.getParameterValues( paramName ) );
-
-                    for ( final String value : paramValues )
+                    for ( final String value : req.getParameterValues( paramName ) )
                     {
                         redirectURL = PwmURL.appendAndEncodeUrlParameters( redirectURL, paramName, value );
                     }

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

@@ -311,13 +311,13 @@ public abstract class AbstractPwmServlet extends HttpServlet implements PwmServl
         String uri = pwmRequest.getURLwithoutQueryString();
         if ( uri.startsWith( pwmRequest.getContextPath() ) )
         {
-            uri = uri.substring( pwmRequest.getContextPath().length(), uri.length() );
+            uri = uri.substring( pwmRequest.getContextPath().length() );
         }
         for ( final String servletUri : getServletDefinition().urlPatterns() )
         {
             if ( uri.startsWith( servletUri ) )
             {
-                uri = uri.substring( servletUri.length(), uri.length() );
+                uri = uri.substring( servletUri.length() );
             }
         }
         return uri;

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

@@ -55,13 +55,13 @@ public abstract class ControlledPwmServlet extends AbstractPwmServlet implements
         String uri = pwmRequest.getURLwithoutQueryString();
         if ( uri.startsWith( pwmRequest.getContextPath() ) )
         {
-            uri = uri.substring( pwmRequest.getContextPath().length(), uri.length() );
+            uri = uri.substring( pwmRequest.getContextPath().length() );
         }
         for ( final String servletUri : getServletDefinition().urlPatterns() )
         {
             if ( uri.startsWith( servletUri ) )
             {
-                uri = uri.substring( servletUri.length(), uri.length() );
+                uri = uri.substring( servletUri.length() );
             }
         }
         return uri;

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

@@ -219,7 +219,7 @@ public class LogoutServlet extends ControlledPwmServlet
             String path = uri.getPath();
             if ( path != null && path.startsWith( pwmRequest.getContextPath() ) )
             {
-                path = path.substring( pwmRequest.getContextPath().length(), path.length() );
+                path = path.substring( pwmRequest.getContextPath().length() );
 
             }
             PwmServletDefinition matchedServlet = null;

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

@@ -221,7 +221,7 @@ public class ShortcutServlet extends AbstractPwmServlet
         final String link = pwmRequest.readParameterAsString( "link" );
         final Map<String, ShortcutItem> visibleItems = shortcutsBean.getVisibleItems();
 
-        if ( link != null && visibleItems.keySet().contains( link ) )
+        if ( link != null && visibleItems.containsKey( link ) )
         {
             final ShortcutItem item = visibleItems.get( link );
 

+ 2 - 2
server/src/main/java/password/pwm/http/servlet/configguide/ConfigGuideForm.java

@@ -206,7 +206,7 @@ public class ConfigGuideForm
         {
             //telemetry
             final boolean telemetryEnabled = Boolean.parseBoolean( formData.get( ConfigGuideFormField.PARAM_TELEMETRY_ENABLE ) );
-            storedConfiguration.writeSetting( PwmSetting.PUBLISH_STATS_ENABLE, null, new BooleanValue( telemetryEnabled ), null );
+            storedConfiguration.writeSetting( PwmSetting.PUBLISH_STATS_ENABLE, null, BooleanValue.of( telemetryEnabled ), null );
 
             final String siteDescription = formData.get( ConfigGuideFormField.PARAM_TELEMETRY_DESCRIPTION );
             storedConfiguration.writeSetting( PwmSetting.PUBLISH_STATS_SITE_DESCRIPTION, null, new StringValue( siteDescription ), null );
@@ -224,7 +224,7 @@ public class ConfigGuideForm
         storedConfiguration.writeSetting( PwmSetting.PWM_SITE_URL, null, new StringValue( formData.get( ConfigGuideFormField.PARAM_APP_SITEURL ) ), null );
 
         // enable debug mode
-        storedConfiguration.writeSetting( PwmSetting.DISPLAY_SHOW_DETAILED_ERRORS, null, new BooleanValue( true ), null );
+        storedConfiguration.writeSetting( PwmSetting.DISPLAY_SHOW_DETAILED_ERRORS, null, BooleanValue.of( true ), null );
 
         return storedConfiguration.newStoredConfiguration();
     }

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

@@ -523,7 +523,7 @@ public class DebugItemGenerator
             }
 
 
-            try ( ClosableIterator<FileSystemUtility.FileSummaryInformation> iter = FileSystemUtility.readFileInformation( interestedFiles ); )
+            try ( ClosableIterator<FileSystemUtility.FileSummaryInformation> iter = FileSystemUtility.readFileInformation( interestedFiles ) )
             {
                 final CSVPrinter csvPrinter = JavaHelper.makeCsvPrinter( outputStream );
                 {

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

@@ -188,7 +188,7 @@ public class RemoteVerificationMethod implements VerificationMethodSystem
                 final String name = entry.getKey();
                 if ( name != null && name.startsWith( prefix ) )
                 {
-                    final String strippedName = name.substring( prefix.length(), name.length() );
+                    final String strippedName = name.substring( prefix.length() );
                     final String value = entry.getValue();
                     remoteResponses.put( strippedName, value );
                 }

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

@@ -174,8 +174,7 @@ class NewUserFormUtils
             final PasswordData passwordData2
     )
     {
-        final Map<String, String> newFormValues = new LinkedHashMap<>();
-        newFormValues.putAll( FormUtility.asStringMap( userFormValues ) );
+        final Map<String, String> newFormValues = new LinkedHashMap<>( FormUtility.asStringMap( userFormValues ) );
 
         final List<FormConfiguration> formConfigurations = newUserProfile.readSettingAsForm( PwmSetting.NEWUSER_FORM );
         if ( injectedValues != null )

+ 3 - 3
server/src/main/java/password/pwm/http/servlet/resource/ResourceFileRequest.java

@@ -228,7 +228,7 @@ class ResourceFileRequest
                 final String path = entry.getKey();
                 if ( filename.startsWith( path ) )
                 {
-                    final String zipSubPath = filename.substring( path.length() + 1, filename.length() );
+                    final String zipSubPath = filename.substring( path.length() + 1 );
                     final ZipFile zipFile = entry.getValue();
                     final ZipEntry zipEntry = zipFile.getEntry( zipSubPath );
                     if ( zipEntry != null )
@@ -309,7 +309,7 @@ class ResourceFileRequest
                 return new RealFileResource( file );
             }
 
-            final String remainingPath = resourcePathUri.substring( ResourceFileServlet.WEBJAR_BASE_URL_PATH.length(), resourcePathUri.length() );
+            final String remainingPath = resourcePathUri.substring( ResourceFileServlet.WEBJAR_BASE_URL_PATH.length() );
 
             final String webJarName;
             final String webJarPath;
@@ -320,7 +320,7 @@ class ResourceFileRequest
                     return null;
                 }
                 webJarName = remainingPath.substring( 0, slashIndex );
-                webJarPath = remainingPath.substring( slashIndex + 1, remainingPath.length() );
+                webJarPath = remainingPath.substring( slashIndex + 1 );
             }
 
             final String versionString = WEB_JAR_VERSION_MAP.get( webJarName );

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

@@ -341,7 +341,7 @@ public class ResourceFileServlet extends HttpServlet implements PwmServlet
     {
         try (
                 OutputStream output = new BufferedOutputStream( response.getOutputStream() );
-                InputStream input = new BufferedInputStream( file.getInputStream() );
+                InputStream input = new BufferedInputStream( file.getInputStream() )
         )
         {
             if ( acceptsGzip )

+ 1 - 3
server/src/main/java/password/pwm/http/servlet/updateprofile/UpdateProfileUtil.java

@@ -214,9 +214,7 @@ public class UpdateProfileUtil
         {
             formValueMap.put(
                     formConfiguration,
-                    updateProfileBean.getFormData().keySet().contains( formConfiguration.getName() )
-                            ? updateProfileBean.getFormData().get( formConfiguration.getName() )
-                            : ""
+                    updateProfileBean.getFormData().getOrDefault( formConfiguration.getName(), "" )
             );
         }
         return formValueMap;

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

@@ -96,8 +96,7 @@ public class LdapBrowser
 
         final LdapBrowseResult result = new LdapBrowseResult();
         {
-            final Map<String, Boolean> childDNs = new TreeMap<>();
-            childDNs.putAll( getChildEntries( profileID, dn ) );
+            final Map<String, Boolean> childDNs = new TreeMap<>( getChildEntries( profileID, dn ) );
 
             for ( final Map.Entry<String, Boolean> entry : childDNs.entrySet() )
             {
@@ -161,7 +160,7 @@ public class LdapBrowser
     private String figureLdapProfileID( final String profile )
     {
         final Configuration configuration = new Configuration( storedConfiguration );
-        if ( configuration.getLdapProfiles().keySet().contains( profile ) )
+        if ( configuration.getLdapProfiles().containsKey( profile ) )
         {
             return profile;
         }

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

@@ -138,8 +138,7 @@ public class PasswordChangeProgressChecker
             throw new IllegalArgumentException( "tracker cannot be null" );
         }
 
-        final Map<String, ProgressRecord> newItemProgress = new LinkedHashMap<>();
-        newItemProgress.putAll( tracker.itemCompletions );
+        final Map<String, ProgressRecord> newItemProgress = new LinkedHashMap<>( tracker.itemCompletions );
 
         if ( tracker.beginTime == null || Instant.now().isAfter( maxCompletionTime( tracker ) ) )
         {

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

@@ -656,7 +656,7 @@ public class UserInfoReader implements UserInfo
                 if ( profileID.isPresent() )
                 {
                     returnMap.put( profileDefinition, profileID.get() );
-                    LOGGER.debug( sessionLabel, () -> "assigned " + profileDefinition.toString() + " profileID \"" + profileID + "\" to " + userIdentity.toDisplayString() );
+                    LOGGER.debug( sessionLabel, () -> "assigned " + profileDefinition.toString() + " profileID \"" + profileID.get() + "\" to " + userIdentity.toDisplayString() );
                 }
                 else
                 {
@@ -669,10 +669,10 @@ public class UserInfoReader implements UserInfo
 
     private static Set<String> figurePasswordRuleAttributes(
             final UserInfo uiBean
-    ) throws PwmUnrecoverableException
+    )
+            throws PwmUnrecoverableException
     {
-        final Set<String> interestingUserAttributes = new HashSet<>();
-        interestingUserAttributes.addAll( uiBean.getPasswordPolicy().getRuleHelper().getDisallowedAttributes() );
+        final Set<String> interestingUserAttributes = new HashSet<>( uiBean.getPasswordPolicy().getRuleHelper().getDisallowedAttributes() );
         if ( uiBean.getPasswordPolicy().getRuleHelper().getADComplexityLevel() == ADPolicyComplexity.AD2003
                 || uiBean.getPasswordPolicy().getRuleHelper().getADComplexityLevel() == ADPolicyComplexity.AD2008 )
         {

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

@@ -741,8 +741,7 @@ public class UserSearchEngine implements PwmService
 
     private Map<String, String> debugProperties( )
     {
-        final Map<String, String> properties = new TreeMap<>();
-        properties.putAll( counters.debugStats() );
+        final Map<String, String> properties = new TreeMap<>( counters.debugStats() );
         properties.put( "jvmThreadCount", Integer.toString( Thread.activeCount() ) );
         if ( executor == null )
         {

+ 1 - 1
server/src/main/java/password/pwm/svc/email/EmailServerUtil.java

@@ -411,7 +411,7 @@ public class EmailServerUtil
         final Optional<EmailServer> emailServer = makeEmailServer( configuration, emailServerProfile, trustManagers );
         if ( emailServer.isPresent() )
         {
-            try ( Transport transport = makeSmtpTransport( emailServer.get() ); )
+            try ( Transport transport = makeSmtpTransport( emailServer.get() ) )
             {
                 return certReaderTm.getCertificates();
             }

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

@@ -614,6 +614,8 @@ public class ReportService implements PwmService
                 return;
             }
 
+            final Instant startTime = Instant.now();
+
             final UserInfo userInfo = UserInfoFactory.newUserInfoUsingProxyForOfflineUser(
                     pwmApplication,
                     SessionLabel.REPORTING_SESSION_LABEL,
@@ -625,7 +627,7 @@ public class ReportService implements PwmService
             summaryData.update( newUserCacheRecord );
             processRateMeter.markEvents( 1 );
 
-            LOGGER.trace( SessionLabel.REPORTING_SESSION_LABEL, () -> "stored cache for " + userIdentity );
+            LOGGER.trace( SessionLabel.REPORTING_SESSION_LABEL, () -> "stored cache for " + userIdentity, () -> TimeDuration.fromCurrent( startTime ) );
         }
     }
 

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

@@ -35,6 +35,7 @@ import java.math.BigInteger;
 import java.time.Instant;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.EnumSet;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
@@ -309,12 +310,12 @@ public class ReportSummaryData
 
         returnCollection.add( builder.makeRow( "Field_Report_Sum_HaveResponses", this.hasResponses.get() ) );
         returnCollection.add( builder.makeRow( "Field_Report_Sum_HaveHelpdeskResponses", this.hasHelpdeskResponses.get() ) );
-        for ( final DataStorageMethod storageMethod : new TreeSet<>( this.getResponseStorage().keySet() ) )
+        for ( final DataStorageMethod storageMethod : EnumSet.copyOf( this.getResponseStorage().keySet() ) )
         {
             final int count = this.getResponseStorage().get( storageMethod );
             returnCollection.add( builder.makeRow( "Field_Report_Sum_StorageMethod", count, storageMethod.toString() ) );
         }
-        for ( final Answer.FormatType formatType : new TreeSet<>( this.getResponseFormatType().keySet() ) )
+        for ( final Answer.FormatType formatType : EnumSet.copyOf( this.getResponseFormatType().keySet() ) )
         {
             final int count = this.getResponseFormatType().get( formatType );
             returnCollection.add( builder.makeRow( "Field_Report_Sum_ResponseFormatType", count, formatType.toString() ) );

+ 2 - 2
server/src/main/java/password/pwm/svc/shorturl/UrlShortenerService.java

@@ -133,7 +133,7 @@ public class UrlShortenerService implements PwmService
             {
                 int start = 0;
                 int end = m.start();
-                result.append( text.substring( start, end ) );
+                result.append( text, start, end );
                 start = end;
                 end = m.end();
                 while ( found )
@@ -144,7 +144,7 @@ public class UrlShortenerService implements PwmService
                     if ( found )
                     {
                         end = m.start();
-                        result.append( text.substring( start, end ) );
+                        result.append( text, start, end );
                         start = end;
                         end = m.end();
                     }

+ 3 - 4
server/src/main/java/password/pwm/svc/wordlist/WordlistConfiguration.java

@@ -84,7 +84,7 @@ public class WordlistConfiguration implements Serializable
         {
             case SEEDLIST:
             {
-                return commonBuilder( configuration, type ).toBuilder()
+                return commonBuilder( configuration ).toBuilder()
                         .autoImportUrl( readAutoImportUrl( configuration, PwmSetting.SEEDLIST_FILENAME ) )
                         .metaDataAppAttribute( AppAttribute.SEEDLIST_METADATA )
                         .builtInWordlistLocationProperty( AppProperty.SEEDLIST_BUILTIN_PATH )
@@ -95,7 +95,7 @@ public class WordlistConfiguration implements Serializable
 
             case WORDLIST:
             {
-                return commonBuilder( configuration, type ).toBuilder()
+                return commonBuilder( configuration ).toBuilder()
                         .caseSensitive( configuration.readSettingAsBoolean( PwmSetting.WORDLIST_CASE_SENSITIVE )  )
                         .checkSize( (int) configuration.readSettingAsLong( PwmSetting.PASSWORD_WORDLIST_WORDSIZE ) )
                         .autoImportUrl( readAutoImportUrl( configuration, PwmSetting.WORDLIST_FILENAME ) )
@@ -114,8 +114,7 @@ public class WordlistConfiguration implements Serializable
     }
 
     private static WordlistConfiguration commonBuilder(
-            final Configuration configuration,
-            final WordlistType type
+            final Configuration configuration
     )
     {
         return WordlistConfiguration.builder()

+ 4 - 5
server/src/main/java/password/pwm/svc/wordlist/WordlistImporter.java

@@ -39,7 +39,7 @@ import java.text.DecimalFormat;
 import java.time.Instant;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.HashMap;
+import java.util.EnumMap;
 import java.util.Map;
 import java.util.Optional;
 import java.util.Set;
@@ -67,7 +67,7 @@ class WordlistImporter implements Runnable
     private ErrorInformation exitError;
     private Instant startTime = Instant.now();
     private long bytesSkipped;
-    private final Map<WordType, Long> seenWordTypes = new HashMap<>();
+    private final Map<WordType, Long> seenWordTypes = new EnumMap<>( WordType.class );
     private boolean completed;
 
     private enum DebugKey
@@ -254,8 +254,7 @@ class WordlistImporter implements Runnable
         }
 
         final WordType wordType = WordType.determineWordType( input );
-        seenWordTypes.computeIfAbsent( wordType, wordType1 -> 0L );
-        seenWordTypes.put( wordType, seenWordTypes.get( wordType ) + 1L );
+        seenWordTypes.compute( wordType, ( key, value ) -> value == null ? 0L : value + 1L );
 
         if ( wordType == WordType.RAW )
         {
@@ -461,7 +460,7 @@ class WordlistImporter implements Runnable
                 .checkDate( now )
                 .sourceType( sourceType )
                 .completed( completed )
-                .wordTypes( new HashMap<>( seenWordTypes ) )
+                .wordTypes( new EnumMap<>( seenWordTypes ) )
                 .bytes( zipFileReader.getByteCount() )
                 .build() );
     }

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

@@ -75,7 +75,7 @@ public class BasicAuthInfo implements Serializable
                 // ***** Get the encoded username/chpass string
                 // Strip off "Basic " from "Basic c2pvaG5zLmNzaTo=bm92ZWxs"
                 final String toStrip = PwmConstants.HTTP_BASIC_AUTH_PREFIX + " ";
-                final String encodedValue = authHeader.substring( toStrip.length(), authHeader.length() );
+                final String encodedValue = authHeader.substring( toStrip.length() );
 
                 try
                 {

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

@@ -224,8 +224,7 @@ public class DailySummaryJob implements Runnable
             // statistics
             htmlBody.append( "<h2>Daily Statistics</h2>" );
             textBody.append( "--Daily Statistics--\n" );
-            final Map<String, String> sortedStats = new TreeMap<>();
-            sortedStats.putAll( dailyStatistics );
+            final Map<String, String> sortedStats = new TreeMap<>( dailyStatistics );
 
             htmlBody.append( "<table border='1'>" );
             for ( final String key : sortedStats.keySet() )

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

@@ -139,9 +139,9 @@ public class PropertyConfigurationImporter
                     null );
         }
 
-        storedConfiguration.writeSetting( PwmSetting.DISPLAY_HOME_BUTTON, null, new BooleanValue( false ), null );
-        storedConfiguration.writeSetting( PwmSetting.LOGOUT_AFTER_PASSWORD_CHANGE, null, new BooleanValue( false ), null );
-        storedConfiguration.writeSetting( PwmSetting.PASSWORD_REQUIRE_CURRENT, null, new BooleanValue( false ), null );
+        storedConfiguration.writeSetting( PwmSetting.DISPLAY_HOME_BUTTON, null, BooleanValue.of( false ), null );
+        storedConfiguration.writeSetting( PwmSetting.LOGOUT_AFTER_PASSWORD_CHANGE, null, BooleanValue.of( false ), null );
+        storedConfiguration.writeSetting( PwmSetting.PASSWORD_REQUIRE_CURRENT, null, BooleanValue.of( false ), null );
         storedConfiguration.writeSetting( PwmSetting.PASSWORD_POLICY_SOURCE, null, new StringValue( "LDAP" ), null );
         storedConfiguration.writeSetting( PwmSetting.CERTIFICATE_VALIDATION_MODE, null, new StringValue( "CA_ONLY" ), null );
         {

+ 3 - 3
server/src/main/java/password/pwm/util/cli/MainOptions.java

@@ -117,7 +117,7 @@ public class MainOptions implements Serializable
                         }
                         else
                         {
-                            final String levelStr = arg.substring( OPT_DEBUG_LEVEL.length() + 1, arg.length() );
+                            final String levelStr = arg.substring( OPT_DEBUG_LEVEL.length() + 1 );
                             try
                             {
                                 pwmLogLevel = PwmLogLevel.valueOf( levelStr.toUpperCase() );
@@ -138,7 +138,7 @@ public class MainOptions implements Serializable
                         }
                         else
                         {
-                            final String pathStr = arg.substring( OPT_APP_PATH.length() + 1, arg.length() );
+                            final String pathStr = arg.substring( OPT_APP_PATH.length() + 1 );
                             applicationPath = new File( pathStr );
                         }
                     }
@@ -155,7 +155,7 @@ public class MainOptions implements Serializable
                         }
                         else
                         {
-                            final String flagStr = arg.substring( OPT_APP_PATH.length() + 1, arg.length() );
+                            final String flagStr = arg.substring( OPT_APP_PATH.length() + 1 );
                             applicationFlags = PwmEnvironment.ParseHelper.parseApplicationFlagValueParameter( flagStr );
                         }
                         outputArgs.add( arg );

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

@@ -577,7 +577,7 @@ class DatabaseAccessorImpl implements DatabaseAccessor
         final String sqlStatement = "SELECT COUNT(" + DatabaseService.KEY_COLUMN + ") FROM " + table.name()
                 + " WHERE " + DatabaseService.KEY_COLUMN + " = ?";
 
-        try ( PreparedStatement selectStatement = connection.prepareStatement( sqlStatement ); )
+        try ( PreparedStatement selectStatement = connection.prepareStatement( sqlStatement ) )
         {
             selectStatement.setString( 1, key );
             selectStatement.setMaxRows( 1 );

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

@@ -155,7 +155,7 @@ public abstract class StringUtil
                 final String key = loopStr.substring( 0, separatorLocation );
                 if ( !key.trim().isEmpty() )
                 {
-                    final String value = loopStr.substring( separatorLocation + separator.length(), loopStr.length() );
+                    final String value = loopStr.substring( separatorLocation + separator.length() );
                     returnMap.put( key, value );
                 }
             }

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

@@ -46,6 +46,7 @@ import java.io.OutputStream;
 import java.io.OutputStreamWriter;
 import java.io.Writer;
 import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
@@ -96,7 +97,7 @@ public interface XmlFactory
 
     class XmlFactoryJDOM implements XmlFactory
     {
-        private static final Charset STORAGE_CHARSET = Charset.forName( "UTF8" );
+        private static final Charset STORAGE_CHARSET = StandardCharsets.UTF_8;
 
         XmlFactoryJDOM()
         {
@@ -179,7 +180,7 @@ public interface XmlFactory
 
     class XmlFactoryW3c implements XmlFactory
     {
-        private static final Charset STORAGE_CHARSET = Charset.forName( "UTF8" );
+        private static final Charset STORAGE_CHARSET = StandardCharsets.UTF_8;
 
         XmlFactoryW3c()
         {

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

@@ -522,8 +522,7 @@ public abstract class AbstractJDBCLocalDB implements LocalDBProvider
             lock.writeLock().lock();
             try
             {
-                final Set<LocalDB.LocalDBIterator<Map.Entry<String, String>>> copiedIterators = new HashSet<>();
-                copiedIterators.addAll( dbIterators );
+                final Set<LocalDB.LocalDBIterator<Map.Entry<String, String>>> copiedIterators = new HashSet<>( dbIterators );
 
                 for ( final LocalDB.LocalDBIterator dbIterator : copiedIterators )
                 {

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

@@ -26,7 +26,6 @@ import password.pwm.util.java.JavaHelper;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.logging.PwmLogger;
 
-import java.math.BigInteger;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -36,6 +35,7 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.NoSuchElementException;
+import java.util.Objects;
 import java.util.Queue;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -47,8 +47,7 @@ import java.util.function.Supplier;
  * A LIFO {@link Queue} implementation backed by a localDB instance.  {@code this} instances are internally
  * synchronized.
  */
-public class
-LocalDBStoredQueue implements Queue<String>, Deque<String>
+public class LocalDBStoredQueue implements Queue<String>, Deque<String>
 {
     private static final PwmLogger LOGGER = PwmLogger.forClass( LocalDBStoredQueue.class, true );
     private static final int MAX_SIZE = Integer.MAX_VALUE - 3;
@@ -142,11 +141,7 @@ LocalDBStoredQueue implements Queue<String>, Deque<String>
     @Override
     public Object[] toArray( )
     {
-        final List<Object> returnList = new ArrayList<>();
-        for ( final Iterator<String> innerIter = this.iterator(); innerIter.hasNext(); )
-        {
-            returnList.add( innerIter.next() );
-        }
+        final List<Object> returnList = new ArrayList<>( this );
         return returnList.toArray();
     }
 
@@ -154,9 +149,9 @@ LocalDBStoredQueue implements Queue<String>, Deque<String>
     public <T> T[] toArray( final T[] a )
     {
         int index = 0;
-        for ( final Iterator<String> innerIter = this.iterator(); innerIter.hasNext(); )
+        for ( final String s : this )
         {
-            a[ index ] = ( T ) innerIter.next();
+            a[index] = ( T ) s;
             index++;
         }
         return a;
@@ -246,7 +241,8 @@ LocalDBStoredQueue implements Queue<String>, Deque<String>
     {
         try
         {
-            return internalQueue.size();
+            final long realSize = internalQueue.size();
+            return realSize >= Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) realSize;
         }
         catch ( final LocalDBException e )
         {
@@ -526,7 +522,7 @@ LocalDBStoredQueue implements Queue<String>, Deque<String>
         private Position position;
         private final InternalQueue internalQueue;
         private final boolean first;
-        private int queueSizeAtCreate;
+        private final long queueSizeAtCreate;
         private int steps;
 
 
@@ -555,7 +551,7 @@ LocalDBStoredQueue implements Queue<String>, Deque<String>
             steps++;
             try
             {
-                final String nextValue = internalQueue.localDB.get( internalQueue.db, position.toString() );
+                final String nextValue = internalQueue.localDB.get( internalQueue.db, position.key() );
                 if ( first )
                 {
                     position = position.equals( internalQueue.tailPosition ) ? null : position.previous();
@@ -582,28 +578,28 @@ LocalDBStoredQueue implements Queue<String>, Deque<String>
         }
     }
 
-    private static class Position
+    static class Position
     {
         private static final int RADIX = 36;
-        private static final BigInteger MAXIMUM_POSITION = new BigInteger( "zzzzzz", RADIX );
-        private static final BigInteger MINIMUM_POSITION = BigInteger.ZERO;
+        private static final long MAXIMUM_POSITION = Long.parseLong( "zzzzzz", RADIX );
+        private static final long MINIMUM_POSITION = 0;
 
-        private final BigInteger bigInt;
+        private final long bigInt;
 
-        private Position( final BigInteger bigInt )
+        private Position( final long bigInt )
         {
             this.bigInt = bigInt;
         }
 
         Position( final String bigInt )
         {
-            this.bigInt = new BigInteger( bigInt, RADIX );
+            this.bigInt = Long.parseLong( bigInt, RADIX );
         }
 
         public Position next( )
         {
-            BigInteger next = bigInt.add( BigInteger.ONE );
-            if ( next.compareTo( MAXIMUM_POSITION ) > 0 )
+            long next = bigInt + 1;
+            if ( next > MAXIMUM_POSITION )
             {
                 next = MINIMUM_POSITION;
             }
@@ -612,38 +608,43 @@ LocalDBStoredQueue implements Queue<String>, Deque<String>
 
         public Position previous( )
         {
-            BigInteger previous = bigInt.subtract( BigInteger.ONE );
-            if ( previous.compareTo( MINIMUM_POSITION ) < 0 )
+            long previous = bigInt - 1;
+            if ( previous < MINIMUM_POSITION )
             {
                 previous = MAXIMUM_POSITION;
             }
             return new Position( previous );
         }
 
-        public BigInteger distanceToHead( final Position head )
+        public long distanceToHead( final Position head )
         {
-            final int compareToValue = head.bigInt.compareTo( this.bigInt );
+            final int compareToValue = Long.compare( head.bigInt, this.bigInt );
             if ( compareToValue == 0 )
             {
-                return BigInteger.ZERO;
+                return 0;
             }
             else if ( compareToValue == 1 )
             {
-                return head.bigInt.subtract( this.bigInt );
+                return head.bigInt - this.bigInt;
             }
 
-            final BigInteger tailToMax = MAXIMUM_POSITION.subtract( this.bigInt );
-            final BigInteger minToHead = head.bigInt.subtract( MINIMUM_POSITION );
-            return minToHead.add( tailToMax ).add( BigInteger.ONE );
+            final long tailToMax = MAXIMUM_POSITION -  this.bigInt;
+            final long minToHead = head.bigInt - MINIMUM_POSITION;
+            return minToHead + tailToMax + 1;
         }
 
         public String toString( )
+        {
+            return key();
+        }
+
+        public String key()
         {
             final StringBuilder sb = new StringBuilder();
-            sb.append( bigInt.toString( RADIX ).toUpperCase() );
+            sb.append( Long.toString( bigInt, RADIX ).toUpperCase() );
             while ( sb.length() < 6 )
             {
-                sb.insert( 0, "0" );
+                sb.insert( 0, '0' );
             }
             return sb.toString();
         }
@@ -659,16 +660,14 @@ LocalDBStoredQueue implements Queue<String>, Deque<String>
             {
                 return false;
             }
-
             final Position position = ( Position ) o;
-
-            return bigInt.equals( position.bigInt );
+            return bigInt == position.bigInt;
         }
 
         @Override
-        public int hashCode( )
+        public int hashCode()
         {
-            return bigInt.hashCode();
+            return Objects.hash( bigInt );
         }
     }
 
@@ -734,10 +733,12 @@ LocalDBStoredQueue implements Queue<String>, Deque<String>
             tailPosition = tailPositionStr != null && tailPositionStr.length() > 0 ? new Position( tailPositionStr ) : new Position( "0" );
 
             {
-                final int finalSize = this.size();
+                final long finalSize = this.size();
                 LOGGER.trace( () -> "loaded for db " + db + "; headPosition=" + headPosition + ", tailPosition=" + tailPosition + ", size=" + finalSize );
             }
 
+            checkSize();
+
             repair();
 
             debugOutput( "post init()" );
@@ -778,7 +779,7 @@ LocalDBStoredQueue implements Queue<String>, Deque<String>
             }
         }
 
-        public int size( )
+        public long size( )
                 throws LocalDBException
         {
             lock.readLock().lock();
@@ -792,14 +793,14 @@ LocalDBStoredQueue implements Queue<String>, Deque<String>
             }
         }
 
-        private int internalSize( )
+        private long internalSize( )
                 throws LocalDBException
         {
             if ( headPosition.equals( tailPosition ) && localDB.get( db, headPosition.toString() ) == null )
             {
                 return 0;
             }
-            return tailPosition.distanceToHead( headPosition ).intValue() + 1;
+            return tailPosition.distanceToHead( headPosition ) + 1;
         }
 
         List<String> removeFirst( final int removalCount, final boolean returnValues ) throws LocalDBException
@@ -808,36 +809,9 @@ LocalDBStoredQueue implements Queue<String>, Deque<String>
             try
             {
                 debugOutput( "pre removeFirst()" );
-
-                if ( removalCount < 1 )
-                {
-                    return Collections.emptyList();
-                }
-
-                final List<String> removalKeys = new ArrayList<>();
-                final List<String> removedValues = new ArrayList<>();
-                Position previousHead = headPosition;
-                int removedPositions = 0;
-                while ( removedPositions < removalCount )
-                {
-                    removalKeys.add( previousHead.toString() );
-                    if ( returnValues )
-                    {
-                        final String loopValue = localDB.get( db, previousHead.toString() );
-                        if ( loopValue != null )
-                        {
-                            removedValues.add( loopValue );
-                        }
-                    }
-                    previousHead = previousHead.equals( tailPosition ) ? previousHead : previousHead.previous();
-                    removedPositions++;
-                }
-                localDB.removeAll( db, removalKeys );
-                localDB.put( db, KEY_HEAD_POSITION, previousHead.toString() );
-                headPosition = previousHead;
-
+                final List<String> removedValues = removeImpl( removalCount, returnValues, true );
                 debugOutput( "post removeFirst()" );
-                return Collections.unmodifiableList( removedValues );
+                return removedValues;
             }
             finally
             {
@@ -851,36 +825,9 @@ LocalDBStoredQueue implements Queue<String>, Deque<String>
             try
             {
                 debugOutput( "pre removeLast()" );
-
-                if ( removalCount < 1 )
-                {
-                    return Collections.emptyList();
-                }
-
-                final List<String> removalKeys = new ArrayList<>();
-                final List<String> removedValues = new ArrayList<>();
-                Position nextTail = tailPosition;
-                int removedPositions = 0;
-                while ( removedPositions < removalCount )
-                {
-                    removalKeys.add( nextTail.toString() );
-                    if ( returnValues )
-                    {
-                        final String loopValue = localDB.get( db, nextTail.toString() );
-                        if ( loopValue != null )
-                        {
-                            removedValues.add( loopValue );
-                        }
-                    }
-                    nextTail = nextTail.equals( headPosition ) ? nextTail : nextTail.next();
-                    removedPositions++;
-                }
-                localDB.removeAll( db, removalKeys );
-                localDB.put( db, KEY_TAIL_POSITION, nextTail.toString() );
-                tailPosition = nextTail;
-
+                final List<String> removedValues = removeImpl( removalCount, returnValues, false );
                 debugOutput( "post removeLast()" );
-                return Collections.unmodifiableList( removedValues );
+                return removedValues;
             }
             finally
             {
@@ -888,43 +835,64 @@ LocalDBStoredQueue implements Queue<String>, Deque<String>
             }
         }
 
-        void addFirst( final Collection<String> values )
+        private List<String> removeImpl( final int removalCount, final boolean returnValues, final boolean forward )
                 throws LocalDBException
         {
-            lock.writeLock().lock();
-            try
+            if ( removalCount < 1 )
             {
-                debugOutput( "pre addFirst()" );
-                if ( JavaHelper.isEmpty( values ) )
-                {
-                    return;
-                }
+                return Collections.emptyList();
+            }
 
-                if ( internalSize() + values.size() > MAX_SIZE )
+            final List<String> removalKeys = new ArrayList<>();
+            final List<String> removedValues = new ArrayList<>();
+            Position loopPosition = forward ? headPosition : tailPosition;
+            int removedPositions = 0;
+            while ( removedPositions < removalCount )
+            {
+                removalKeys.add( loopPosition.key() );
+                if ( returnValues )
                 {
-                    throw new IllegalStateException( "queue overflow" );
+                    final String loopValue = localDB.get( db, loopPosition.key() );
+                    if ( loopValue != null )
+                    {
+                        removedValues.add( loopValue );
+                    }
                 }
 
-                final Iterator<String> valueIterator = values.iterator();
-
-                final Map<String, String> keyValueMap = new HashMap<>();
-                Position nextHead = headPosition;
-
-                if ( internalSize() == 0 )
+                if ( forward )
                 {
-                    keyValueMap.put( nextHead.toString(), valueIterator.next() );
+                    loopPosition = loopPosition.equals( tailPosition ) ? loopPosition : loopPosition.previous();
                 }
-
-                while ( valueIterator.hasNext() )
+                else
                 {
-                    nextHead = nextHead.next();
-                    keyValueMap.put( nextHead.toString(), valueIterator.next() );
+                    loopPosition = loopPosition.equals( headPosition ) ? loopPosition : loopPosition.next();
                 }
 
-                keyValueMap.put( KEY_HEAD_POSITION, String.valueOf( nextHead ) );
-                localDB.putAll( db, keyValueMap );
-                headPosition = nextHead;
+                removedPositions++;
+            }
+            localDB.removeAll( db, removalKeys );
+            localDB.put( db, forward ? KEY_HEAD_POSITION : KEY_TAIL_POSITION, loopPosition.key() );
+
+            if ( forward )
+            {
+                headPosition = loopPosition;
+            }
+            else
+            {
+                tailPosition = loopPosition;
+            }
+
+            return Collections.unmodifiableList( removedValues );
+        }
 
+        void addFirst( final Collection<String> values )
+                throws LocalDBException
+        {
+            lock.writeLock().lock();
+            try
+            {
+                debugOutput( "pre addFirst()" );
+                addImpl( values, true );
                 debugOutput( "post addFirst()" );
             }
             finally
@@ -939,43 +907,59 @@ LocalDBStoredQueue implements Queue<String>, Deque<String>
             try
             {
                 debugOutput( "pre addLast()" );
-                if ( JavaHelper.isEmpty( values ) )
-                {
-                    return;
-                }
+                addImpl( values, false );
+                debugOutput( "post addLast()" );
+            }
+            finally
+            {
+                lock.writeLock().unlock();
+            }
+        }
 
-                if ( internalSize() + values.size() > MAX_SIZE )
-                {
-                    throw new IllegalStateException( "queue overflow" );
-                }
+        private void addImpl( final Collection<String> values, final boolean forward )
+                throws LocalDBException
+        {
+            if ( JavaHelper.isEmpty( values ) )
+            {
+                return;
+            }
 
-                final Iterator<String> valueIterator = values.iterator();
+            if ( internalSize() + values.size() > MAX_SIZE )
+            {
+                throw new IllegalStateException( "queue overflow" );
+            }
 
-                final Map<String, String> keyValueMap = new HashMap<>();
-                Position nextTail = tailPosition;
+            final Iterator<String> valueIterator = values.iterator();
 
-                if ( internalSize() == 0 )
-                {
-                    keyValueMap.put( nextTail.toString(), valueIterator.next() );
-                }
+            final Map<String, String> keyValueMap = new HashMap<>();
+            Position loopPosition = forward ? headPosition : tailPosition;
 
-                while ( valueIterator.hasNext() )
-                {
-                    nextTail = nextTail.previous();
-                    keyValueMap.put( nextTail.toString(), valueIterator.next() );
-                }
-                keyValueMap.put( KEY_TAIL_POSITION, String.valueOf( nextTail ) );
-                localDB.putAll( db, keyValueMap );
-                tailPosition = nextTail;
+            if ( internalSize() == 0 )
+            {
+                keyValueMap.put( loopPosition.toString(), valueIterator.next() );
+            }
 
-                debugOutput( "post addLast()" );
+            while ( valueIterator.hasNext() )
+            {
+                loopPosition = forward ? loopPosition.next() : loopPosition.previous();
+                keyValueMap.put( loopPosition.key(), valueIterator.next() );
             }
-            finally
+
+            keyValueMap.put( forward ? KEY_HEAD_POSITION : KEY_TAIL_POSITION, loopPosition.key() );
+            localDB.putAll( db, keyValueMap );
+
+            if ( forward )
             {
-                lock.writeLock().unlock();
+                headPosition = loopPosition;
+            }
+            else
+            {
+                tailPosition = loopPosition;
             }
         }
 
+
+
         List<String> getFirst( final int count )
                 throws LocalDBException
         {
@@ -983,29 +967,8 @@ LocalDBStoredQueue implements Queue<String>, Deque<String>
             try
             {
                 debugOutput( "pre getFirst()" );
-
-                int getCount = count;
-                if ( getCount < 1 )
-                {
-                    return Collections.emptyList();
-                }
-
-                if ( getCount > internalSize() )
-                {
-                    getCount = internalSize();
-                }
-
-                final List<String> returnList = new ArrayList<>();
-
-                Position nextHead = headPosition;
-                while ( returnList.size() < getCount )
-                {
-                    returnList.add( localDB.get( db, nextHead.toString() ) );
-                    nextHead = nextHead.previous();
-                }
-
+                final List<String> returnList = getImpl( count, true );
                 debugOutput( "post getFirst()" );
-
                 return returnList;
             }
             finally
@@ -1021,29 +984,8 @@ LocalDBStoredQueue implements Queue<String>, Deque<String>
             try
             {
                 debugOutput( "pre getLast()" );
-
-                int getCount = count;
-                if ( getCount < 1 )
-                {
-                    return Collections.emptyList();
-                }
-
-                if ( getCount > internalSize() )
-                {
-                    getCount = internalSize();
-                }
-
-                final List<String> returnList = new ArrayList<>();
-
-                Position nextTail = tailPosition;
-                while ( returnList.size() < getCount )
-                {
-                    returnList.add( localDB.get( db, nextTail.toString() ) );
-                    nextTail = nextTail.next();
-                }
-
+                final List<String> returnList = getImpl( count, false );
                 debugOutput( "post getLast()" );
-
                 return returnList;
             }
             finally
@@ -1052,6 +994,32 @@ LocalDBStoredQueue implements Queue<String>, Deque<String>
             }
         }
 
+        private List<String> getImpl( final long count, final boolean forward )
+                throws LocalDBException
+        {
+            long getCount = count;
+            if ( getCount < 1 )
+            {
+                return Collections.emptyList();
+            }
+
+            if ( getCount > internalSize() )
+            {
+                getCount = internalSize();
+            }
+
+            final List<String> returnList = new ArrayList<>();
+
+            Position nextPosition = forward ? headPosition : tailPosition;
+            while ( returnList.size() < getCount )
+            {
+                returnList.add( localDB.get( db, nextPosition.key() ) );
+                nextPosition = forward ? nextPosition.previous() : nextPosition.next();
+            }
+
+            return Collections.unmodifiableList( returnList );
+        }
+
         void debugOutput( final String input )
         {
             if ( !developerDebug || DEBUG_IGNORED_DB.contains( db ) )
@@ -1095,78 +1063,93 @@ LocalDBStoredQueue implements Queue<String>, Deque<String>
             LOGGER.trace( debugOutput );
         }
 
+        private void checkSize()
+            throws LocalDBException
+        {
+            final long dbSize = localDB.size( db );
+            final long positionDistance = tailPosition.distanceToHead( headPosition );
+
+            // +3 for header/tail position and version keys.
+            if ( dbSize != positionDistance + 3 )
+            {
+                LOGGER.warn( () -> "dbSize=" + dbSize + " and positionDistance=" + positionDistance + " stored Queue is corrupted" );
+            }
+        }
+
         private void repair( ) throws LocalDBException
         {
-            int headTrim = 0;
-            int tailTrim = 0;
+            lock.writeLock().lock();
+            try
+            {
+                int headTrim = 0;
+                int tailTrim = 0;
 
-            debugOutput( "pre repair()" );
+                debugOutput( "pre repair()" );
 
-            final AtomicInteger examinedRecords = new AtomicInteger( 0 );
+                final AtomicInteger examinedRecords = new AtomicInteger( 0 );
 
-            final ConditionalTaskExecutor conditionalTaskExecutor = new ConditionalTaskExecutor(
-                     new Runnable()
+                final ConditionalTaskExecutor conditionalTaskExecutor = new ConditionalTaskExecutor( () ->
+                {
+                    try
                     {
-                        @Override
-                        public void run( )
-                        {
-                            try
-                            {
-                                localDB.put( db, KEY_HEAD_POSITION, headPosition.toString() );
-                                localDB.put( db, KEY_TAIL_POSITION, tailPosition.toString() );
-                                final int dbSize = size();
-                                LOGGER.debug( () -> "repairing db " + db + ", " + examinedRecords.get() + " records examined"
-                                        + ", size=" + dbSize
-                                        + ", head=" + headPosition.toString() + ", tail=" + tailPosition.toString() );
-                            }
-                            catch ( final Exception e )
-                            {
-                                LOGGER.error( () -> "unexpected error during output of debug message during stored queue repair operation: " + e.getMessage(), e );
-                            }
-                        }
-                    },
-                    new ConditionalTaskExecutor.TimeDurationPredicate( 30, TimeDuration.Unit.SECONDS )
-            );
-
-            // trim the top.
-            while ( !headPosition.equals( tailPosition ) && localDB.get( db, headPosition.toString() ) == null )
-            {
-                examinedRecords.incrementAndGet();
-                conditionalTaskExecutor.conditionallyExecuteTask();
-                headPosition = headPosition.previous();
-                headTrim++;
-            }
-            localDB.put( db, KEY_HEAD_POSITION, headPosition.toString() );
+                        localDB.put( db, KEY_HEAD_POSITION, headPosition.key() );
+                        localDB.put( db, KEY_TAIL_POSITION, tailPosition.key() );
+                        final long dbSize = size();
+                        LOGGER.debug( () -> "repairing db " + db + ", " + examinedRecords.get() + " records examined"
+                                + ", size=" + dbSize
+                                + ", head=" + headPosition.key() + ", tail=" + tailPosition.key() );
+                    }
+                    catch ( final Exception e )
+                    {
+                        LOGGER.error( () -> "unexpected error during output of debug message during stored queue repair operation: " + e.getMessage(), e );
+                    }
+                },
+                        new ConditionalTaskExecutor.TimeDurationPredicate( TimeDuration.SECONDS_10 )
+                );
 
-            // trim the bottom.
-            while ( !headPosition.equals( tailPosition ) && localDB.get( db, tailPosition.toString() ) == null )
-            {
-                examinedRecords.incrementAndGet();
-                conditionalTaskExecutor.conditionallyExecuteTask();
-                tailPosition = tailPosition.next();
-                tailTrim++;
-            }
-            localDB.put( db, KEY_TAIL_POSITION, tailPosition.toString() );
+                // trim the top.
+                while ( !headPosition.equals( tailPosition ) && localDB.get( db, headPosition.key() ) == null )
+                {
+                    examinedRecords.incrementAndGet();
+                    conditionalTaskExecutor.conditionallyExecuteTask();
+                    headPosition = headPosition.previous();
+                    headTrim++;
+                }
+                localDB.put( db, KEY_HEAD_POSITION, headPosition.key() );
 
-            if ( tailTrim == 0 && headTrim == 0 )
-            {
-                LOGGER.trace( () -> "repair unnecessary for " + db );
-            }
-            else
-            {
-                if ( headTrim > 0 )
+                // trim the bottom.
+                while ( !headPosition.equals( tailPosition ) && localDB.get( db, tailPosition.toString() ) == null )
                 {
-                    final int headTrimFinal = headTrim;
-                    LOGGER.warn( () -> "trimmed " + headTrimFinal + " from head position against database " + db );
+                    examinedRecords.incrementAndGet();
+                    conditionalTaskExecutor.conditionallyExecuteTask();
+                    tailPosition = tailPosition.next();
+                    tailTrim++;
                 }
+                localDB.put( db, KEY_TAIL_POSITION, tailPosition.key() );
 
-                if ( tailTrim > 0 )
+                if ( tailTrim == 0 && headTrim == 0 )
                 {
-                    final int tailTrimFinal = tailTrim;
-                    LOGGER.warn( () -> "trimmed " + tailTrimFinal + " from tail position against database " + db );
+                    LOGGER.trace( () -> "repair unnecessary for " + db );
                 }
-            }
+                else
+                {
+                    if ( headTrim > 0 )
+                    {
+                        final int headTrimFinal = headTrim;
+                        LOGGER.warn( () -> "trimmed " + headTrimFinal + " from head position against database " + db );
+                    }
 
+                    if ( tailTrim > 0 )
+                    {
+                        final int tailTrimFinal = tailTrim;
+                        LOGGER.warn( () -> "trimmed " + tailTrimFinal + " from tail position against database " + db );
+                    }
+                }
+            }
+            finally
+            {
+                lock.writeLock().unlock();
+            }
         }
     }
 }

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

@@ -29,7 +29,7 @@ import password.pwm.util.java.TimeDuration;
 
 import java.io.Serializable;
 import java.util.Collections;
-import java.util.HashSet;
+import java.util.EnumSet;
 import java.util.Set;
 
 @Data
@@ -76,7 +76,7 @@ public class LocalDBLoggerSettings implements Serializable
 
     public static LocalDBLoggerSettings fromConfiguration( final Configuration configuration )
     {
-        final Set<Flag> flags = new HashSet<>();
+        final Set<Flag> flags = EnumSet.noneOf( Flag.class );
         if ( configuration.isDevDebugMode() )
         {
             flags.add( Flag.DevDebug );

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

@@ -500,7 +500,7 @@ public class PwmLogger
         private final PwmLogLevel logLevel;
         private final SessionLabel sessionLabel;
 
-        private StringBuilder buffer = new StringBuilder();
+        private final StringBuilder buffer = new StringBuilder();
 
         private PwmLoggerAppendable(
                 final PwmLogLevel logLevel,

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

@@ -559,7 +559,7 @@ public class NMASCrOperator implements CrOperator
             {
                 throw new IllegalStateException( "test may not be called after success returned" );
             }
-            final List<String> answers = new ArrayList<>( challengeStringMap == null ? Collections.<String>emptyList() : challengeStringMap.values() );
+            final List<String> answers = new ArrayList<>( challengeStringMap == null ? Collections.emptyList() : challengeStringMap.values() );
             if ( answers.isEmpty() || answers.size() < challengeSet.minimumResponses() )
             {
                 return false;

+ 3 - 3
server/src/main/java/password/pwm/util/operations/otp/PasscodeGenerator.java

@@ -105,12 +105,12 @@ public class PasscodeGenerator
 
     private String padOutput( final int value )
     {
-        String result = Integer.toString( value );
+        final StringBuilder result = new StringBuilder( Integer.toString( value ) );
         for ( int i = result.length(); i < codeLength; i++ )
         {
-            result = "0" + result;
+            result.insert( 0, "0" );
         }
-        return result;
+        return result.toString();
     }
 
     /**

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

@@ -94,7 +94,7 @@ public class PasswordCharCounter
     public int getRepeatedChars( )
     {
         int numberOfRepeats = 0;
-        final CharSequence passwordL = password.toString().toLowerCase();
+        final CharSequence passwordL = password.toLowerCase();
 
         for ( int i = 0; i < passwordLength - 1; i++ )
         {
@@ -119,7 +119,7 @@ public class PasswordCharCounter
     public int getSequentialRepeatedChars( )
     {
         int numberOfRepeats = 0;
-        final CharSequence passwordL = password.toString().toLowerCase();
+        final CharSequence passwordL = password.toLowerCase();
 
         for ( int i = 0; i < passwordLength - 1; i++ )
         {
@@ -200,7 +200,7 @@ public class PasswordCharCounter
     public int getUniqueChars( )
     {
         final StringBuilder sb = new StringBuilder();
-        final String passwordL = password.toString().toLowerCase();
+        final String passwordL = password.toLowerCase();
         for ( int i = 0; i < passwordLength; i++ )
         {
             final char loopChar = passwordL.charAt( i );

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

@@ -237,9 +237,9 @@ public class PwmPasswordRuleUtil
             int lastCodePoint = -1;
             int consecutiveCharCount = 1;
 
-            for ( int i = 0; i < codePoints.length; i++ )
+            for ( final int codePoint : codePoints )
             {
-                if ( codePoints[ i ] == lastCodePoint + 1 )
+                if ( codePoint == lastCodePoint + 1 )
                 {
                     consecutiveCharCount++;
                 }
@@ -248,7 +248,7 @@ public class PwmPasswordRuleUtil
                     consecutiveCharCount = 1;
                 }
 
-                lastCodePoint = codePoints[ i ];
+                lastCodePoint = codePoint;
 
                 if ( consecutiveCharCount == maximumConsecutive )
                 {

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

@@ -430,13 +430,13 @@ public class SmsQueueManager implements PwmService
         // Remove leading double zero, replace by plus
         if ( returnValue.startsWith( "00" ) )
         {
-            returnValue = "+" + returnValue.substring( 2, returnValue.length() );
+            returnValue = "+" + returnValue.substring( 2 );
         }
 
         // Replace leading zero by country code
         if ( returnValue.startsWith( "0" ) )
         {
-            returnValue = countryCodeNumber + returnValue.substring( 1, returnValue.length() );
+            returnValue = countryCodeNumber + returnValue.substring( 1 );
         }
 
         // Add a leading plus if necessary

+ 2 - 11
server/src/main/java/password/pwm/util/secure/PwmSecurityKey.java

@@ -27,7 +27,7 @@ import password.pwm.error.PwmUnrecoverableException;
 import javax.crypto.SecretKey;
 import javax.crypto.spec.SecretKeySpec;
 import java.io.ByteArrayInputStream;
-import java.io.UnsupportedEncodingException;
+import java.nio.charset.StandardCharsets;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Map;
@@ -64,16 +64,7 @@ public class PwmSecurityKey
 
     private byte[] stringToKeyData( final String input ) throws PwmUnrecoverableException
     {
-        try
-        {
-            return input.getBytes( "iso-8859-1" );
-        }
-        catch ( final UnsupportedEncodingException e )
-        {
-            final String errorMsg = "unexpected error converting input text to crypto key bytes: " + e.getMessage();
-            final ErrorInformation errorInformation = new ErrorInformation( PwmError.ERROR_CRYPT_ERROR, errorMsg );
-            throw new PwmUnrecoverableException( errorInformation );
-        }
+        return input.getBytes( StandardCharsets.ISO_8859_1 );
     }
 
     SecretKey getKey( final Type keyType )

+ 3 - 3
server/src/main/java/password/pwm/util/secure/X509Utils.java

@@ -254,12 +254,12 @@ public class X509Utils
 
     public static String hexSerial( final X509Certificate x509Certificate )
     {
-        String result = x509Certificate.getSerialNumber().toString( 16 ).toUpperCase();
+        final StringBuilder result = new StringBuilder( x509Certificate.getSerialNumber().toString( 16 ).toUpperCase() );
         while ( result.length() % 2 != 0 )
         {
-            result = "0" + result;
+            result.insert( 0, "0" );
         }
-        return result;
+        return result.toString();
     }
 
     public static String makeDetailText( final X509Certificate x509Certificate )

+ 5 - 5
server/src/main/java/password/pwm/ws/server/RestAuthenticationProcessor.java

@@ -33,9 +33,9 @@ import password.pwm.error.ErrorInformation;
 import password.pwm.error.PwmError;
 import password.pwm.error.PwmOperationalException;
 import password.pwm.error.PwmUnrecoverableException;
-import password.pwm.ldap.permission.UserPermissionTester;
 import password.pwm.ldap.auth.AuthenticationResult;
 import password.pwm.ldap.auth.SimpleLdapAuthenticator;
+import password.pwm.ldap.permission.UserPermissionTester;
 import password.pwm.ldap.search.UserSearchEngine;
 import password.pwm.util.BasicAuthInfo;
 import password.pwm.util.java.JavaHelper;
@@ -43,7 +43,7 @@ import password.pwm.util.logging.PwmLogger;
 
 import javax.servlet.http.HttpServletRequest;
 import java.util.Collections;
-import java.util.HashSet;
+import java.util.EnumSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -75,7 +75,7 @@ public class RestAuthenticationProcessor
             if ( namedSecretName != null )
             {
                 LOGGER.trace( sessionLabel, () -> "authenticating with named secret '" + namedSecretName + "'" );
-                final Set<WebServiceUsage> usages = new HashSet<>( JavaHelper.readEnumSetFromStringCollection(
+                final Set<WebServiceUsage> usages = EnumSet.copyOf( JavaHelper.readEnumSetFromStringCollection(
                         WebServiceUsage.class,
                         pwmApplication.getConfig().readSettingAsNamedPasswords( PwmSetting.WEBSERVICES_EXTERNAL_SECRET ).get( namedSecretName ).getUsage()
                 ) );
@@ -120,7 +120,7 @@ public class RestAuthenticationProcessor
                         RestAuthenticationType.LDAP,
                         null,
                         userIdentity,
-                        Collections.unmodifiableSet( new HashSet<>( WebServiceUsage.forType( RestAuthenticationType.LDAP ) ) ),
+                        Collections.unmodifiableSet( EnumSet.copyOf( WebServiceUsage.forType( RestAuthenticationType.LDAP ) ) ),
                         thirdParty,
                         chaiProvider
                 );
@@ -128,7 +128,7 @@ public class RestAuthenticationProcessor
         }
 
         final Set<WebServiceUsage> publicUsages = WebServiceUsage.forType( RestAuthenticationType.PUBLIC );
-        final Set<WebServiceUsage> enabledUsages = new HashSet<>(
+        final Set<WebServiceUsage> enabledUsages = EnumSet.copyOf(
                 pwmApplication.getConfig().readSettingAsOptionList( PwmSetting.WEBSERVICES_PUBLIC_ENABLE, WebServiceUsage.class ) );
         enabledUsages.retainAll( publicUsages );
 

+ 1 - 1
server/src/main/java/password/pwm/ws/server/RestUtility.java

@@ -105,7 +105,7 @@ public class RestUtility
         {
             final int pipeIndex = username.indexOf( "|" );
             ldapProfileID = username.substring( 0, pipeIndex );
-            effectiveUsername = username.substring( pipeIndex + 1, username.length() );
+            effectiveUsername = username.substring( pipeIndex + 1 );
         }
         else
         {

+ 1 - 1
server/src/test/java/password/pwm/config/stored/ConfigurationCleanerTest.java

@@ -49,7 +49,7 @@ public class ConfigurationCleanerTest
     {
         //PwmLogger.disableAllLogging();
 
-        try ( InputStream xmlFile = ConfigurationCleanerTest.class.getResourceAsStream( "ConfigurationCleanerTest.xml" ); )
+        try ( InputStream xmlFile = ConfigurationCleanerTest.class.getResourceAsStream( "ConfigurationCleanerTest.xml" ) )
         {
             final StoredConfiguration storedConfiguration = StoredConfigurationFactory.input( xmlFile );
             configuration = new Configuration( storedConfiguration );

+ 1 - 2
server/src/test/java/password/pwm/config/stored/StoredConfigurationTest.java

@@ -40,7 +40,7 @@ public class StoredConfigurationTest
     @BeforeClass
     public static void setUp() throws Exception
     {
-        try ( InputStream xmlFile = ConfigurationCleanerTest.class.getResourceAsStream( "ConfigurationCleanerTest.xml" ); )
+        try ( InputStream xmlFile = ConfigurationCleanerTest.class.getResourceAsStream( "ConfigurationCleanerTest.xml" ) )
         {
             final StoredConfiguration storedConfiguration = StoredConfigurationFactory.input( xmlFile );
             configuration = new Configuration( storedConfiguration );
@@ -53,6 +53,5 @@ public class StoredConfigurationTest
     {
         final PwmApplication pwmApplication = TestHelper.makeTestPwmApplication( temporaryFolder.newFolder(), configuration );
         final String configHash = configuration.configurationHash( pwmApplication.getSecureService() );
-        System.out.println( configHash );
     }
 }

+ 1 - 1
server/src/test/java/password/pwm/health/HealthMessageTest.java

@@ -41,7 +41,7 @@ public class HealthMessageTest
         for ( final HealthMessage healthMessage : HealthMessage.values() )
         {
             // duplicate key found
-            Assert.assertTrue( !seenKeys.contains( healthMessage.getKey() ) );
+            Assert.assertFalse( seenKeys.contains( healthMessage.getKey() ) );
             seenKeys.add( healthMessage.getKey() );
         }
     }

+ 1 - 1
server/src/test/java/password/pwm/http/filter/RequestInitializationFilterTest.java

@@ -129,7 +129,7 @@ public class RequestInitializationFilterTest
             throws PwmUnrecoverableException
     {
         final StoredConfigurationModifier modifier = StoredConfigurationFactory.newModifiableConfig();
-        modifier.writeSetting( PwmSetting.USE_X_FORWARDED_FOR_HEADER, null, new BooleanValue( false ), null );
+        modifier.writeSetting( PwmSetting.USE_X_FORWARDED_FOR_HEADER, null, BooleanValue.of( false ), null );
         final Configuration conf = new Configuration( modifier.newStoredConfiguration() );
         final HttpServletRequest mockRequest = Mockito.mock( HttpServletRequest.class );
         Mockito.when( mockRequest.getRemoteAddr() ).thenReturn( "10.1.1.1" );

+ 1 - 1
server/src/test/java/password/pwm/i18n/NonLocalizedKeyTest.java

@@ -51,7 +51,7 @@ public class NonLocalizedKeyTest
             for ( final String key : NON_LOCALIZED_KEYS )
             {
                 final String value = resourceBundle.getString( key );
-                Assert.assertTrue( !StringUtil.isEmpty( value ) );
+                Assert.assertFalse( StringUtil.isEmpty( value ) );
             }
         }
 

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

@@ -93,7 +93,7 @@ public class LocalDBStoredQueueExtendedTest
         try
         {
             storedQueue.remove();
-            Assert.assertTrue( false );
+            Assert.fail();
         }
         catch ( final NoSuchElementException e )
         {
@@ -101,7 +101,7 @@ public class LocalDBStoredQueueExtendedTest
         }
         catch ( final Exception e )
         {
-            Assert.assertTrue( false );
+            Assert.fail();
         }
 
         Assert.assertTrue( storedQueue.isEmpty() );
@@ -126,7 +126,7 @@ public class LocalDBStoredQueueExtendedTest
 
         {
             final Iterator<String> iter = storedQueue.iterator();
-            iter.hasNext();
+            Assert.assertTrue( iter.hasNext() );
             Assert.assertEquals( "value0", iter.next() );
             Assert.assertEquals( "value1", iter.next() );
             Assert.assertEquals( "value2", iter.next() );
@@ -136,7 +136,7 @@ public class LocalDBStoredQueueExtendedTest
 
         {
             final Iterator<String> iter = storedQueue.descendingIterator();
-            iter.hasNext();
+            Assert.assertTrue( iter.hasNext() );
             Assert.assertEquals( "value4", iter.next() );
             Assert.assertEquals( "value3", iter.next() );
             Assert.assertEquals( "value2", iter.next() );

+ 80 - 0
server/src/test/java/password/pwm/util/localdb/LocalDBStoredQueuePositionTest.java

@@ -0,0 +1,80 @@
+/*
+ * Password Management Servlets (PWM)
+ * http://www.pwm-project.org
+ *
+ * Copyright (c) 2006-2009 Novell, Inc.
+ * Copyright (c) 2009-2020 The PWM Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package password.pwm.util.localdb;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class LocalDBStoredQueuePositionTest
+{
+    @Test
+    public void positionTest()
+    {
+        final LocalDBStoredQueue.Position initialPosition = new LocalDBStoredQueue.Position( "0" );
+        Assert.assertEquals( "000000", initialPosition.toString() );
+
+        {
+            LocalDBStoredQueue.Position position = initialPosition.next();
+            Assert.assertEquals( "000001", position.toString() );
+            position = position.next();
+            Assert.assertEquals( "000002", position.toString() );
+            position = position.next();
+            Assert.assertEquals( "000003", position.toString() );
+
+            position = position.previous();
+            Assert.assertEquals( "000002", position.toString() );
+            position = position.previous();
+            Assert.assertEquals( "000001", position.toString() );
+            position = position.previous();
+            Assert.assertEquals( "000000", position.toString() );
+            position = position.previous();
+            Assert.assertEquals( "ZZZZZZ", position.toString() );
+        }
+
+        {
+            LocalDBStoredQueue.Position position = initialPosition.previous();
+            Assert.assertEquals( "ZZZZZZ", position.toString() );
+            position = position.previous();
+            Assert.assertEquals( "ZZZZZY", position.toString() );
+            position = position.previous();
+            Assert.assertEquals( "ZZZZZX", position.toString() );
+
+            position = position.next();
+            Assert.assertEquals( "ZZZZZY", position.toString() );
+            position = position.next();
+            Assert.assertEquals( "ZZZZZZ", position.toString() );
+            position = position.next();
+            Assert.assertEquals( "000000", position.toString() );
+            position = position.next();
+            Assert.assertEquals( "000001", position.toString() );
+        }
+
+        {
+            final long distance = initialPosition.distanceToHead( new LocalDBStoredQueue.Position( "000003" ) );
+            Assert.assertEquals( 3, distance );
+        }
+
+        {
+            final long distance = initialPosition.distanceToHead( new LocalDBStoredQueue.Position( "ZZZZZX" ) );
+            Assert.assertEquals( 2176782333L, distance );
+        }
+    }
+}

+ 546 - 0
server/src/test/java/password/pwm/util/localdb/LocalDBStoredQueueTest.java

@@ -0,0 +1,546 @@
+/*
+ * Password Management Servlets (PWM)
+ * http://www.pwm-project.org
+ *
+ * Copyright (c) 2006-2009 Novell, Inc.
+ * Copyright (c) 2009-2020 The PWM Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package password.pwm.util.localdb;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import password.pwm.PwmApplication;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.stream.Collectors;
+
+public class LocalDBStoredQueueTest
+{
+    private static final int MAX_PROBLEM_SIZE = 100;
+
+    @Rule
+    public TemporaryFolder testFolder = new TemporaryFolder();
+
+    private LocalDBStoredQueue localDBStoredQueue;
+
+    @Before
+    public void setUp() throws Exception
+    {
+        final File localDbTestFolder = testFolder.newFolder( "test-stored-queue-test" );
+        final PwmApplication pwmApplication = TestHelper.makeTestPwmApplication( localDbTestFolder );
+        final LocalDB localDB = LocalDBFactory.getInstance( localDbTestFolder, false, pwmApplication.getPwmEnvironment(), pwmApplication.getConfig() );
+        localDBStoredQueue = LocalDBStoredQueue.createLocalDBStoredQueue( localDB, LocalDB.DB.TEMP, true );
+    }
+
+    @Test
+    public void testStoredQueueSimple() throws LocalDBException
+    {
+        Assert.assertEquals( 0, localDBStoredQueue.size() );
+
+        localDBStoredQueue.add( "one" );
+        Assert.assertEquals( 1, localDBStoredQueue.size() );
+
+        localDBStoredQueue.add( "two" );
+        Assert.assertEquals( 2, localDBStoredQueue.size() );
+
+        localDBStoredQueue.add( "three" );
+        Assert.assertEquals( 3, localDBStoredQueue.size() );
+
+        localDBStoredQueue.removeFirst();
+        Assert.assertEquals( 2, localDBStoredQueue.size() );
+
+        {
+            final List<String> values = localDBStoredQueue.stream().collect( Collectors.toList() );
+            Assert.assertEquals( 2, values.size() );
+        }
+    }
+
+    @Test
+    public void testStoredQueueBulk() throws LocalDBException
+    {
+        addValues( localDBStoredQueue, MAX_PROBLEM_SIZE );
+
+        Assert.assertEquals( MAX_PROBLEM_SIZE, localDBStoredQueue.size() );
+        Assert.assertEquals( "99", localDBStoredQueue.getFirst() );
+        Assert.assertEquals( "0", localDBStoredQueue.getLast() );
+
+        for ( int i = 99; i > -1; i-- )
+        {
+            localDBStoredQueue.removeLast();
+            Assert.assertEquals( i, localDBStoredQueue.size() );
+        }
+    }
+
+    @Test
+    public void testStoredQueueIterators()
+    {
+        addValues( localDBStoredQueue, MAX_PROBLEM_SIZE );
+
+        {
+            final Iterator<String> iter = localDBStoredQueue.descendingIterator();
+            for ( int i = 0; i < MAX_PROBLEM_SIZE; i++ )
+            {
+                Assert.assertEquals( String.valueOf( i ), iter.next() );
+            }
+        }
+
+        {
+            final Iterator<String> iter = localDBStoredQueue.iterator();
+            for ( int i = ( MAX_PROBLEM_SIZE - 1 ); i > -1; i-- )
+            {
+                Assert.assertEquals( String.valueOf( i ), iter.next() );
+            }
+        }
+    }
+
+    @Test
+    public void testRemoveLast()
+    {
+        for ( int i = 0; i < MAX_PROBLEM_SIZE; i++ )
+        {
+            localDBStoredQueue.addFirst( String.valueOf( i ) );
+            Assert.assertEquals( String.valueOf( i ), localDBStoredQueue.removeLast() );
+        }
+
+        localDBStoredQueue.clear();
+
+        for ( int i = 0; i < MAX_PROBLEM_SIZE; i++ )
+        {
+            localDBStoredQueue.addLast( String.valueOf( i ) );
+            Assert.assertEquals( String.valueOf( i ), localDBStoredQueue.removeLast() );
+        }
+
+        localDBStoredQueue.clear();
+
+        for ( int i = 0; i < MAX_PROBLEM_SIZE; i++ )
+        {
+            localDBStoredQueue.addFirst( String.valueOf( i ) );
+        }
+
+        for ( int i = 0; i < MAX_PROBLEM_SIZE; i++ )
+        {
+            Assert.assertEquals( String.valueOf( i ), localDBStoredQueue.removeLast() );
+        }
+    }
+
+    @Test
+    public void testAddFirst()
+    {
+        final String[] aBunchOfString = {
+                "One",
+                "Two",
+                "Three",
+                "Four",
+        };
+
+        for ( final String loopString : aBunchOfString )
+        {
+            localDBStoredQueue.addFirst( loopString );
+        }
+
+        for ( int i = aBunchOfString.length - 1; i >= 0; i-- )
+        {
+            Assert.assertEquals( aBunchOfString[i], localDBStoredQueue.removeFirst() );
+        }
+    }
+
+    @Test
+    public void testAddLast()
+    {
+        final String[] aBunchOfString = {
+                "One",
+                "Two",
+                "Three",
+                "Four",
+        };
+
+        for ( final String loopString : aBunchOfString )
+        {
+            localDBStoredQueue.addLast( loopString );
+        }
+
+        for ( int i = aBunchOfString.length - 1; i >= 0; i-- )
+        {
+            Assert.assertEquals( aBunchOfString[i], localDBStoredQueue.removeLast() );
+        }
+    }
+
+
+    @Test
+    public void testIsEmptyAfterAddRemoveFirst()
+    {
+        localDBStoredQueue.addFirst( "Something" );
+        boolean empty = localDBStoredQueue.isEmpty();
+        Assert.assertFalse( empty );
+        localDBStoredQueue.removeFirst();
+
+        empty = localDBStoredQueue.isEmpty();
+        Assert.assertTrue( "Should be empty after adding then removing",
+                empty );
+
+    }
+
+    @Test
+    public void testIsEmptyAfterAddRemoveLast()
+    {
+        localDBStoredQueue.addLast( "Something" );
+        Assert.assertFalse( localDBStoredQueue.isEmpty() );
+        localDBStoredQueue.removeLast();
+        Assert.assertTrue( "Should be empty after adding then removing",
+                localDBStoredQueue.isEmpty() );
+
+    }
+
+    @Test
+    public void testIsEmptyAfterAddFirstRemoveLast()
+    {
+        localDBStoredQueue.addFirst( "Something" );
+        Assert.assertFalse( localDBStoredQueue.isEmpty() );
+        localDBStoredQueue.removeLast();
+        Assert.assertTrue( "Should be empty after adding then removing",
+                localDBStoredQueue.isEmpty() );
+    }
+
+    @Test
+    public void testIsEmptyAfterAddLastRemoveFirst()
+    {
+        localDBStoredQueue.addLast( "Something" );
+        Assert.assertFalse( localDBStoredQueue.isEmpty() );
+        localDBStoredQueue.removeFirst();
+        Assert.assertTrue( "Should be empty after adding then removing",
+                localDBStoredQueue.isEmpty() );
+    }
+
+    @Test
+    public void testIsEmptyAfterMultipleAddRemove()
+    {
+        for ( int i = 0; i < MAX_PROBLEM_SIZE; i++ )
+        {
+            localDBStoredQueue.addFirst( "Something" );
+            Assert.assertFalse( "Should not be empty after " + i + " item added",
+                    localDBStoredQueue.isEmpty() );
+        }
+
+        for ( int i = 0; i < MAX_PROBLEM_SIZE; i++ )
+        {
+            Assert.assertFalse( "Should not be empty after " + i + " item removed",
+                    localDBStoredQueue.isEmpty() );
+            localDBStoredQueue.removeLast();
+        }
+
+        Assert.assertTrue( "Should be empty after adding and removing "
+                        + MAX_PROBLEM_SIZE + " elements.",
+                localDBStoredQueue.isEmpty() );
+    }
+
+    @Test
+    public void testMultipleFillAndEmpty()
+    {
+        for ( int tries = 0; tries < 50; tries++ )
+        {
+            for ( int i = 0; i < MAX_PROBLEM_SIZE; i++ )
+            {
+                localDBStoredQueue.addFirst( String.valueOf( i ) );
+            }
+
+            Assert.assertFalse( localDBStoredQueue.isEmpty() );
+            int counter = 0;
+            while ( !localDBStoredQueue.isEmpty() )
+            {
+                Assert.assertEquals( String.valueOf( counter ), localDBStoredQueue.removeLast() );
+                counter++;
+            }
+
+            Assert.assertTrue( localDBStoredQueue.isEmpty() );
+
+            for ( int j = 0; j < MAX_PROBLEM_SIZE; j++ )
+            {
+                localDBStoredQueue.addLast( String.valueOf( j ) );
+            }
+
+            Assert.assertFalse( localDBStoredQueue.isEmpty() );
+
+            counter = 0;
+            while ( !localDBStoredQueue.isEmpty() )
+            {
+                Assert.assertEquals( String.valueOf( counter ), localDBStoredQueue.removeFirst() );
+                counter++;
+            }
+
+            Assert.assertTrue( localDBStoredQueue.isEmpty() );
+        }
+    }
+
+    @Test
+    public void testSize()
+    {
+        Assert.assertEquals( 0, localDBStoredQueue.size() );
+        for ( int i = 0; i < MAX_PROBLEM_SIZE; i++ )
+        {
+            localDBStoredQueue.addFirst( "Something" );
+            Assert.assertEquals( i + 1, localDBStoredQueue.size() );
+        }
+
+        for ( int i = MAX_PROBLEM_SIZE; i > 0; i-- )
+        {
+            Assert.assertEquals( i, localDBStoredQueue.size() );
+            localDBStoredQueue.removeLast();
+        }
+
+        Assert.assertEquals( 0, localDBStoredQueue.size() );
+    }
+
+    @Test
+    public void testAddNull()
+    {
+        try
+        {
+            localDBStoredQueue.addFirst( null );
+            Assert.fail( "Should have thrown a NullPointerException" );
+        }
+        catch ( final NullPointerException npe )
+        {
+            // Continue
+        }
+        catch ( final Exception e )
+        {
+            Assert.fail( "Wrong exception catched." + e );
+        }
+
+        try
+        {
+            localDBStoredQueue.addLast( null );
+            Assert.fail( "Should have thrown a NullPointerException" );
+        }
+        catch ( final NullPointerException npe )
+        {
+            // Continue
+        }
+        catch ( final Exception e )
+        {
+            Assert.fail( "Wrong exception catched." + e );
+        }
+    }
+
+    @Test
+    public void testRemoveFirst()
+    {
+        for ( int i = 0; i < MAX_PROBLEM_SIZE; i++ )
+        {
+            localDBStoredQueue.addFirst( String.valueOf( i ) );
+            Assert.assertEquals( String.valueOf( i ), localDBStoredQueue.removeFirst() );
+        }
+
+        localDBStoredQueue.clear();
+
+        for ( int i = 0; i < MAX_PROBLEM_SIZE; i++ )
+        {
+            localDBStoredQueue.addLast( String.valueOf( i ) );
+            Assert.assertEquals( String.valueOf( i ), localDBStoredQueue.removeFirst() );
+        }
+
+        localDBStoredQueue.clear();
+
+        for ( int i = 0; i < MAX_PROBLEM_SIZE; i++ )
+        {
+            localDBStoredQueue.addLast( String.valueOf( i ) );
+        }
+
+        for ( int i = 0; i < MAX_PROBLEM_SIZE; i++ )
+        {
+            Assert.assertEquals( String.valueOf( i ), localDBStoredQueue.removeFirst() );
+        }
+
+    }
+
+    @Test
+    public void testRemoveEmpty()
+    {
+        try
+        {
+            Assert.assertTrue( localDBStoredQueue.isEmpty() );
+            localDBStoredQueue.removeFirst();
+            Assert.fail( "Expected a NoSuchElementException" );
+        }
+        catch ( final NoSuchElementException nsee )
+        {
+            // Continue
+        }
+        catch ( final Exception e )
+        {
+            Assert.fail( "Unexpected exception : " + e );
+        }
+
+        try
+        {
+            Assert.assertTrue( localDBStoredQueue.isEmpty() );
+            localDBStoredQueue.removeLast();
+            Assert.fail( "Expected a NoSuchElementException" );
+        }
+        catch ( final NoSuchElementException nsee )
+        {
+            // Continue
+        }
+        catch ( final Exception e )
+        {
+            Assert.fail( "Unexpected exception : " + e );
+        }
+
+        try
+        {
+            Assert.assertTrue( localDBStoredQueue.isEmpty() );
+
+            for ( int i = 0; i < MAX_PROBLEM_SIZE; i++ )
+            {
+                localDBStoredQueue.addLast( String.valueOf( i ) );
+            }
+            for ( int i = 0; i < MAX_PROBLEM_SIZE; i++ )
+            {
+                localDBStoredQueue.removeLast();
+            }
+            localDBStoredQueue.removeLast();
+            Assert.fail( "Expected a NoSuchElementException" );
+        }
+        catch ( final NoSuchElementException nsee )
+        {
+            // Continue
+        }
+        catch ( final Exception e )
+        {
+            Assert.fail( "Unexpected exception : " + e );
+        }
+    }
+
+    @Test
+    public void testIteratorRemoveNotSupported()
+    {
+        final Iterator<String> anIterator = localDBStoredQueue.iterator();
+        try
+        {
+            anIterator.remove();
+            Assert.fail( "Should have thrown an UnsupportedOperationException" );
+        }
+        catch ( final UnsupportedOperationException uoe )
+        {
+            // Continue
+        }
+        catch ( final Exception e )
+        {
+            Assert.fail( "Unexpected exception : " + e );
+        }
+    }
+
+    @Test
+    public void testMultipleIterator()
+    {
+        for ( int i = 0; i < MAX_PROBLEM_SIZE / 1000; i++ )
+        {
+
+            localDBStoredQueue.clear();
+            for ( int j = 0; j < i; j++ )
+            {
+                localDBStoredQueue.addLast( String.valueOf( j ) );
+            }
+
+            @SuppressWarnings( "rawtypes" )
+            final Iterator[] someIterators = {
+                    localDBStoredQueue.iterator(),
+                    localDBStoredQueue.iterator(),
+                    localDBStoredQueue.iterator(),
+                    localDBStoredQueue.iterator(),
+                    localDBStoredQueue.iterator(),
+                    localDBStoredQueue.iterator(),
+            };
+
+            @SuppressWarnings( "unchecked" )
+            final Iterator<String>[] manyStringIterators =
+                    ( Iterator<String>[] ) someIterators;
+
+            for ( int iterID = 0; iterID < manyStringIterators.length; iterID++ )
+            {
+                int index = 0;
+                while ( manyStringIterators[iterID].hasNext() )
+                {
+                    Assert.assertEquals( "Iterator #" + iterID + " failed:\n",
+                            String.valueOf( index ),
+                            manyStringIterators[iterID].next() );
+                    index++;
+                }
+            }
+
+        }
+    }
+
+    @Test
+    public void testQueueBehavior()
+    {
+        final String[] aBunchOfString = {
+                "One",
+                "Two",
+                "Three",
+                "Four",
+        };
+
+        for ( final String loopString : aBunchOfString )
+        {
+            localDBStoredQueue.addFirst( loopString );
+        }
+
+        for ( final String loopString : aBunchOfString )
+        {
+            Assert.assertEquals( loopString, localDBStoredQueue.removeLast() );
+        }
+    }
+
+    @Test
+    public void testStackBehavior()
+    {
+
+        final String[] aBunchOfString = {
+                "One",
+                "Two",
+                "Three",
+                "Four",
+        };
+
+        for ( final String loopString : aBunchOfString )
+        {
+            localDBStoredQueue.addFirst( loopString );
+        }
+
+        for ( int i = aBunchOfString.length - 1; i >= 0; i-- )
+        {
+            Assert.assertEquals( aBunchOfString[i], localDBStoredQueue.removeFirst() );
+        }
+    }
+
+    private static void addValues( final LocalDBStoredQueue localDBStoredQueue, final int count )
+    {
+        final List<String> addValues = new ArrayList<>();
+        for ( int i = 0; i < count; i++ )
+        {
+            addValues.add( String.valueOf( i ) );
+        }
+        localDBStoredQueue.addAll( addValues );
+    }
+}

+ 1 - 1
server/src/test/java/password/pwm/util/password/PasswordRuleChecksTest.java

@@ -435,6 +435,6 @@ public class PasswordRuleChecksTest
 
     private static <T> org.hamcrest.Matcher<java.lang.Iterable<T>> hasItems( final T... items )
     {
-        return org.hamcrest.core.IsCollectionContaining.<T>hasItems( items );
+        return org.hamcrest.core.IsCollectionContaining.hasItems( items );
     }
 }